From 25bddc96d01ca1cbdaa91ce30469fa477ec22ab1 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 11 Sep 2020 08:21:15 +0200 Subject: [PATCH 01/62] mockup --- Cargo.lock | 17 +++++++++++++++++ Cargo.toml | 1 + 2 files changed, 18 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 173624261f133..a54f8a1cf8be2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1287,6 +1287,23 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +[[package]] +name = "election-providers" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "serde", + "sp-arithmetic", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-staking", + "sp-std", + "static_assertions", +] + [[package]] name = "enumflags2" version = "0.6.4" diff --git a/Cargo.toml b/Cargo.toml index 7589e8d774124..fc23363b7a04d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,6 +100,7 @@ members = [ "frame/staking", "frame/staking/reward-curve", "frame/staking/fuzzer", + "frame/election-providers", "frame/sudo", "frame/support", "frame/support/procedural", From 7bef52f390b6223b343263f5c60c0b82fa24bce6 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 11 Sep 2020 08:29:31 +0200 Subject: [PATCH 02/62] Add files --- frame/election-providers/Cargo.toml | 21 ++++++++++ frame/election-providers/src/lib.rs | 31 +++++++++++++++ frame/election-providers/src/offchain.rs | 36 +++++++++++++++++ frame/election-providers/src/onchain.rs | 50 ++++++++++++++++++++++++ 4 files changed, 138 insertions(+) create mode 100644 frame/election-providers/Cargo.toml create mode 100644 frame/election-providers/src/lib.rs create mode 100644 frame/election-providers/src/offchain.rs create mode 100644 frame/election-providers/src/onchain.rs diff --git a/frame/election-providers/Cargo.toml b/frame/election-providers/Cargo.toml new file mode 100644 index 0000000000000..b6789d3e954d9 --- /dev/null +++ b/frame/election-providers/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "election-providers" +version = "0.1.0" +authors = ["kianenigma "] +edition = "2018" + +[dependencies] +static_assertions = "1.1.0" +serde = { version = "1.0.101", optional = true } +codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] } +sp-io ={ version = "2.0.0-rc6", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/runtime" } +sp-staking = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/staking" } +frame-support = { version = "2.0.0-rc6", default-features = false, path = "../support" } +frame-system = { version = "2.0.0-rc6", default-features = false, path = "../system" } + +sp-npos-elections = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/npos-elections" } +sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } +sp-arithmetic = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/arithmetic" } + + diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs new file mode 100644 index 0000000000000..635e36decc4be --- /dev/null +++ b/frame/election-providers/src/lib.rs @@ -0,0 +1,31 @@ + +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod offchain; +pub mod onchain; + +use sp_npos_elections::{ExtendedBalance, SupportMap}; +use sp_arithmetic::PerThing; + +/// Something that can compute the result of an election and pass it back to a pallet. +pub trait ElectionProvider { + /// Elect a new set of winners. + /// + /// The result is returned in a target major format, namely as a support map. + fn elect( + to_elect: usize, + candidates: Vec, + voters: Vec<(AccountId, VoteWeight, Vec)>, + ) -> Result, Error> where + // TODO: Okay about these two, I get that we probably need the first one, but can't we + // alleviate the latter one? I think we can say that all PerThing are Mul of some types. + // Perhaps it is time to move the PerBill macros to something better? Yeah I think then we + // can get rid of both of these types everywhere. + ExtendedBalance: From<

::Inner>, + P: sp_std::ops::Mul; +} + +pub enum Error { + ElectionFailed, +} + diff --git a/frame/election-providers/src/offchain.rs b/frame/election-providers/src/offchain.rs new file mode 100644 index 0000000000000..9a0cb1c3c4ffd --- /dev/null +++ b/frame/election-providers/src/offchain.rs @@ -0,0 +1,36 @@ + + +use sp_std::marker::PhantomData; +use frame_support::{ + dispatch::{DispatchResult, IsSubType}, decl_module, decl_storage, decl_event, + weights::{DispatchClass, ClassifyDispatch, WeighData, Weight, PaysFee, Pays}, +}; +use sp_std::prelude::*; +use frame_system::{ensure_signed, ensure_root}; +use codec::{Encode, Decode}; +use sp_runtime::{ + traits::{ + SignedExtension, Bounded, SaturatedConversion, DispatchInfoOf, + }, + transaction_validity::{ + ValidTransaction, TransactionValidityError, InvalidTransaction, TransactionValidity, + }, +}; + +pub trait Trait: frame_system::Trait {} + +decl_storage! { + trait Store for Module as OffchainElectionProvider { + + } +} + +// decl_event!( +// pub enum Event { +// } +// ); + +decl_module! { + // Simple declaration of the `Module` type. Lets the macro know what its working on. + pub struct Module for enum Call where origin: T::Origin {} +} diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs new file mode 100644 index 0000000000000..238e7b644abcd --- /dev/null +++ b/frame/election-providers/src/onchain.rs @@ -0,0 +1,50 @@ +use crate::{ElectionProvider, Error}; +use sp_npos_elections::{VoteWeight, ElectionResult, SupportMap, IdentifierT, ExtendedBalance}; +use sp_arithmetic::PerThing; +use sp_std::collections::btree_map::BTreeMap; + +pub struct OnChainSequentialPhragmen; +impl ElectionProvider for OnChainSequentialPhragmen { + fn elect( + to_elect: usize, + candidates: Vec, + voters: Vec<(AccountId, VoteWeight, Vec)>, + ) -> Result, Error> where + ExtendedBalance: From<

::Inner>, + P: sp_std::ops::Mul + { + // TODO: so henceforth, we will always return a Result here. + // TODO: we really don't need to do this conversion all the time. With + // https://github.com/paritytech/substrate/pull/6685 merged, we should make variants of + // seq_phragmen and others that return a different return type. In fact, I think I should + // rebase this branch there and just build there as well. + // TODO: Okay even if not the above, then def. make the extension traits for converting + // between validator Major and Nominator Major result types, and make the conversions be + // lossless and painless to happen. + let mut stake_map: BTreeMap = BTreeMap::new(); + voters.iter().for_each(|(v, s, _)| { + stake_map.insert(v.clone(), *s); + }); + let stake_of = Box::new(|w: &AccountId| -> VoteWeight { + stake_map.get(w).cloned().unwrap_or_default() + }); + + sp_npos_elections::seq_phragmen::<_, P>( + to_elect, + 0, + candidates, + voters, + ).map(| ElectionResult { winners, assignments } | { + let staked = sp_npos_elections::assignment_ratio_to_staked_normalized( + assignments, + &stake_of, + ).unwrap(); + + let winners = sp_npos_elections::to_without_backing(winners); + let (supports, _error) = sp_npos_elections::build_support_map(&winners, &staked); + + debug_assert_eq!(_error, 0); + supports + }).ok_or(Error::ElectionFailed) + } +} From bc30ce14dbf1d489fec9f4d799719a9cc858eecb Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 24 Sep 2020 14:30:45 +0200 Subject: [PATCH 03/62] More mockup --- Cargo.lock | 35 +- frame/election-providers/Cargo.toml | 26 +- frame/election-providers/src/lib.rs | 24 +- frame/election-providers/src/offchain.rs | 429 ++++++++++++++++++++-- frame/election-providers/src/onchain.rs | 49 +-- frame/staking/Cargo.toml | 2 + frame/staking/src/lib.rs | 4 +- primitives/npos-elections/src/lib.rs | 14 +- primitives/npos-elections/src/phragmen.rs | 34 +- 9 files changed, 533 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ebc4b16057bc..3a2c081fd7c31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1234,23 +1234,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" -[[package]] -name = "election-providers" -version = "0.1.0" -dependencies = [ - "frame-support", - "frame-system", - "parity-scale-codec", - "serde", - "sp-arithmetic", - "sp-io", - "sp-npos-elections", - "sp-runtime", - "sp-staking", - "sp-std", - "static_assertions", -] - [[package]] name = "enumflags2" version = "0.6.4" @@ -1562,6 +1545,23 @@ dependencies = [ "structopt", ] +[[package]] +name = "frame-election-providers" +version = "2.0.0" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "serde", + "sp-arithmetic", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-staking", + "sp-std", + "static_assertions", +] + [[package]] name = "frame-executive" version = "2.0.0" @@ -4869,6 +4869,7 @@ name = "pallet-staking" version = "2.0.0" dependencies = [ "frame-benchmarking", + "frame-election-providers", "frame-support", "frame-system", "hex", diff --git a/frame/election-providers/Cargo.toml b/frame/election-providers/Cargo.toml index b6789d3e954d9..b936b59ca716c 100644 --- a/frame/election-providers/Cargo.toml +++ b/frame/election-providers/Cargo.toml @@ -1,8 +1,16 @@ [package] -name = "election-providers" -version = "0.1.0" -authors = ["kianenigma "] +name = "frame-election-providers" +version = "2.0.0" +authors = ["Parity Technologies "] edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME election providers" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] [dependencies] static_assertions = "1.1.0" @@ -18,4 +26,14 @@ sp-npos-elections = { version = "2.0.0-rc6", default-features = false, path = ". sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } sp-arithmetic = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/arithmetic" } - +[features] +default = ["std"] +std = [ + "serde", + "codec/std", + "frame-support/std", + "sp-runtime/std", + "sp-npos-elections/std", + "frame-system/std", + "sp-std/std", +] diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs index 635e36decc4be..ca6282b9af85a 100644 --- a/frame/election-providers/src/lib.rs +++ b/frame/election-providers/src/lib.rs @@ -1,31 +1,45 @@ - #![cfg_attr(not(feature = "std"), no_std)] +use sp_std::prelude::*; pub mod offchain; pub mod onchain; -use sp_npos_elections::{ExtendedBalance, SupportMap}; use sp_arithmetic::PerThing; +use sp_npos_elections::{ExtendedBalance, FlatSupportMap}; +use sp_runtime::RuntimeDebug; +// TODO: maybe we can have this be generic in the trait? probably in the future. +use sp_npos_elections::VoteWeight; /// Something that can compute the result of an election and pass it back to a pallet. -pub trait ElectionProvider { +pub trait ElectionProvider { /// Elect a new set of winners. /// /// The result is returned in a target major format, namely as a support map. fn elect( to_elect: usize, - candidates: Vec, + targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Error> where + ) -> Result, Error> + where // TODO: Okay about these two, I get that we probably need the first one, but can't we // alleviate the latter one? I think we can say that all PerThing are Mul of some types. // Perhaps it is time to move the PerBill macros to something better? Yeah I think then we // can get rid of both of these types everywhere. ExtendedBalance: From<

::Inner>, P: sp_std::ops::Mul; + + /// Returns true if an election is still ongoing. + fn ongoing() -> bool; } +#[derive(RuntimeDebug, Eq, PartialEq)] pub enum Error { ElectionFailed, + Internal(sp_npos_elections::Error), } +impl From for Error { + fn from(err: sp_npos_elections::Error) -> Self { + Error::Internal(err) + } +} diff --git a/frame/election-providers/src/offchain.rs b/frame/election-providers/src/offchain.rs index 9a0cb1c3c4ffd..47db7e66de8a4 100644 --- a/frame/election-providers/src/offchain.rs +++ b/frame/election-providers/src/offchain.rs @@ -1,36 +1,419 @@ - - -use sp_std::marker::PhantomData; +use crate::{onchain::OnChainSequentialPhragmen, ElectionProvider, Error}; +use codec::{Decode, Encode, HasCompact}; use frame_support::{ - dispatch::{DispatchResult, IsSubType}, decl_module, decl_storage, decl_event, - weights::{DispatchClass, ClassifyDispatch, WeighData, Weight, PaysFee, Pays}, + decl_error, decl_event, decl_module, decl_storage, + dispatch::DispatchResultWithPostInfo, + ensure, + traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, + weights::Weight, }; -use sp_std::prelude::*; -use frame_system::{ensure_signed, ensure_root}; -use codec::{Encode, Decode}; -use sp_runtime::{ - traits::{ - SignedExtension, Bounded, SaturatedConversion, DispatchInfoOf, - }, - transaction_validity::{ - ValidTransaction, TransactionValidityError, InvalidTransaction, TransactionValidity, - }, +use frame_system::{ensure_none, ensure_signed}; +use sp_npos_elections::{ + generate_solution_type, is_score_better, ElectionScore, ExtendedBalance, FlatSupportMap, + VoteWeight, }; +use sp_runtime::{traits::Zero, PerThing, PerU16, Perbill, RuntimeDebug}; +use sp_std::{mem::size_of, prelude::*}; + +pub trait ElectionDataProvider { + fn targets() -> (Vec, Weight); + fn voters() -> (Vec<(AccountId, VoteWeight, Vec)>, Weight); + fn desired_targets() -> (u32, Weight); + fn next_election_prediction() -> (B, Weight); +} + +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +type PositiveImbalanceOf = + <::Currency as Currency<::AccountId>>::PositiveImbalance; +type NegativeImbalanceOf = + <::Currency as Currency<::AccountId>>::NegativeImbalance; + +/// Accuracy used for on-chain election. +pub type ChainAccuracy = Perbill; + +/// Accuracy used for off-chain election. This better be small. +pub type OffchainAccuracy = PerU16; + +/// Data type used to index nominators in the compact type +pub type VoterIndex = u32; + +/// Data type used to index validators in the compact type. +pub type TargetIndex = u16; + +// Ensure the size of both TargetIndex and VoterIndex. They both need to be well below usize. +static_assertions::const_assert!(size_of::() <= size_of::()); +static_assertions::const_assert!(size_of::() <= size_of::()); +static_assertions::const_assert!(size_of::() <= size_of::()); +static_assertions::const_assert!(size_of::() <= size_of::()); + +// TODO: deal with 16 being defined here. +generate_solution_type!( + #[compact] + pub struct CompactAssignments::(16) +); + +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] +pub enum Phase { + Off, + Signed, + Unsigned(bool), +} + +impl Default for Phase { + fn default() -> Self { + Phase::Off + } +} + +impl Phase { + pub fn is_signed(&self) -> bool { + matches!(self, Phase::Signed) + } + + pub fn is_unsigned(&self) -> bool { + matches!(self, Phase::Unsigned(_)) + } + + pub fn is_unsigned_open(&self) -> bool { + matches!(self, Phase::Unsigned(true)) + } + + pub fn is_off(&self) -> bool { + matches!(self, Phase::Off) + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] +pub enum ElectionCompute { + OnChain, + Signed, + Unsigned, +} + +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub struct RawSolution { + winners: Vec, + compact: CompactAssignments, + score: ElectionScore, +} + +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub struct SignedSubmission { + who: AccountId, + deposit: Balance, + reward: Balance, + solution: RawSolution, +} + +/// A parsed solution, ready to be enacted. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] +pub struct ReadySolution { + winners: Vec, + supports: FlatSupportMap, +} + +pub trait WeightInfo {} + +pub trait Trait: frame_system::Trait { + type Event: From + Into<::Event>; + + type Currency: ReservableCurrency + Currency; + + type SignedPhase: Get; + type UnsignedPhase: Get; + + type MaxSignedSubmissions: Get; + + type SignedRewardBase: Get>; + type SignedRewardFactor: Get>; + + type SolutionImprovementThreshold: Get; -pub trait Trait: frame_system::Trait {} + type SubmissionBondBase: Get>; + type SubmissionBondByte: Get>; + + type SlashHandler: OnUnbalanced>; + type RewardHandler: OnUnbalanced>; + + type ElectionDataProvider: ElectionDataProvider; + + type WeightInfo: WeightInfo; +} decl_storage! { - trait Store for Module as OffchainElectionProvider { + trait Store for Module as TwoPhaseElectionProvider { + /// Current phase. + pub CurrentPhase get(fn current_phase): Phase = Phase::Off; + + /// Sorted list of unchecked, signed solutions. + pub SignedSubmissions get(fn signed_submissions): Vec>>; + + /// Current, best, unsigned solution. + pub QueuedSolution get(fn queued_solution): Option>; + + /// Raw targets. + /// Snapshot of all Voters. The indices if this will be used in election. + pub SnapshotTargets get(fn snapshot_targets): Vec; + /// Raw voters. + /// Snapshot of all targets. The indices if this will be used in election. + pub SnapshotVoters get(fn snapshot_voters): Vec<(T::AccountId, VoteWeight, Vec)>; + + /// Desired number of targets to elect + pub DesiredTargets get(fn desired_targets): u32; } } -// decl_event!( -// pub enum Event { -// } -// ); +decl_event!( + pub enum Event { + SolutionStored(ElectionCompute), + ElectionFinalized(ElectionCompute), + } +); + +decl_error! { + pub enum PalletError for Module { + EarlySubmission, + LowScoreSubmission, + SubmissionQueuedFull, + CannotPayDeposit, + } +} decl_module! { - // Simple declaration of the `Module` type. Lets the macro know what its working on. - pub struct Module for enum Call where origin: T::Origin {} + pub struct Module for enum Call where origin: T::Origin { + fn deposit_event() = default; + + fn on_initialize(now: T::BlockNumber) -> Weight { + let (next_election, weight) = T::ElectionDataProvider::next_election_prediction(); + // TODO: document this invariant. + let next_election = next_election.max(now); + + let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); + let unsigned_deadline = T::UnsignedPhase::get(); + + let remaining = next_election - now; + match Self::current_phase() { + Phase::Off => { + // check only for the signed phase. Note that next + if remaining < signed_deadline { + let w = Self::start_signed_phase(); + } + }, + Phase::Signed => { + // check the unsigned phase. + if remaining < unsigned_deadline { + let (found_solution, w) = Self::finalize_signed_phase(); + CurrentPhase::put(Phase::Unsigned(!found_solution)); + } + }, + Phase::Unsigned(_) => { + // Nothing. We wait in the unsigned phase until we receive the call to `elect`. + } + } + + + Default::default() + } + + fn offchain_worker(n: T::BlockNumber) { + + } + + #[weight = 0] + fn submit(origin, solution: RawSolution) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + + // ensure solution is timely. + ensure!(Self::current_phase().is_signed(), PalletError::::EarlySubmission); + + // ensure queued is not full. + let queue_size = >::decode_len().unwrap_or_default() as u32; + ensure!( + queue_size < T::MaxSignedSubmissions::get(), + PalletError::::SubmissionQueuedFull, + ); + + // ensure solution claims is better. + let mut signed_submissions = Self::signed_submissions(); + let improvement = signed_submissions.last().map_or( + true, + |best: &SignedSubmission<_, _>| -> bool { + is_score_better( + solution.score, + best.solution.score, + T::SolutionImprovementThreshold::get() + ) + } + ); + ensure!(improvement, PalletError::::LowScoreSubmission); + + // ensure... what else? + // TODO + + // collect deposit. Thereafter, the function cannot fail. + let deposit = Self::deposit_for(&solution); + T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; + + // amount to be rewarded if this solution is accepted. + let reward = Self::reward_for(&solution); + + signed_submissions.push(SignedSubmission { who, deposit, reward, solution }); + >::put(signed_submissions); + + Ok(None.into()) + } + + #[weight = 0] + fn submit_unsigned(origin, solution: RawSolution) { + ensure_none(origin)?; + unimplemented!() + } + } +} + +impl Module { + fn start_signed_phase() -> Weight { + let (targets, w1) = T::ElectionDataProvider::targets(); + // TODO: this module is not aware at all of self-vote. Clarify this. + let (voters, w2) = T::ElectionDataProvider::voters(); + let (desired_targets, w3) = T::ElectionDataProvider::desired_targets(); + + >::put(targets); + >::put(voters); + DesiredTargets::put(desired_targets); + + CurrentPhase::put(Phase::Signed); + Default::default() + } + + /// Returns true if we have a good solution in the signed phase. + fn finalize_signed_phase() -> (bool, Weight) { + let mut all_submission: Vec> = >::take(); + let mut found_solution = false; + + while let Some(best) = all_submission.pop() { + let SignedSubmission { + solution, + who, + deposit, + reward, + } = best; + match Self::feasibility_check(solution) { + (Ok(ready_solution), w) => { + >::put(ready_solution); + + // unreserve deposit. + let _remaining = T::Currency::unreserve(&who, deposit); + debug_assert!(_remaining.is_zero()); + + // Reward. + let positive_imbalance = T::Currency::deposit_creating(&who, reward); + T::RewardHandler::on_unbalanced(positive_imbalance); + + found_solution = true; + break; + } + (Err(_), w) => { + let (negative_imbalance, _remaining) = + T::Currency::slash_reserved(&who, deposit); + debug_assert!(_remaining.is_zero()); + T::SlashHandler::on_unbalanced(negative_imbalance); + } + } + } + + // Any unprocessed solution is not pointless to even ponder upon. Feasible or malicious, + // they didn't end up being used. Unreserve the bonds. + all_submission.into_iter().for_each(|not_processed| { + let SignedSubmission { who, deposit, .. } = not_processed; + let _remaining = T::Currency::unreserve(&who, deposit); + debug_assert!(_remaining.is_zero()); + }); + + (found_solution, Default::default()) + } + + fn feasibility_check( + solution: RawSolution, + ) -> (Result, ()>, Weight) { + unimplemented!() + } + + fn deposit_for(solution: &RawSolution) -> BalanceOf { + unimplemented!() + } + + fn reward_for(solution: &RawSolution) -> BalanceOf { + T::SignedRewardBase::get() + } + + fn onchain_fallback() -> Result, crate::Error> { + let desired_targets = Self::desired_targets() as usize; + let voters = Self::snapshot_voters(); + let targets = Self::snapshot_targets(); + >::elect::( + desired_targets, + targets, + voters, + ) + } +} + +impl crate::ElectionProvider for Module { + fn elect( + _to_elect: usize, + _targets: Vec, + _voters: Vec<(T::AccountId, VoteWeight, Vec)>, + ) -> Result, crate::Error> + where + ExtendedBalance: From<

::Inner>, + P: sp_std::ops::Mul, + { + CurrentPhase::put(Phase::Off); + Self::queued_solution().map_or_else( + || Self::onchain_fallback(), + |ReadySolution { supports, .. }| Ok(supports), + ) + } + + fn ongoing() -> bool { + matches!(Self::current_phase(), Phase::Signed | Phase::Unsigned(_)) + } +} + +#[cfg(test)] +mod tests { + + mod signed { + #[test] + fn cannot_submit_too_early() {} + + #[test] + fn should_pay_deposit() {} + + #[test] + fn cannot_submit_worse() {} + + #[test] + fn good_solution_is_rewarded() {} + + #[test] + fn bad_solution_is_slashed() {} + + #[test] + fn suppressed_solution_gets_bond_back() {} + + #[test] + fn all_in_one() { + // a combination of: + // - good_solution_is_rewarded + // - bad_solution_is_slashed + // - suppressed_solution_gets_bond_back + } + } + + mod unsigned {} } diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs index 238e7b644abcd..b88c0913538aa 100644 --- a/frame/election-providers/src/onchain.rs +++ b/frame/election-providers/src/onchain.rs @@ -1,19 +1,21 @@ use crate::{ElectionProvider, Error}; -use sp_npos_elections::{VoteWeight, ElectionResult, SupportMap, IdentifierT, ExtendedBalance}; use sp_arithmetic::PerThing; -use sp_std::collections::btree_map::BTreeMap; +use sp_npos_elections::{ + ElectionResult, ExtendedBalance, FlatSupportMap, IdentifierT, SupportMap, VoteWeight, +}; +use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub struct OnChainSequentialPhragmen; -impl ElectionProvider for OnChainSequentialPhragmen { +impl ElectionProvider for OnChainSequentialPhragmen { fn elect( to_elect: usize, - candidates: Vec, + targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Error> where + ) -> Result, Error> + where ExtendedBalance: From<

::Inner>, - P: sp_std::ops::Mul + P: sp_std::ops::Mul, { - // TODO: so henceforth, we will always return a Result here. // TODO: we really don't need to do this conversion all the time. With // https://github.com/paritytech/substrate/pull/6685 merged, we should make variants of // seq_phragmen and others that return a different return type. In fact, I think I should @@ -29,22 +31,25 @@ impl ElectionProvider for OnChain stake_map.get(w).cloned().unwrap_or_default() }); - sp_npos_elections::seq_phragmen::<_, P>( - to_elect, - 0, - candidates, - voters, - ).map(| ElectionResult { winners, assignments } | { - let staked = sp_npos_elections::assignment_ratio_to_staked_normalized( - assignments, - &stake_of, - ).unwrap(); + sp_npos_elections::seq_phragmen::<_, P>(to_elect, targets, voters, None) + .and_then(|e| { + let ElectionResult { + winners, + assignments, + } = e; + let staked = sp_npos_elections::assignment_ratio_to_staked_normalized( + assignments, + &stake_of, + )?; + let winners = sp_npos_elections::to_without_backing(winners); - let winners = sp_npos_elections::to_without_backing(winners); - let (supports, _error) = sp_npos_elections::build_support_map(&winners, &staked); + sp_npos_elections::build_support_map(&winners, &staked) + .map(|s| s.into_iter().map(|(k, v)| (k, v)).collect::>()) + }) + .map_err(From::from) + } - debug_assert_eq!(_error, 0); - supports - }).ok_or(Error::ElectionFailed) + fn ongoing() -> bool { + false } } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 88b8c1270a4e1..6d451a3ff1910 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -25,6 +25,7 @@ frame-support = { version = "2.0.0", default-features = false, path = "../suppor frame-system = { version = "2.0.0", default-features = false, path = "../system" } pallet-session = { version = "2.0.0", default-features = false, features = ["historical"], path = "../session" } pallet-authorship = { version = "2.0.0", default-features = false, path = "../authorship" } +frame-election-providers = { version = "2.0.0", default-features = false, path = "../election-providers" } sp-application-crypto = { version = "2.0.0", default-features = false, path = "../../primitives/application-crypto" } # Optional imports for benchmarking @@ -59,6 +60,7 @@ std = [ "frame-system/std", "pallet-authorship/std", "sp-application-crypto/std", + "frame-election-providers/std", ] runtime-benchmarks = [ "frame-benchmarking", diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index e5c1a68dfbeae..3efc2744d1816 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -885,6 +885,8 @@ pub trait Trait: frame_system::Trait + SendTransactionTypes> { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + type ElectionProvider: frame_election_providers::ElectionProvider; } /// Mode of era-forcing. @@ -2938,7 +2940,7 @@ impl Module { all_nominators, Some((iterations, 0)), // exactly run `iterations` rounds. ) - .map_err(|err| log!(error, "Call to seq-phragmen failed due to {}", err)) + .map_err(|err| log!(error, "Call to seq-phragmen failed due to {:?}", err)) .ok() } } diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 11951d2065989..c5381a983bc12 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -151,6 +151,8 @@ pub enum Error { CompactInvalidIndex, /// An error occurred in some arithmetic operation. ArithmeticError(&'static str), + /// The data provided to create support map was invalid. + InvalidSupportEdge, } /// A type which is used in the API of this crate as a numeric weight of a vote, most often the @@ -479,7 +481,7 @@ impl StakedAssignment { /// /// This, at the current version, resembles the `Exposure` defined in the Staking pallet, yet they /// do not necessarily have to be the same. -#[derive(Default, Debug)] +#[derive(Default, Debug, Encode, Decode, Clone)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Eq, PartialEq))] pub struct Support { /// Total support. @@ -491,6 +493,11 @@ pub struct Support { /// A linkage from a candidate and its [`Support`]. pub type SupportMap = BTreeMap>; +/// A flat variant of [`SupportMap`]. +/// +/// The main advantage of this is that it is encodable. +pub type FlatSupportMap = Vec<(A, Support)>; + /// Build the support map from the given election result. It maps a flat structure like /// /// ```nocompile @@ -525,7 +532,8 @@ pub type SupportMap = BTreeMap>; pub fn build_support_map( winners: &[AccountId], assignments: &[StakedAssignment], -) -> Result, AccountId> where +) -> Result, Error> +where AccountId: IdentifierT, { // Initialize the support of each candidate. @@ -541,7 +549,7 @@ pub fn build_support_map( support.total = support.total.saturating_add(*weight_extended); support.voters.push((who.clone(), *weight_extended)); } else { - return Err(c.clone()) + return Err(Error::InvalidSupportEdge) } } } diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index cfbeed1cdd3fb..efe462d7b5e6b 100644 --- a/primitives/npos-elections/src/phragmen.rs +++ b/primitives/npos-elections/src/phragmen.rs @@ -68,7 +68,10 @@ pub fn seq_phragmen( initial_candidates: Vec, initial_voters: Vec<(AccountId, VoteWeight, Vec)>, balance: Option<(usize, ExtendedBalance)>, -) -> Result, &'static str> where ExtendedBalance: From> { +) -> Result, crate::Error> +where + ExtendedBalance: From>, +{ let (candidates, voters) = setup_inputs(initial_candidates, initial_voters); let (candidates, mut voters) = seq_phragmen_core::( @@ -93,13 +96,26 @@ pub fn seq_phragmen( // sort winners based on desirability. winners.sort_by_key(|c_ptr| c_ptr.borrow().round); - let mut assignments = voters.into_iter().filter_map(|v| v.into_assignment()).collect::>(); - let _ = assignments.iter_mut().map(|a| a.try_normalize()).collect::>()?; - let winners = winners.into_iter().map(|w_ptr| - (w_ptr.borrow().who.clone(), w_ptr.borrow().backed_stake) - ).collect(); + let mut assignments = voters + .into_iter() + .filter_map(|v| v.into_assignment()) + .collect::>(); + let _ = assignments + .iter_mut() + .map(|a| { + a.try_normalize() + .map_err(|e| crate::Error::ArithmeticError(e)) + }) + .collect::>()?; + let winners = winners + .into_iter() + .map(|w_ptr| (w_ptr.borrow().who.clone(), w_ptr.borrow().backed_stake)) + .collect(); - Ok(ElectionResult { winners, assignments }) + Ok(ElectionResult { + winners, + assignments, + }) } /// Core implementation of seq-phragmen. @@ -115,7 +131,7 @@ pub fn seq_phragmen_core( rounds: usize, candidates: Vec>, mut voters: Vec>, -) -> Result<(Vec>, Vec>), &'static str> { +) -> Result<(Vec>, Vec>), crate::Error> { // we have already checked that we have more candidates than minimum_candidate_count. let to_elect = rounds.min(candidates.len()); @@ -199,7 +215,7 @@ pub fn seq_phragmen_core( // edge of all candidates that eventually have a non-zero weight must be elected. debug_assert!(voter.edges.iter().all(|e| e.candidate.borrow().elected)); // inc budget to sum the budget. - voter.try_normalize_elected()?; + voter.try_normalize_elected().map_err(|e| crate::Error::ArithmeticError(e))?; } Ok((candidates, voters)) From 14ebc9532e8f14bc5202e6272f04f8b682faaaff Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 2 Oct 2020 10:20:55 +0200 Subject: [PATCH 04/62] Lots more changes and tests. Initial design of signed is forseable now. --- .gitignore | 1 + Cargo.lock | 19 +- frame/election-providers/Cargo.toml | 8 + frame/election-providers/src/lib.rs | 36 +- frame/election-providers/src/onchain.rs | 4 +- .../election-providers/src/two_phase/mock.rs | 238 +++++++++++++ .../src/{offchain.rs => two_phase/mod.rs} | 326 ++++++++++-------- .../src/two_phase/signed.rs | 273 +++++++++++++++ .../src/two_phase/unsigned.rs | 0 9 files changed, 744 insertions(+), 161 deletions(-) create mode 100644 frame/election-providers/src/two_phase/mock.rs rename frame/election-providers/src/{offchain.rs => two_phase/mod.rs} (55%) create mode 100644 frame/election-providers/src/two_phase/signed.rs create mode 100644 frame/election-providers/src/two_phase/unsigned.rs diff --git a/.gitignore b/.gitignore index 353d49df28f34..c8f1ea9567bc2 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ rls*.log **/hfuzz_target/ **/hfuzz_workspace/ .cargo/ +.cargo-remote.toml diff --git a/Cargo.lock b/Cargo.lock index 4f16c17fb5437..c4b27840dc92a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1519,7 +1519,7 @@ dependencies = [ "hex-literal", "linregress", "parity-scale-codec", - "paste", + "paste 0.1.18", "sp-api", "sp-io", "sp-runtime", @@ -1552,15 +1552,20 @@ version = "2.0.0" dependencies = [ "frame-support", "frame-system", + "hex-literal", + "pallet-balances", "parity-scale-codec", + "paste 1.0.1", "serde", "sp-arithmetic", + "sp-core", "sp-io", "sp-npos-elections", "sp-runtime", "sp-staking", "sp-std", "static_assertions", + "substrate-test-utils", ] [[package]] @@ -1606,7 +1611,7 @@ dependencies = [ "once_cell 1.4.0", "parity-scale-codec", "parity-util-mem", - "paste", + "paste 0.1.18", "pretty_assertions", "serde", "smallvec 1.4.1", @@ -3264,7 +3269,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c50092e40e0ccd1bf2015a10333fde0502ff95b832b0895dc1ca0d7ac6c52f6" dependencies = [ - "paste", + "paste 0.1.18", ] [[package]] @@ -5331,6 +5336,12 @@ dependencies = [ "proc-macro-hack", ] +[[package]] +name = "paste" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0520af26d4cf99643dbbe093a61507922b57232d9978d8491fdc8f7b44573c8c" + [[package]] name = "paste-impl" version = "0.1.18" @@ -8237,7 +8248,7 @@ dependencies = [ "log", "parity-scale-codec", "parity-util-mem", - "paste", + "paste 0.1.18", "rand 0.7.3", "serde", "serde_json", diff --git a/frame/election-providers/Cargo.toml b/frame/election-providers/Cargo.toml index b936b59ca716c..b7be30e133f9e 100644 --- a/frame/election-providers/Cargo.toml +++ b/frame/election-providers/Cargo.toml @@ -26,6 +26,14 @@ sp-npos-elections = { version = "2.0.0-rc6", default-features = false, path = ". sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } sp-arithmetic = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/arithmetic" } +[dev-dependencies] +sp-io = { version = "2.0.0", path = "../../primitives/io" } +hex-literal = "0.3.1" +pallet-balances = { version = "2.0.0", path = "../balances" } +sp-core = { version = "2.0.0", path = "../../primitives/core" } +paste = "1.0.1" +substrate-test-utils = { version = "2.0.0", path = "../../test-utils" } + [features] default = ["std"] std = [ diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs index ca6282b9af85a..a190b83876632 100644 --- a/frame/election-providers/src/lib.rs +++ b/frame/election-providers/src/lib.rs @@ -1,14 +1,41 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_std::prelude::*; -pub mod offchain; pub mod onchain; +pub mod two_phase; use sp_arithmetic::PerThing; use sp_npos_elections::{ExtendedBalance, FlatSupportMap}; use sp_runtime::RuntimeDebug; -// TODO: maybe we can have this be generic in the trait? probably in the future. -use sp_npos_elections::VoteWeight; + +// for the helper macros +#[doc(hidden)] +pub use sp_npos_elections::VoteWeight; +#[doc(hidden)] +pub use sp_std::convert::TryInto; + +pub trait ElectionDataProvider { + fn targets() -> Vec; + fn voters() -> Vec<(AccountId, VoteWeight, Vec)>; + fn desired_targets() -> u32; + fn next_election_prediction(now: B) -> B; +} + +#[cfg(feature = "std")] +impl ElectionDataProvider for () { + fn targets() -> Vec { + Default::default() + } + fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { + Default::default() + } + fn desired_targets() -> u32 { + Default::default() + } + fn next_election_prediction(_: B) -> B { + Default::default() + } +} /// Something that can compute the result of an election and pass it back to a pallet. pub trait ElectionProvider { @@ -16,7 +43,7 @@ pub trait ElectionProvider { /// /// The result is returned in a target major format, namely as a support map. fn elect( - to_elect: usize, + to_elect: usize, // TODO: consider making this u32 targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, ) -> Result, Error> @@ -35,6 +62,7 @@ pub trait ElectionProvider { #[derive(RuntimeDebug, Eq, PartialEq)] pub enum Error { ElectionFailed, + SnapshotUnAvailable, Internal(sp_npos_elections::Error), } diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs index b88c0913538aa..43ed95e866c76 100644 --- a/frame/election-providers/src/onchain.rs +++ b/frame/election-providers/src/onchain.rs @@ -1,8 +1,6 @@ use crate::{ElectionProvider, Error}; use sp_arithmetic::PerThing; -use sp_npos_elections::{ - ElectionResult, ExtendedBalance, FlatSupportMap, IdentifierT, SupportMap, VoteWeight, -}; +use sp_npos_elections::{ElectionResult, ExtendedBalance, FlatSupportMap, IdentifierT, VoteWeight}; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub struct OnChainSequentialPhragmen; diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs new file mode 100644 index 0000000000000..cd663333b36eb --- /dev/null +++ b/frame/election-providers/src/two_phase/mock.rs @@ -0,0 +1,238 @@ +use super::*; +use frame_support::{parameter_types, traits::OnInitialize, weights::Weight}; +use sp_core::H256; +use sp_npos_elections::FlatSupportMap; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; +use std::cell::RefCell; + +pub use frame_support::{assert_noop, assert_ok}; + +#[derive(Eq, PartialEq, Clone)] +pub struct Runtime; +pub(crate) type Balances = pallet_balances::Module; +pub(crate) type System = frame_system::Module; +pub(crate) type TwoPhase = super::Module; +pub(crate) type Balance = u64; +pub(crate) type AccountId = u64; + +/// To from `now` to block `n`. +pub fn roll_to(n: u64) { + let now = System::block_number(); + for i in now + 1..=n { + System::set_block_number(i); + TwoPhase::on_initialize(i); + } +} + +/// Get the free and reserved balance of some account. +pub fn balances(who: &AccountId) -> (Balance, Balance) { + (Balances::free_balance(who), Balances::reserved_balance(who)) +} + +/// Spit out a verifiable raw solution. +/// +/// This is a good example of what an offchain miner would do. +pub fn raw_solution() -> RawSolution { + let voters = TwoPhase::snapshot_voters().unwrap(); + let targets = TwoPhase::snapshot_targets().unwrap(); + let desired = TwoPhase::desired_targets() as usize; + + // closures + let voter_at = crate::voter_at_fn!(voters, AccountId); + let target_at = crate::target_at_fn!(targets, AccountId); + let stake_of = crate::stake_of_fn!(voters, AccountId); + + use sp_npos_elections::{seq_phragmen, to_without_backing, ElectionResult}; + let ElectionResult { + winners, + assignments, + } = seq_phragmen::<_, OffchainAccuracy>(desired, targets.clone(), voters.clone(), None).unwrap(); + + let winners = to_without_backing(winners); + + let score = { + // TODO: we really need to clean this process. + let staked = sp_npos_elections::assignment_ratio_to_staked(assignments.clone(), &stake_of); + let support = sp_npos_elections::build_support_map(&winners, &staked).unwrap(); + sp_npos_elections::evaluate_support(&support) + }; + let compact = CompactAssignments::from_assignment(assignments, &voter_at, &target_at).unwrap(); + + RawSolution { + compact, + winners, + score, + } +} + +frame_support::impl_outer_origin! { + pub enum Origin for Runtime where system = frame_system {} +} + +impl frame_system::Trait for Runtime { + type BaseCallFilter = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = (); + type MaximumBlockWeight = (); + type DbWeight = (); + type BlockExecutionWeight = (); + type ExtrinsicBaseWeight = (); + type MaximumExtrinsicWeight = (); + type MaximumBlockLength = (); + type AvailableBlockRatio = (); + type Version = (); + type PalletInfo = (); + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); +} + +parameter_types! { + pub const ExistentialDeposit: u64 = 1; +} + +impl pallet_balances::Trait for Runtime { + type Balance = Balance; + type Event = (); + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type MaxLocks = (); + type WeightInfo = (); +} + +use paste::paste; +macro_rules! parameter_types_thread_local { + ( + $( + static $name:ident : $type:ty = $default:expr; + )* + ) => { + parameter_types_thread_local! { + @THREAD_LOCAL($( + $name, $type, $default, + )*) + } + + parameter_types_thread_local! { + @GETTER_STRUCT($( + $name, $type, + )*) + } + }; + (@THREAD_LOCAL($($name:ident, $type:ty, $default:expr,)*)) => { + thread_local! { + $( + static $name: RefCell<$type> = RefCell::new($default); + )* + } + }; + (@GETTER_STRUCT($($name:ident, $type:ty,)*)) => { + $( + paste! { + pub struct [<$name:camel>]; + impl Get<$type> for [<$name:camel>] { + fn get() -> $type { $name.with(|v| v.borrow().clone() )} + } + } + )* + } +} + +parameter_types_thread_local! { + static SIGNED_PHASE: u64 = 10; + static UNSIGNED_PHASE: u64 = 5; + static MAX_SIGNED_SUBMISSIONS: u32 = 5; + static TARGETS: Vec = vec![10, 20, 30, 40]; + static VOTERS: Vec<(AccountId, VoteWeight, Vec)> = vec![ + (1, 10, vec![10, 20]), + (2, 10, vec![30, 40]), + (3, 10, vec![40]), + (4, 10, vec![10, 20, 30, 40]), + // self votes. + (10, 10, vec![10]), + (20, 20, vec![20]), + (30, 30, vec![30]), + (40, 40, vec![40]), + ]; + static DESIRED_TARGETS: u32 = 2; + static SIGNED_DEPOSIT_BASE: Balance = 5; + static SIGNED_REWARD_BASE: Balance = 5; +} + +impl crate::ElectionDataProvider for ExtBuilder { + fn targets() -> Vec { + Targets::get() + } + fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { + Voters::get() + } + fn desired_targets() -> u32 { + DesiredTargets::get() + } + fn next_election_prediction(now: u64) -> u64 { + now + 20 - now % 20 + } +} + +impl crate::two_phase::Trait for Runtime { + type Event = (); + type Currency = Balances; + type SignedPhase = SignedPhase; + type UnsignedPhase = UnsignedPhase; + type MaxSignedSubmissions = MaxSignedSubmissions; + type SignedRewardBase = SignedRewardBase; + type SignedRewardFactor = (); + type SignedDepositBase = SignedDepositBase; + type SignedDepositByte = (); + type SignedDepositWeight = (); + type SolutionImprovementThreshold = (); + type SlashHandler = (); + type RewardHandler = (); + type ElectionDataProvider = ExtBuilder; + type WeightInfo = (); +} + +pub struct ExtBuilder { + signed_phase: u64, + unsigned_phase: u64, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { + signed_phase: SignedPhase::get(), + unsigned_phase: UnsignedPhase::get(), + } + } +} + +impl ExtBuilder { + fn set_constants(&self) {} + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.set_constants(); + let mut storage = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + let _ = pallet_balances::GenesisConfig:: { + balances: vec![(99, 100)], + } + .assimilate_storage(&mut storage); + + sp_io::TestExternalities::from(storage).execute_with(test) + } +} diff --git a/frame/election-providers/src/offchain.rs b/frame/election-providers/src/two_phase/mod.rs similarity index 55% rename from frame/election-providers/src/offchain.rs rename to frame/election-providers/src/two_phase/mod.rs index 47db7e66de8a4..79a953bb90b7a 100644 --- a/frame/election-providers/src/offchain.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -1,4 +1,4 @@ -use crate::{onchain::OnChainSequentialPhragmen, ElectionProvider, Error}; +use crate::{onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, Error}; use codec::{Decode, Encode, HasCompact}; use frame_support::{ decl_error, decl_event, decl_module, decl_storage, @@ -15,12 +15,10 @@ use sp_npos_elections::{ use sp_runtime::{traits::Zero, PerThing, PerU16, Perbill, RuntimeDebug}; use sp_std::{mem::size_of, prelude::*}; -pub trait ElectionDataProvider { - fn targets() -> (Vec, Weight); - fn voters() -> (Vec<(AccountId, VoteWeight, Vec)>, Weight); - fn desired_targets() -> (u32, Weight); - fn next_election_prediction() -> (B, Weight); -} +#[cfg(test)] +mod mock; +pub mod signed; +pub mod unsigned; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -36,7 +34,7 @@ pub type ChainAccuracy = Perbill; /// Accuracy used for off-chain election. This better be small. pub type OffchainAccuracy = PerU16; -/// Data type used to index nominators in the compact type +/// Data type used to index nominators in the compact type. pub type VoterIndex = u32; /// Data type used to index validators in the compact type. @@ -54,6 +52,45 @@ generate_solution_type!( pub struct CompactAssignments::(16) ); +#[macro_export] +macro_rules! voter_at_fn { + ($voters:ident, $acc:ty) => { + |who: &$acc| -> Option<$crate::two_phase::VoterIndex> { + $voters + .iter() + .position(|(x, _, _)| x == who) + .and_then(|i| >::try_into(i).ok()) + } + }; +} + +#[macro_export] +macro_rules! target_at_fn { + ($targets:ident, $acc:ty) => { + |who: &$acc| -> Option<$crate::two_phase::TargetIndex> { + $targets + .iter() + .position(|x| x == who) + .and_then(|i| >::try_into(i).ok()) + } + }; +} + +// TODO: these can use a cache. +// TODO: move these to test if they are not used.. They most likely will be used in offchain. +#[macro_export] +macro_rules! stake_of_fn { + ($voters:ident, $acc:ty) => { + |who: &$acc| -> $crate::VoteWeight { + $voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + } + }; +} + #[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] pub enum Phase { Off, @@ -92,7 +129,7 @@ pub enum ElectionCompute { Unsigned, } -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] pub struct RawSolution { winners: Vec, compact: CompactAssignments, @@ -115,6 +152,7 @@ pub struct ReadySolution { } pub trait WeightInfo {} +impl WeightInfo for () {} pub trait Trait: frame_system::Trait { type Event: From + Into<::Event>; @@ -127,12 +165,13 @@ pub trait Trait: frame_system::Trait { type MaxSignedSubmissions: Get; type SignedRewardBase: Get>; - type SignedRewardFactor: Get>; + type SignedRewardFactor: Get; - type SolutionImprovementThreshold: Get; + type SignedDepositBase: Get>; + type SignedDepositByte: Get>; + type SignedDepositWeight: Get>; - type SubmissionBondBase: Get>; - type SubmissionBondByte: Get>; + type SolutionImprovementThreshold: Get; type SlashHandler: OnUnbalanced>; type RewardHandler: OnUnbalanced>; @@ -153,13 +192,15 @@ decl_storage! { /// Current, best, unsigned solution. pub QueuedSolution get(fn queued_solution): Option>; - /// Raw targets. /// Snapshot of all Voters. The indices if this will be used in election. - pub SnapshotTargets get(fn snapshot_targets): Vec; + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub SnapshotTargets get(fn snapshot_targets): Option>; - /// Raw voters. /// Snapshot of all targets. The indices if this will be used in election. - pub SnapshotVoters get(fn snapshot_voters): Vec<(T::AccountId, VoteWeight, Vec)>; + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub SnapshotVoters get(fn snapshot_voters): Option)>>; /// Desired number of targets to elect pub DesiredTargets get(fn desired_targets): u32; @@ -187,7 +228,7 @@ decl_module! { fn deposit_event() = default; fn on_initialize(now: T::BlockNumber) -> Weight { - let (next_election, weight) = T::ElectionDataProvider::next_election_prediction(); + let next_election = T::ElectionDataProvider::next_election_prediction(now); // TODO: document this invariant. let next_election = next_election.max(now); @@ -196,20 +237,17 @@ decl_module! { let remaining = next_election - now; match Self::current_phase() { - Phase::Off => { - // check only for the signed phase. Note that next - if remaining < signed_deadline { - let w = Self::start_signed_phase(); - } + Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { + // check only for the signed phase. + CurrentPhase::put(Phase::Signed); + Self::start_signed_phase(); }, - Phase::Signed => { + Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { // check the unsigned phase. - if remaining < unsigned_deadline { - let (found_solution, w) = Self::finalize_signed_phase(); - CurrentPhase::put(Phase::Unsigned(!found_solution)); - } + let found_solution = Self::finalize_signed_phase(); + CurrentPhase::put(Phase::Unsigned(!found_solution)); }, - Phase::Unsigned(_) => { + _ => { // Nothing. We wait in the unsigned phase until we receive the call to `elect`. } } @@ -232,35 +270,25 @@ decl_module! { // ensure queued is not full. let queue_size = >::decode_len().unwrap_or_default() as u32; ensure!( - queue_size < T::MaxSignedSubmissions::get(), + queue_size <= T::MaxSignedSubmissions::get(), PalletError::::SubmissionQueuedFull, ); // ensure solution claims is better. let mut signed_submissions = Self::signed_submissions(); - let improvement = signed_submissions.last().map_or( - true, - |best: &SignedSubmission<_, _>| -> bool { - is_score_better( - solution.score, - best.solution.score, - T::SolutionImprovementThreshold::get() - ) - } - ); - ensure!(improvement, PalletError::::LowScoreSubmission); + let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution); + ensure!(maybe_index.is_some(), PalletError::::LowScoreSubmission); + let index = maybe_index.expect("Option checked to be `Some`; qed."); // ensure... what else? // TODO // collect deposit. Thereafter, the function cannot fail. - let deposit = Self::deposit_for(&solution); + let deposit = signed_submissions[index].deposit; T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; - // amount to be rewarded if this solution is accepted. - let reward = Self::reward_for(&solution); - - signed_submissions.push(SignedSubmission { who, deposit, reward, solution }); + // store the new signed submission. + debug_assert_eq!(signed_submissions.len() as u32, queue_size + 1); >::put(signed_submissions); Ok(None.into()) @@ -274,86 +302,18 @@ decl_module! { } } +// General stuff impl Module { - fn start_signed_phase() -> Weight { - let (targets, w1) = T::ElectionDataProvider::targets(); - // TODO: this module is not aware at all of self-vote. Clarify this. - let (voters, w2) = T::ElectionDataProvider::voters(); - let (desired_targets, w3) = T::ElectionDataProvider::desired_targets(); - - >::put(targets); - >::put(voters); - DesiredTargets::put(desired_targets); - - CurrentPhase::put(Phase::Signed); - Default::default() - } - - /// Returns true if we have a good solution in the signed phase. - fn finalize_signed_phase() -> (bool, Weight) { - let mut all_submission: Vec> = >::take(); - let mut found_solution = false; - - while let Some(best) = all_submission.pop() { - let SignedSubmission { - solution, - who, - deposit, - reward, - } = best; - match Self::feasibility_check(solution) { - (Ok(ready_solution), w) => { - >::put(ready_solution); - - // unreserve deposit. - let _remaining = T::Currency::unreserve(&who, deposit); - debug_assert!(_remaining.is_zero()); - - // Reward. - let positive_imbalance = T::Currency::deposit_creating(&who, reward); - T::RewardHandler::on_unbalanced(positive_imbalance); - - found_solution = true; - break; - } - (Err(_), w) => { - let (negative_imbalance, _remaining) = - T::Currency::slash_reserved(&who, deposit); - debug_assert!(_remaining.is_zero()); - T::SlashHandler::on_unbalanced(negative_imbalance); - } - } - } - - // Any unprocessed solution is not pointless to even ponder upon. Feasible or malicious, - // they didn't end up being used. Unreserve the bonds. - all_submission.into_iter().for_each(|not_processed| { - let SignedSubmission { who, deposit, .. } = not_processed; - let _remaining = T::Currency::unreserve(&who, deposit); - debug_assert!(_remaining.is_zero()); - }); - - (found_solution, Default::default()) - } - fn feasibility_check( solution: RawSolution, - ) -> (Result, ()>, Weight) { + ) -> Result, ()> { unimplemented!() } - fn deposit_for(solution: &RawSolution) -> BalanceOf { - unimplemented!() - } - - fn reward_for(solution: &RawSolution) -> BalanceOf { - T::SignedRewardBase::get() - } - fn onchain_fallback() -> Result, crate::Error> { let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters(); - let targets = Self::snapshot_targets(); + let voters = Self::snapshot_voters().ok_or(crate::Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(crate::Error::SnapshotUnAvailable)?; >::elect::( desired_targets, targets, @@ -372,11 +332,19 @@ impl crate::ElectionProvider for Module { ExtendedBalance: From<

::Inner>, P: sp_std::ops::Mul, { - CurrentPhase::put(Phase::Off); - Self::queued_solution().map_or_else( - || Self::onchain_fallback(), - |ReadySolution { supports, .. }| Ok(supports), - ) + Self::queued_solution() + .map_or_else( + || Self::onchain_fallback(), + |ReadySolution { supports, .. }| Ok(supports), + ) + .map(|result| { + // reset phase. + CurrentPhase::put(Phase::Off); + // clear snapshots. + >::kill(); + >::kill(); + result + }) } fn ongoing() -> bool { @@ -386,34 +354,92 @@ impl crate::ElectionProvider for Module { #[cfg(test)] mod tests { + use super::{mock::*, *}; + use crate::ElectionProvider; + use frame_support::traits::OnInitialize; + use sp_npos_elections::Support; + + #[test] + fn phase_rotation_works() { + ExtBuilder::default().build_and_execute(|| { + // 0 ------- 5 -------------- 15 ------- 20 + // | | + // Signed Unsigned + + assert_eq!(System::block_number(), 0); + assert_eq!(TwoPhase::current_phase(), Phase::Off); + + roll_to(4); + assert_eq!(TwoPhase::current_phase(), Phase::Off); + assert!(TwoPhase::snapshot_voters().is_none()); + + roll_to(5); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + assert!(TwoPhase::snapshot_voters().is_some()); + + roll_to(14); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + assert!(TwoPhase::snapshot_voters().is_some()); + + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned(true)); + assert!(TwoPhase::snapshot_voters().is_some()); + + roll_to(19); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned(true)); + assert!(TwoPhase::snapshot_voters().is_some()); + + roll_to(20); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned(true)); + assert!(TwoPhase::snapshot_voters().is_some()); + + // we close when upstream tells us to elect. + roll_to(21); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned(true)); + assert!(TwoPhase::snapshot_voters().is_some()); + + TwoPhase::elect::(2, Default::default(), Default::default()) + .unwrap(); + assert_eq!(TwoPhase::current_phase(), Phase::Off); + assert!(TwoPhase::snapshot_voters().is_none()); + }) + } - mod signed { - #[test] - fn cannot_submit_too_early() {} - - #[test] - fn should_pay_deposit() {} - - #[test] - fn cannot_submit_worse() {} - - #[test] - fn good_solution_is_rewarded() {} - - #[test] - fn bad_solution_is_slashed() {} - - #[test] - fn suppressed_solution_gets_bond_back() {} - - #[test] - fn all_in_one() { - // a combination of: - // - good_solution_is_rewarded - // - bad_solution_is_slashed - // - suppressed_solution_gets_bond_back - } + #[test] + fn onchain_backup_works() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + + roll_to(20); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned(true)); + + // zilch solutions thus far. + let supports = + TwoPhase::elect::(2, Default::default(), Default::default()) + .unwrap(); + assert_eq!( + supports, + vec![ + ( + 30, + Support { + total: 40, + voters: vec![(2, 5), (4, 5), (30, 30)] + } + ), + ( + 40, + Support { + total: 60, + voters: vec![(2, 5), (3, 10), (4, 5), (40, 40)] + } + ) + ] + ) + }) } - mod unsigned {} + #[test] + fn can_only_submit_threshold_better() {} } diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs new file mode 100644 index 0000000000000..0b9defaf71eb6 --- /dev/null +++ b/frame/election-providers/src/two_phase/signed.rs @@ -0,0 +1,273 @@ +use crate::two_phase::*; +use codec::Encode; +use sp_arithmetic::traits::SaturatedConversion; + +impl Module { + /// Start the signed phase. + /// + /// Upon calling this, auxillary data for election is stored and signed solutions will be + /// accepted. + /// + /// The signed phase must always start before the unsigned phase. + pub fn start_signed_phase() { + let targets = T::ElectionDataProvider::targets(); + // TODO: this module is not aware at all of self-vote. Clarify this. + let voters = T::ElectionDataProvider::voters(); + let desired_targets = T::ElectionDataProvider::desired_targets(); + + >::put(targets); + >::put(voters); + DesiredTargets::put(desired_targets); + } + + /// Finish the singed phase. + /// + /// Returns true if we have a good solution in the signed phase. + pub fn finalize_signed_phase() -> bool { + let mut all_submission: Vec> = >::take(); + let mut found_solution = false; + + while let Some(best) = all_submission.pop() { + let SignedSubmission { + solution, + who, + deposit, + reward, + } = best; + match Self::feasibility_check(solution) { + Ok(ready_solution) => { + >::put(ready_solution); + + // unreserve deposit. + let _remaining = T::Currency::unreserve(&who, deposit); + debug_assert!(_remaining.is_zero()); + + // Reward. + let positive_imbalance = T::Currency::deposit_creating(&who, reward); + T::RewardHandler::on_unbalanced(positive_imbalance); + + found_solution = true; + break; + } + Err(_) => { + let (negative_imbalance, _remaining) = + T::Currency::slash_reserved(&who, deposit); + debug_assert!(_remaining.is_zero()); + T::SlashHandler::on_unbalanced(negative_imbalance); + } + } + } + + // Any unprocessed solution is not pointless to even ponder upon. Feasible or malicious, + // they didn't end up being used. Unreserve the bonds. + all_submission.into_iter().for_each(|not_processed| { + let SignedSubmission { who, deposit, .. } = not_processed; + let _remaining = T::Currency::unreserve(&who, deposit); + debug_assert!(_remaining.is_zero()); + }); + + found_solution + } + + /// Find a proper position in the queue for the signed queue, whilst maintaining the order of + /// solution quality. + pub fn insert_submission( + who: &T::AccountId, + queue: &mut Vec>>, + solution: RawSolution, + ) -> Option { + use sp_npos_elections::is_score_better; + // consider using VecDeQue or sth like that? + + let outcome = queue + .iter() + .enumerate() + .rev() + .find_map(|(i, s)| { + if is_score_better( + solution.score, + s.solution.score, + T::SolutionImprovementThreshold::get(), + ) { + Some(i + 1) + } else { + None + } + }) + .or(Some(0)) + .and_then(|at| { + if at == 0 && queue.len() as u32 >= T::MaxSignedSubmissions::get() { + // if this is worse than all, and the queue is full, don't bother. + None + } else { + // add to the designated spo. If the length is too much, remove one. + let reward = Self::reward_for(&solution); + let deposit = Self::deposit_for(&solution); + let submission = SignedSubmission { + who: who.clone(), + deposit, + reward, + solution, + }; + // TODO: write proof that this cannot panic + queue.insert(at, submission); + if queue.len() as u32 >= T::MaxSignedSubmissions::get() { + queue.remove(0); + Some(at - 1) + } else { + Some(at) + } + } + }); + + debug_assert!(queue.len() as u32 <= T::MaxSignedSubmissions::get()); + outcome + } + + pub fn deposit_for(solution: &RawSolution) -> BalanceOf { + let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); + // TODO + T::SignedDepositBase::get() + T::SignedDepositByte::get() * encoded_len + } + + pub fn reward_for(solution: &RawSolution) -> BalanceOf { + T::SignedRewardBase::get() + + T::SignedRewardFactor::get() * solution.score[0].saturated_into::>() + } +} + +#[cfg(test)] +mod tests { + use super::{mock::*, *}; + use crate::*; + + #[test] + fn cannot_submit_too_early() { + ExtBuilder::default().build_and_execute(|| { + roll_to(2); + assert_eq!(TwoPhase::current_phase(), Phase::Off); + + // create a temp snapshot only for this test. + TwoPhase::start_signed_phase(); + let solution = raw_solution(); + + assert_noop!( + TwoPhase::submit(Origin::signed(10), solution), + PalletError::::EarlySubmission + ); + }) + } + + #[test] + fn should_pay_deposit() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + + let solution = raw_solution(); + assert_eq!(balances(&99), (100, 0)); + + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + + assert_eq!(balances(&99), (95, 5)); + assert_eq!(TwoPhase::signed_submissions().first().unwrap().deposit, 5); + }) + } + + #[test] + fn good_solution_is_rewarded() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + + let mut solution = raw_solution(); + // cheat here. + solution.score[0] += 1; + assert_eq!(balances(&99), (100, 0)); + + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!(balances(&99), (95, 5)); + + assert!(TwoPhase::finalize_signed_phase()); + assert_eq!(balances(&99), (100 + 5, 0)); + }) + } + + #[test] + fn bad_solution_is_slashed() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + + let solution = raw_solution(); + assert_eq!(balances(&99), (100, 0)); + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!(balances(&99), (95, 5)); + + assert!(TwoPhase::finalize_signed_phase()); + assert_eq!(balances(&99), (95, 0)); + }) + } + + #[test] + fn queue_is_always_sorted() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + + let solution = RawSolution { + winners: vec![1u64], + score: [5, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + + // then a worse one. + let solution = RawSolution { + winners: vec![2u64], + score: [4, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + + // then a better one. + let solution = RawSolution { + winners: vec![3u64], + score: [6, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + + assert_eq!( + TwoPhase::signed_submissions() + .iter() + .map(|x| x.solution.winners[0]) + .collect::>(), + vec![2, 1, 3] + ); + }) + } + + #[test] + fn can_submit_until_queue_full() {} + + #[test] + fn weakest_is_removed_if_better_provided() {} + + #[test] + fn cannot_submit_worse_with_full_queue() {} + + #[test] + fn suppressed_solution_gets_bond_back() {} + + #[test] + fn solutions_are_sorted() {} + + #[test] + fn all_in_one_singed_submission() { + // a combination of: + // - good_solution_is_rewarded + // - bad_solution_is_slashed + // - suppressed_solution_gets_bond_back + } +} diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs new file mode 100644 index 0000000000000..e69de29bb2d1d From 233d4e16b0f89a89e82e90ad486866dcfd91a9a0 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 9 Oct 2020 11:06:00 +0200 Subject: [PATCH 05/62] More changes for the signed phase, now going to the cluster-fu*k of generic Compact. --- frame/election-providers/exapnded.test.rs | 7700 +++++++++++++++++ frame/election-providers/expanded.rs | 5567 ++++++++++++ frame/election-providers/src/lib.rs | 133 +- frame/election-providers/src/onchain.rs | 26 +- .../src/two_phase/macros.rs | 66 + .../election-providers/src/two_phase/mock.rs | 74 +- frame/election-providers/src/two_phase/mod.rs | 458 +- .../src/two_phase/signed.rs | 331 +- primitives/npos-elections/src/lib.rs | 61 +- 9 files changed, 14242 insertions(+), 174 deletions(-) create mode 100644 frame/election-providers/exapnded.test.rs create mode 100644 frame/election-providers/expanded.rs create mode 100644 frame/election-providers/src/two_phase/macros.rs diff --git a/frame/election-providers/exapnded.test.rs b/frame/election-providers/exapnded.test.rs new file mode 100644 index 0000000000000..2b811ec618ab9 --- /dev/null +++ b/frame/election-providers/exapnded.test.rs @@ -0,0 +1,7700 @@ +#![feature(prelude_import)] +#[prelude_import] +use std::prelude::v1::*; +#[macro_use] +extern crate std; +use sp_std::prelude::*; +pub mod onchain { + use crate::{ElectionProvider, Error}; + use sp_arithmetic::PerThing; + use sp_npos_elections::{ + ElectionResult, ExtendedBalance, FlatSupportMap, FlattenSupportMap, IdentifierT, VoteWeight, + }; + use sp_std::{collections::btree_map::BTreeMap, prelude::*}; + pub struct OnChainSequentialPhragmen; + impl ElectionProvider for OnChainSequentialPhragmen { + fn elect( + to_elect: usize, + targets: Vec, + voters: Vec<(AccountId, VoteWeight, Vec)>, + ) -> Result, Error> + where + ExtendedBalance: From<

::Inner>, + P: sp_std::ops::Mul, + { + let mut stake_map: BTreeMap = BTreeMap::new(); + voters.iter().for_each(|(v, s, _)| { + stake_map.insert(v.clone(), *s); + }); + let stake_of = Box::new(|w: &AccountId| -> VoteWeight { + stake_map.get(w).cloned().unwrap_or_default() + }); + sp_npos_elections::seq_phragmen::<_, P>(to_elect, targets, voters, None) + .and_then(|e| { + let ElectionResult { + winners, + assignments, + } = e; + let staked = sp_npos_elections::assignment_ratio_to_staked_normalized( + assignments, + &stake_of, + )?; + let winners = sp_npos_elections::to_without_backing(winners); + sp_npos_elections::build_support_map(&winners, &staked).map(|s| s.flatten()) + }) + .map_err(From::from) + } + fn ongoing() -> bool { + false + } + } +} +pub mod two_phase { + use crate::{ + onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, Error, + }; + use codec::{Decode, Encode, HasCompact}; + use frame_support::{ + decl_error, decl_event, decl_module, decl_storage, + dispatch::DispatchResultWithPostInfo, + ensure, + traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, + weights::Weight, + }; + use frame_system::{ensure_none, ensure_signed}; + use sp_npos_elections::{ + evaluate_support, generate_solution_type, is_score_better, Assignment, ElectionScore, + ExtendedBalance, FlatSupportMap, FlattenSupportMap, VoteWeight, + }; + use sp_runtime::{traits::Zero, PerThing, PerU16, Perbill, RuntimeDebug}; + use sp_std::{mem::size_of, prelude::*}; + #[cfg(test)] + mod mock { + use super::*; + pub use frame_support::{assert_noop, assert_ok}; + use frame_support::{parameter_types, traits::OnInitialize, weights::Weight}; + use sp_core::H256; + use sp_npos_elections::FlatSupportMap; + use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + }; + use std::cell::RefCell; + pub struct Runtime; + impl ::core::marker::StructuralEq for Runtime {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Runtime { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + {} + } + } + impl ::core::marker::StructuralPartialEq for Runtime {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Runtime { + #[inline] + fn eq(&self, other: &Runtime) -> bool { + match *other { + Runtime => match *self { + Runtime => true, + }, + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Runtime { + #[inline] + fn clone(&self) -> Runtime { + match *self { + Runtime => Runtime, + } + } + } + pub(crate) type Balances = pallet_balances::Module; + pub(crate) type System = frame_system::Module; + pub(crate) type TwoPhase = super::Module; + pub(crate) type Balance = u64; + pub(crate) type AccountId = u64; + /// To from `now` to block `n`. + pub fn roll_to(n: u64) { + let now = System::block_number(); + for i in now + 1..=n { + System::set_block_number(i); + TwoPhase::on_initialize(i); + } + } + /// Get the free and reserved balance of some account. + pub fn balances(who: &AccountId) -> (Balance, Balance) { + (Balances::free_balance(who), Balances::reserved_balance(who)) + } + /// Spit out a verifiable raw solution. + /// + /// This is a good example of what an offchain miner would do. + pub fn raw_solution() -> RawSolution { + let voters = TwoPhase::snapshot_voters().unwrap(); + let targets = TwoPhase::snapshot_targets().unwrap(); + let desired = TwoPhase::desired_targets() as usize; + let voter_index = |who: &AccountId| -> Option { + voters.iter().position(|(x, _, _)| x == who).and_then(|i| { + >::try_into(i).ok() + }) + }; + let target_index = |who: &AccountId| -> Option { + targets.iter().position(|x| x == who).and_then(|i| { + >::try_into(i).ok() + }) + }; + let stake_of = |who: &AccountId| -> crate::VoteWeight { + voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + }; + use sp_npos_elections::{seq_phragmen, to_without_backing, ElectionResult}; + let ElectionResult { + winners, + assignments, + } = seq_phragmen::<_, OffchainAccuracy>(desired, targets.clone(), voters.clone(), None) + .unwrap(); + let winners = to_without_backing(winners); + let score = { + let staked = + sp_npos_elections::assignment_ratio_to_staked(assignments.clone(), &stake_of); + let support = sp_npos_elections::build_support_map(&winners, &staked).unwrap(); + sp_npos_elections::evaluate_support(&support) + }; + let compact = + CompactAssignments::from_assignment(assignments, &voter_index, &target_index) + .unwrap(); + let winners = winners + .into_iter() + .map(|w| target_index(&w).unwrap()) + .collect::>(); + RawSolution { + winners, + compact, + score, + } + } + pub struct Origin { + caller: OriginCaller, + filter: ::frame_support::sp_std::rc::Rc< + Box::Call) -> bool>, + >, + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Origin { + #[inline] + fn clone(&self) -> Origin { + match *self { + Origin { + caller: ref __self_0_0, + filter: ref __self_0_1, + } => Origin { + caller: ::core::clone::Clone::clone(&(*__self_0_0)), + filter: ::core::clone::Clone::clone(&(*__self_0_1)), + }, + } + } + } + #[cfg(feature = "std")] + impl ::frame_support::sp_std::fmt::Debug for Origin { + fn fmt( + &self, + fmt: &mut ::frame_support::sp_std::fmt::Formatter, + ) -> ::frame_support::sp_std::result::Result<(), ::frame_support::sp_std::fmt::Error> { + fmt.debug_struct("Origin") + .field("caller", &self.caller) + .field("filter", &"[function ptr]") + .finish() + } + } + impl ::frame_support::traits::OriginTrait for Origin { + type Call = ::Call; + type PalletsOrigin = OriginCaller; + type AccountId = ::AccountId; + fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static) { + let f = self.filter.clone(); + self.filter = ::frame_support::sp_std::rc::Rc::new(Box::new(move |call| { + f(call) && filter(call) + })); + } + fn reset_filter(&mut self) { + let filter = < < Runtime as frame_system :: Trait > :: BaseCallFilter as :: frame_support :: traits :: Filter < < Runtime as frame_system :: Trait > :: Call > > :: filter ; + self.filter = ::frame_support::sp_std::rc::Rc::new(Box::new(filter)); + } + fn set_caller_from(&mut self, other: impl Into) { + self.caller = other.into().caller + } + fn filter_call(&self, call: &Self::Call) -> bool { + (self.filter)(call) + } + fn caller(&self) -> &Self::PalletsOrigin { + &self.caller + } + /// Create with system none origin and `frame-system::Trait::BaseCallFilter`. + fn none() -> Self { + frame_system::RawOrigin::None.into() + } + /// Create with system root origin and no filter. + fn root() -> Self { + frame_system::RawOrigin::Root.into() + } + /// Create with system signed origin and `frame-system::Trait::BaseCallFilter`. + fn signed(by: ::AccountId) -> Self { + frame_system::RawOrigin::Signed(by).into() + } + } + #[allow(non_camel_case_types)] + pub enum OriginCaller { + system(frame_system::Origin), + #[allow(dead_code)] + Void(::frame_support::Void), + } + #[automatically_derived] + #[allow(unused_qualifications)] + #[allow(non_camel_case_types)] + impl ::core::clone::Clone for OriginCaller { + #[inline] + fn clone(&self) -> OriginCaller { + match (&*self,) { + (&OriginCaller::system(ref __self_0),) => { + OriginCaller::system(::core::clone::Clone::clone(&(*__self_0))) + } + (&OriginCaller::Void(ref __self_0),) => { + OriginCaller::Void(::core::clone::Clone::clone(&(*__self_0))) + } + } + } + } + #[allow(non_camel_case_types)] + impl ::core::marker::StructuralPartialEq for OriginCaller {} + #[automatically_derived] + #[allow(unused_qualifications)] + #[allow(non_camel_case_types)] + impl ::core::cmp::PartialEq for OriginCaller { + #[inline] + fn eq(&self, other: &OriginCaller) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &OriginCaller::system(ref __self_0), + &OriginCaller::system(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + ( + &OriginCaller::Void(ref __self_0), + &OriginCaller::Void(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => unsafe { ::core::intrinsics::unreachable() }, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &OriginCaller) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &OriginCaller::system(ref __self_0), + &OriginCaller::system(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + ( + &OriginCaller::Void(ref __self_0), + &OriginCaller::Void(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => unsafe { ::core::intrinsics::unreachable() }, + } + } else { + true + } + } + } + } + #[allow(non_camel_case_types)] + impl ::core::marker::StructuralEq for OriginCaller {} + #[automatically_derived] + #[allow(unused_qualifications)] + #[allow(non_camel_case_types)] + impl ::core::cmp::Eq for OriginCaller { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq<::frame_support::Void>; + } + } + } + impl core::fmt::Debug for OriginCaller { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::system(ref a0) => { + fmt.debug_tuple("OriginCaller::system").field(a0).finish() + } + Self::Void(ref a0) => fmt.debug_tuple("OriginCaller::Void").field(a0).finish(), + _ => Ok(()), + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for OriginCaller { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + OriginCaller::system(ref aa) => { + dest.push_byte(0usize as u8); + dest.push(aa); + } + OriginCaller::Void(ref aa) => { + dest.push_byte(1usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for OriginCaller {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for OriginCaller { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(OriginCaller::system({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err( + "Error decoding field OriginCaller :: system.0".into() + ) + } + Ok(a) => a, + } + })), + x if x == 1usize as u8 => Ok(OriginCaller::Void({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field OriginCaller :: Void.0".into()) + } + Ok(a) => a, + } + })), + x => Err("No such variant in enum OriginCaller".into()), + } + } + } + }; + #[allow(dead_code)] + impl Origin { + /// Create with system none origin and `frame-system::Trait::BaseCallFilter`. + pub fn none() -> Self { + ::none() + } + /// Create with system root origin and no filter. + pub fn root() -> Self { + ::root() + } + /// Create with system signed origin and `frame-system::Trait::BaseCallFilter`. + pub fn signed(by: ::AccountId) -> Self { + ::signed(by) + } + } + impl From> for OriginCaller { + fn from(x: frame_system::Origin) -> Self { + OriginCaller::system(x) + } + } + impl From> for Origin { + /// Convert to runtime origin: + /// * root origin is built with no filter + /// * others use `frame-system::Trait::BaseCallFilter` + fn from(x: frame_system::Origin) -> Self { + let o: OriginCaller = x.into(); + o.into() + } + } + impl From for Origin { + fn from(x: OriginCaller) -> Self { + let mut o = Origin { + caller: x, + filter: ::frame_support::sp_std::rc::Rc::new(Box::new(|_| true)), + }; + if !match o.caller { + OriginCaller::system(frame_system::Origin::::Root) => true, + _ => false, + } { + ::frame_support::traits::OriginTrait::reset_filter(&mut o); + } + o + } + } + impl Into<::frame_support::sp_std::result::Result, Origin>> + for Origin + { + /// NOTE: converting to pallet origin loses the origin filter information. + fn into( + self, + ) -> ::frame_support::sp_std::result::Result, Self> { + if let OriginCaller::system(l) = self.caller { + Ok(l) + } else { + Err(self) + } + } + } + impl From::AccountId>> for Origin { + /// Convert to runtime origin with caller being system signed or none and use filter + /// `frame-system::Trait::BaseCallFilter`. + fn from(x: Option<::AccountId>) -> Self { + >::from(x).into() + } + } + impl frame_system::Trait for Runtime { + type BaseCallFilter = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = (); + type MaximumBlockWeight = (); + type DbWeight = (); + type BlockExecutionWeight = (); + type ExtrinsicBaseWeight = (); + type MaximumExtrinsicWeight = (); + type MaximumBlockLength = (); + type AvailableBlockRatio = (); + type Version = (); + type PalletInfo = (); + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + } + pub struct ExistentialDeposit; + impl ExistentialDeposit { + /// Returns the value of this parameter type. + pub const fn get() -> u64 { + 1 + } + } + impl> ::frame_support::traits::Get for ExistentialDeposit { + fn get() -> I { + I::from(1) + } + } + impl pallet_balances::Trait for Runtime { + type Balance = Balance; + type Event = (); + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type MaxLocks = (); + type WeightInfo = (); + } + use paste::paste; + const SIGNED_PHASE: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(10) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const UNSIGNED_PHASE: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(5) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const MAX_SIGNED_SUBMISSIONS: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(5) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const TARGETS: ::std::thread::LocalKey>> = { + #[inline] + fn __init() -> RefCell> { + RefCell::new(<[_]>::into_vec(box [10, 20, 30, 40])) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell>> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner>> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const VOTERS: ::std::thread::LocalKey< + RefCell)>>, + > = { + #[inline] + fn __init() -> RefCell)>> { + RefCell::new(<[_]>::into_vec(box [ + (1, 10, <[_]>::into_vec(box [10, 20])), + (2, 10, <[_]>::into_vec(box [30, 40])), + (3, 10, <[_]>::into_vec(box [40])), + (4, 10, <[_]>::into_vec(box [10, 20, 30, 40])), + (10, 10, <[_]>::into_vec(box [10])), + (20, 20, <[_]>::into_vec(box [20])), + (30, 30, <[_]>::into_vec(box [30])), + (40, 40, <[_]>::into_vec(box [40])), + ])) + } + unsafe fn __getit( + ) -> ::std::option::Option<&'static RefCell)>>> + { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner< + RefCell)>>, + > = ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const DESIRED_TARGETS: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(2) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const SIGNED_DEPOSIT_BASE: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(5) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const SIGNED_REWARD_BASE: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(7) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + pub struct SignedPhase; + impl Get for SignedPhase { + fn get() -> u64 { + SIGNED_PHASE.with(|v| v.borrow().clone()) + } + } + pub struct UnsignedPhase; + impl Get for UnsignedPhase { + fn get() -> u64 { + UNSIGNED_PHASE.with(|v| v.borrow().clone()) + } + } + pub struct MaxSignedSubmissions; + impl Get for MaxSignedSubmissions { + fn get() -> u32 { + MAX_SIGNED_SUBMISSIONS.with(|v| v.borrow().clone()) + } + } + pub struct Targets; + impl Get> for Targets { + fn get() -> Vec { + TARGETS.with(|v| v.borrow().clone()) + } + } + pub struct Voters; + impl Get)>> for Voters { + fn get() -> Vec<(AccountId, VoteWeight, Vec)> { + VOTERS.with(|v| v.borrow().clone()) + } + } + pub struct DesiredTargets; + impl Get for DesiredTargets { + fn get() -> u32 { + DESIRED_TARGETS.with(|v| v.borrow().clone()) + } + } + pub struct SignedDepositBase; + impl Get for SignedDepositBase { + fn get() -> Balance { + SIGNED_DEPOSIT_BASE.with(|v| v.borrow().clone()) + } + } + pub struct SignedRewardBase; + impl Get for SignedRewardBase { + fn get() -> Balance { + SIGNED_REWARD_BASE.with(|v| v.borrow().clone()) + } + } + impl crate::ElectionDataProvider for ExtBuilder { + fn targets() -> Vec { + Targets::get() + } + fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { + Voters::get() + } + fn desired_targets() -> u32 { + DesiredTargets::get() + } + fn feasibility_check_assignment( + _: &AccountId, + _: &[(AccountId, P)], + ) -> bool { + true + } + fn next_election_prediction(now: u64) -> u64 { + now + 20 - now % 20 + } + } + impl crate::two_phase::Trait for Runtime { + type Event = (); + type Currency = Balances; + type SignedPhase = SignedPhase; + type UnsignedPhase = UnsignedPhase; + type MaxSignedSubmissions = MaxSignedSubmissions; + type SignedRewardBase = SignedRewardBase; + type SignedRewardFactor = (); + type SignedDepositBase = SignedDepositBase; + type SignedDepositByte = (); + type SignedDepositWeight = (); + type SolutionImprovementThreshold = (); + type SlashHandler = (); + type RewardHandler = (); + type ElectionDataProvider = ExtBuilder; + type WeightInfo = (); + } + pub struct ExtBuilder { + signed_phase: u64, + unsigned_phase: u64, + } + impl Default for ExtBuilder { + fn default() -> Self { + Self { + signed_phase: SignedPhase::get(), + unsigned_phase: UnsignedPhase::get(), + } + } + } + impl ExtBuilder { + fn set_constants(&self) {} + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.set_constants(); + let mut storage = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + let _ = pallet_balances::GenesisConfig:: { + balances: <[_]>::into_vec(box [(99, 100)]), + } + .assimilate_storage(&mut storage); + sp_io::TestExternalities::from(storage).execute_with(test) + } + } + } + pub mod signed { + use crate::two_phase::*; + use codec::Encode; + use sp_arithmetic::traits::SaturatedConversion; + use sp_npos_elections::is_score_better; + impl Module { + /// Start the signed phase. + /// + /// Upon calling this, auxillary data for election is stored and signed solutions will be + /// accepted. + /// + /// The signed phase must always start before the unsigned phase. + pub fn start_signed_phase() { + let targets = T::ElectionDataProvider::targets(); + let voters = T::ElectionDataProvider::voters(); + let desired_targets = T::ElectionDataProvider::desired_targets(); + >::put(targets); + >::put(voters); + DesiredTargets::put(desired_targets); + } + /// Finish the singed phase. + /// + /// Returns true if we have a good solution in the signed phase. + pub fn finalize_signed_phase() -> bool { + let mut all_submission: Vec> = + >::take(); + let mut found_solution = false; + while let Some(best) = all_submission.pop() { + let SignedSubmission { + solution, + who, + deposit, + reward, + } = best; + match Self::feasibility_check(solution) { + Ok(ready_solution) => { + >::put(ready_solution); + let _remaining = T::Currency::unreserve(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic( + "assertion failed: _remaining.is_zero()", + ) + } + }; + }; + let positive_imbalance = T::Currency::deposit_creating(&who, reward); + T::RewardHandler::on_unbalanced(positive_imbalance); + found_solution = true; + break; + } + Err(_) => { + let (negative_imbalance, _remaining) = + T::Currency::slash_reserved(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic( + "assertion failed: _remaining.is_zero()", + ) + } + }; + }; + T::SlashHandler::on_unbalanced(negative_imbalance); + } + } + } + all_submission.into_iter().for_each(|not_processed| { + let SignedSubmission { who, deposit, .. } = not_processed; + let _remaining = T::Currency::unreserve(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic("assertion failed: _remaining.is_zero()") + } + }; + }; + }); + found_solution + } + /// Find a proper position in the queue for the signed queue, whilst maintaining the order of + /// solution quality. + pub fn insert_submission( + who: &T::AccountId, + queue: &mut Vec>>, + solution: RawSolution, + ) -> Option { + let outcome = queue + .iter() + .enumerate() + .rev() + .find_map(|(i, s)| { + if is_score_better( + solution.score, + s.solution.score, + T::SolutionImprovementThreshold::get(), + ) { + Some(i + 1) + } else { + None + } + }) + .or(Some(0)) + .and_then(|at| { + if at == 0 && queue.len() as u32 >= T::MaxSignedSubmissions::get() { + None + } else { + let reward = Self::reward_for(&solution); + let deposit = Self::deposit_for(&solution); + let submission = SignedSubmission { + who: who.clone(), + deposit, + reward, + solution, + }; + queue.insert(at, submission); + if queue.len() as u32 >= T::MaxSignedSubmissions::get() { + queue.remove(0); + Some(at - 1) + } else { + Some(at) + } + } + }); + if true { + if !(queue.len() as u32 <= T::MaxSignedSubmissions::get()) { + { + :: std :: rt :: begin_panic ( "assertion failed: queue.len() as u32 <= T::MaxSignedSubmissions::get()" ) + } + }; + }; + outcome + } + pub fn deposit_for(solution: &RawSolution) -> BalanceOf { + let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); + T::SignedDepositBase::get() + T::SignedDepositByte::get() * encoded_len + } + pub fn reward_for(solution: &RawSolution) -> BalanceOf { + T::SignedRewardBase::get() + + T::SignedRewardFactor::get() + * solution.score[0].saturated_into::>() + } + } + #[cfg(test)] + mod tests { + use super::{mock::*, *}; + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const cannot_submit_too_early: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::signed::tests::cannot_submit_too_early"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(cannot_submit_too_early())), + }; + fn cannot_submit_too_early() { + ExtBuilder::default().build_and_execute(|| { + roll_to(2); + { + match (&TwoPhase::current_phase(), &Phase::Off) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + TwoPhase::start_signed_phase(); + let solution = raw_solution(); + let h = ::frame_support::storage_root(); + { + match ( + &TwoPhase::submit(Origin::signed(10), solution), + &Err(PalletError::::EarlySubmission.into()), + ) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&h, &::frame_support::storage_root()) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const should_pay_deposit: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::signed::tests::should_pay_deposit"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(should_pay_deposit())), + }; + fn should_pay_deposit() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let solution = raw_solution(); + { + match (&balances(&99), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + { + match (&balances(&99), &(95, 5)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&TwoPhase::signed_submissions().first().unwrap().deposit, &5) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const good_solution_is_rewarded: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::good_solution_is_rewarded", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn( + || test::assert_test_result(good_solution_is_rewarded()), + ), + }; + fn good_solution_is_rewarded() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let mut solution = raw_solution(); + { + match (&balances(&99), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + { + match (&balances(&99), &(95, 5)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::finalize_signed_phase() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::finalize_signed_phase()", + ) + } + }; + { + match (&balances(&99), &(100 + 7, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const bad_solution_is_slashed: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::signed::tests::bad_solution_is_slashed"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(bad_solution_is_slashed())), + }; + fn bad_solution_is_slashed() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let mut solution = raw_solution(); + { + match (&balances(&99), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + solution.score[0] += 1; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + { + match (&balances(&99), &(95, 5)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !!TwoPhase::finalize_signed_phase() { + { + ::std::rt::begin_panic( + "assertion failed: !TwoPhase::finalize_signed_phase()", + ) + } + }; + { + match (&balances(&99), &(95, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const queue_is_always_sorted: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::signed::tests::queue_is_always_sorted"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(queue_is_always_sorted())), + }; + fn queue_is_always_sorted() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let solution = RawSolution { + winners: <[_]>::into_vec(box [1u16]), + score: [5, 0, 0], + ..Default::default() + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + let solution = RawSolution { + winners: <[_]>::into_vec(box [2u16]), + score: [4, 0, 0], + ..Default::default() + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + let solution = RawSolution { + winners: <[_]>::into_vec(box [3u16]), + score: [6, 0, 0], + ..Default::default() + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + { + match ( + &TwoPhase::signed_submissions() + .iter() + .map(|x| x.solution.winners[0]) + .collect::>(), + &<[_]>::into_vec(box [2, 1, 3]), + ) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const can_submit_until_queue_full: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::can_submit_until_queue_full", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(can_submit_until_queue_full()) + }), + }; + fn can_submit_until_queue_full() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + for s in 0..MaxSignedSubmissions::get() { + let solution = RawSolution { + winners: <[_]>::into_vec(box [1u16]), + score: [(5 + s).into(), 0, 0], + ..Default::default() + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: + ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: + ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + } + let solution = RawSolution { + winners: <[_]>::into_vec(box [1u16]), + score: [4, 0, 0], + ..Default::default() + }; + let h = ::frame_support::storage_root(); + { + match ( + &TwoPhase::submit(Origin::signed(99), solution), + &Err(PalletError::::QueueFull.into()), + ) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&h, &::frame_support::storage_root()) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const weakest_is_removed_if_better_provided: test::TestDescAndFn = + test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::weakest_is_removed_if_better_provided", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(weakest_is_removed_if_better_provided()) + }), + }; + fn weakest_is_removed_if_better_provided() {} + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const cannot_submit_worse_with_full_queue: test::TestDescAndFn = + test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::cannot_submit_worse_with_full_queue", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(cannot_submit_worse_with_full_queue()) + }), + }; + fn cannot_submit_worse_with_full_queue() {} + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const suppressed_solution_gets_bond_back: test::TestDescAndFn = + test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::suppressed_solution_gets_bond_back", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(suppressed_solution_gets_bond_back()) + }), + }; + fn suppressed_solution_gets_bond_back() {} + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const solutions_are_sorted: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::signed::tests::solutions_are_sorted"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(solutions_are_sorted())), + }; + fn solutions_are_sorted() {} + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const all_in_one_singed_submission: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::all_in_one_singed_submission", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(all_in_one_singed_submission()) + }), + }; + fn all_in_one_singed_submission() {} + } + } + pub mod unsigned {} + type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + type PositiveImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::PositiveImbalance; + type NegativeImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::NegativeImbalance; + /// Accuracy used for on-chain election. + pub type ChainAccuracy = Perbill; + /// Accuracy used for off-chain election. This better be small. + pub type OffchainAccuracy = PerU16; + /// Data type used to index nominators in the compact type. + pub type VoterIndex = u32; + /// Data type used to index validators in the compact type. + pub type TargetIndex = u16; + #[allow(unknown_lints, eq_op)] + const _: [(); 0 - !{ + const ASSERT: bool = size_of::() <= size_of::(); + ASSERT + } as usize] = []; + #[allow(unknown_lints, eq_op)] + const _: [(); 0 - !{ + const ASSERT: bool = size_of::() <= size_of::(); + ASSERT + } as usize] = []; + #[allow(unknown_lints, eq_op)] + const _: [(); 0 - !{ + const ASSERT: bool = size_of::() <= size_of::(); + ASSERT + } as usize] = []; + #[allow(unknown_lints, eq_op)] + const _: [(); 0 - !{ + const ASSERT: bool = size_of::() <= size_of::(); + ASSERT + } as usize] = []; + extern crate sp_npos_elections as _npos; + /// A struct to encode a election assignment in a compact way. + impl _npos::codec::Encode for CompactAssignments { + fn encode(&self) -> Vec { + let mut r = ::alloc::vec::Vec::new(); + let votes1 = self + .votes1 + .iter() + .map(|(v, t)| { + ( + _npos::codec::Compact(v.clone()), + _npos::codec::Compact(t.clone()), + ) + }) + .collect::>(); + votes1.encode_to(&mut r); + let votes2 = self + .votes2 + .iter() + .map(|(v, (t1, w), t2)| { + ( + _npos::codec::Compact(v.clone()), + ( + _npos::codec::Compact(t1.clone()), + _npos::codec::Compact(w.clone()), + ), + _npos::codec::Compact(t2.clone()), + ) + }) + .collect::>(); + votes2.encode_to(&mut r); + let votes3 = self + .votes3 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes3.encode_to(&mut r); + let votes4 = self + .votes4 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes4.encode_to(&mut r); + let votes5 = self + .votes5 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes5.encode_to(&mut r); + let votes6 = self + .votes6 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes6.encode_to(&mut r); + let votes7 = self + .votes7 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes7.encode_to(&mut r); + let votes8 = self + .votes8 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes8.encode_to(&mut r); + let votes9 = self + .votes9 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes9.encode_to(&mut r); + let votes10 = self + .votes10 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes10.encode_to(&mut r); + let votes11 = self + .votes11 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes11.encode_to(&mut r); + let votes12 = self + .votes12 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes12.encode_to(&mut r); + let votes13 = self + .votes13 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes13.encode_to(&mut r); + let votes14 = self + .votes14 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[12usize].0.clone()), + _npos::codec::Compact(inner[12usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes14.encode_to(&mut r); + let votes15 = self + .votes15 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[12usize].0.clone()), + _npos::codec::Compact(inner[12usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[13usize].0.clone()), + _npos::codec::Compact(inner[13usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes15.encode_to(&mut r); + let votes16 = self + .votes16 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[12usize].0.clone()), + _npos::codec::Compact(inner[12usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[13usize].0.clone()), + _npos::codec::Compact(inner[13usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[14usize].0.clone()), + _npos::codec::Compact(inner[14usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes16.encode_to(&mut r); + r + } + } + impl _npos::codec::Decode for CompactAssignments { + fn decode(value: &mut I) -> Result { + let votes1 = , + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes1 = votes1 + .into_iter() + .map(|(v, t)| (v.0, t.0)) + .collect::>(); + let votes2 = , + ( + _npos::codec::Compact, + _npos::codec::Compact, + ), + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes2 = votes2 + .into_iter() + .map(|(v, (t1, w), t2)| (v.0, (t1.0, w.0), t2.0)) + .collect::>(); + let votes3 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 3usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes3 = votes3 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes4 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 4usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes4 = votes4 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes5 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 5usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes5 = votes5 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes6 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 6usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes6 = votes6 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes7 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 7usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes7 = votes7 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes8 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 8usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes8 = votes8 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes9 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 9usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes9 = votes9 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes10 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 10usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes10 = votes10 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes11 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 11usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes11 = votes11 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes12 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 12usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes12 = votes12 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes13 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 13usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes13 = votes13 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes14 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 14usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes14 = votes14 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ((inner[12usize].0).0, (inner[12usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes15 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 15usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes15 = votes15 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ((inner[12usize].0).0, (inner[12usize].1).0), + ((inner[13usize].0).0, (inner[13usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes16 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 16usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes16 = votes16 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ((inner[12usize].0).0, (inner[12usize].1).0), + ((inner[13usize].0).0, (inner[13usize].1).0), + ((inner[14usize].0).0, (inner[14usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + Ok(CompactAssignments { + votes1, + votes2, + votes3, + votes4, + votes5, + votes6, + votes7, + votes8, + votes9, + votes10, + votes11, + votes12, + votes13, + votes14, + votes15, + votes16, + }) + } + } + pub struct CompactAssignments { + votes1: Vec<(VoterIndex, TargetIndex)>, + votes2: Vec<(VoterIndex, (TargetIndex, OffchainAccuracy), TargetIndex)>, + votes3: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 2usize], + TargetIndex, + )>, + votes4: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 3usize], + TargetIndex, + )>, + votes5: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 4usize], + TargetIndex, + )>, + votes6: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 5usize], + TargetIndex, + )>, + votes7: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 6usize], + TargetIndex, + )>, + votes8: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 7usize], + TargetIndex, + )>, + votes9: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 8usize], + TargetIndex, + )>, + votes10: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 9usize], + TargetIndex, + )>, + votes11: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 10usize], + TargetIndex, + )>, + votes12: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 11usize], + TargetIndex, + )>, + votes13: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 12usize], + TargetIndex, + )>, + votes14: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 13usize], + TargetIndex, + )>, + votes15: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 14usize], + TargetIndex, + )>, + votes16: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 15usize], + TargetIndex, + )>, + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for CompactAssignments { + #[inline] + fn default() -> CompactAssignments { + CompactAssignments { + votes1: ::core::default::Default::default(), + votes2: ::core::default::Default::default(), + votes3: ::core::default::Default::default(), + votes4: ::core::default::Default::default(), + votes5: ::core::default::Default::default(), + votes6: ::core::default::Default::default(), + votes7: ::core::default::Default::default(), + votes8: ::core::default::Default::default(), + votes9: ::core::default::Default::default(), + votes10: ::core::default::Default::default(), + votes11: ::core::default::Default::default(), + votes12: ::core::default::Default::default(), + votes13: ::core::default::Default::default(), + votes14: ::core::default::Default::default(), + votes15: ::core::default::Default::default(), + votes16: ::core::default::Default::default(), + } + } + } + impl ::core::marker::StructuralPartialEq for CompactAssignments {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for CompactAssignments { + #[inline] + fn eq(&self, other: &CompactAssignments) -> bool { + match *other { + CompactAssignments { + votes1: ref __self_1_0, + votes2: ref __self_1_1, + votes3: ref __self_1_2, + votes4: ref __self_1_3, + votes5: ref __self_1_4, + votes6: ref __self_1_5, + votes7: ref __self_1_6, + votes8: ref __self_1_7, + votes9: ref __self_1_8, + votes10: ref __self_1_9, + votes11: ref __self_1_10, + votes12: ref __self_1_11, + votes13: ref __self_1_12, + votes14: ref __self_1_13, + votes15: ref __self_1_14, + votes16: ref __self_1_15, + } => match *self { + CompactAssignments { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + && (*__self_0_3) == (*__self_1_3) + && (*__self_0_4) == (*__self_1_4) + && (*__self_0_5) == (*__self_1_5) + && (*__self_0_6) == (*__self_1_6) + && (*__self_0_7) == (*__self_1_7) + && (*__self_0_8) == (*__self_1_8) + && (*__self_0_9) == (*__self_1_9) + && (*__self_0_10) == (*__self_1_10) + && (*__self_0_11) == (*__self_1_11) + && (*__self_0_12) == (*__self_1_12) + && (*__self_0_13) == (*__self_1_13) + && (*__self_0_14) == (*__self_1_14) + && (*__self_0_15) == (*__self_1_15) + } + }, + } + } + #[inline] + fn ne(&self, other: &CompactAssignments) -> bool { + match *other { + CompactAssignments { + votes1: ref __self_1_0, + votes2: ref __self_1_1, + votes3: ref __self_1_2, + votes4: ref __self_1_3, + votes5: ref __self_1_4, + votes6: ref __self_1_5, + votes7: ref __self_1_6, + votes8: ref __self_1_7, + votes9: ref __self_1_8, + votes10: ref __self_1_9, + votes11: ref __self_1_10, + votes12: ref __self_1_11, + votes13: ref __self_1_12, + votes14: ref __self_1_13, + votes15: ref __self_1_14, + votes16: ref __self_1_15, + } => match *self { + CompactAssignments { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) + || (*__self_0_2) != (*__self_1_2) + || (*__self_0_3) != (*__self_1_3) + || (*__self_0_4) != (*__self_1_4) + || (*__self_0_5) != (*__self_1_5) + || (*__self_0_6) != (*__self_1_6) + || (*__self_0_7) != (*__self_1_7) + || (*__self_0_8) != (*__self_1_8) + || (*__self_0_9) != (*__self_1_9) + || (*__self_0_10) != (*__self_1_10) + || (*__self_0_11) != (*__self_1_11) + || (*__self_0_12) != (*__self_1_12) + || (*__self_0_13) != (*__self_1_13) + || (*__self_0_14) != (*__self_1_14) + || (*__self_0_15) != (*__self_1_15) + } + }, + } + } + } + impl ::core::marker::StructuralEq for CompactAssignments {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for CompactAssignments { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq< + Vec<(VoterIndex, (TargetIndex, OffchainAccuracy), TargetIndex)>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 2usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 3usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 4usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 5usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 6usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 7usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 8usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 9usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 10usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 11usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 12usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 13usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 14usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 15usize], + TargetIndex, + )>, + >; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for CompactAssignments { + #[inline] + fn clone(&self) -> CompactAssignments { + match *self { + CompactAssignments { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => CompactAssignments { + votes1: ::core::clone::Clone::clone(&(*__self_0_0)), + votes2: ::core::clone::Clone::clone(&(*__self_0_1)), + votes3: ::core::clone::Clone::clone(&(*__self_0_2)), + votes4: ::core::clone::Clone::clone(&(*__self_0_3)), + votes5: ::core::clone::Clone::clone(&(*__self_0_4)), + votes6: ::core::clone::Clone::clone(&(*__self_0_5)), + votes7: ::core::clone::Clone::clone(&(*__self_0_6)), + votes8: ::core::clone::Clone::clone(&(*__self_0_7)), + votes9: ::core::clone::Clone::clone(&(*__self_0_8)), + votes10: ::core::clone::Clone::clone(&(*__self_0_9)), + votes11: ::core::clone::Clone::clone(&(*__self_0_10)), + votes12: ::core::clone::Clone::clone(&(*__self_0_11)), + votes13: ::core::clone::Clone::clone(&(*__self_0_12)), + votes14: ::core::clone::Clone::clone(&(*__self_0_13)), + votes15: ::core::clone::Clone::clone(&(*__self_0_14)), + votes16: ::core::clone::Clone::clone(&(*__self_0_15)), + }, + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::fmt::Debug for CompactAssignments { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match *self { + CompactAssignments { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => { + let mut debug_trait_builder = f.debug_struct("CompactAssignments"); + let _ = debug_trait_builder.field("votes1", &&(*__self_0_0)); + let _ = debug_trait_builder.field("votes2", &&(*__self_0_1)); + let _ = debug_trait_builder.field("votes3", &&(*__self_0_2)); + let _ = debug_trait_builder.field("votes4", &&(*__self_0_3)); + let _ = debug_trait_builder.field("votes5", &&(*__self_0_4)); + let _ = debug_trait_builder.field("votes6", &&(*__self_0_5)); + let _ = debug_trait_builder.field("votes7", &&(*__self_0_6)); + let _ = debug_trait_builder.field("votes8", &&(*__self_0_7)); + let _ = debug_trait_builder.field("votes9", &&(*__self_0_8)); + let _ = debug_trait_builder.field("votes10", &&(*__self_0_9)); + let _ = debug_trait_builder.field("votes11", &&(*__self_0_10)); + let _ = debug_trait_builder.field("votes12", &&(*__self_0_11)); + let _ = debug_trait_builder.field("votes13", &&(*__self_0_12)); + let _ = debug_trait_builder.field("votes14", &&(*__self_0_13)); + let _ = debug_trait_builder.field("votes15", &&(*__self_0_14)); + let _ = debug_trait_builder.field("votes16", &&(*__self_0_15)); + debug_trait_builder.finish() + } + } + } + } + impl _npos::VotingLimit for CompactAssignments { + const LIMIT: usize = 16usize; + } + impl CompactAssignments { + /// Get the length of all the assignments that this type is encoding. This is basically + /// the same as the number of assignments, or the number of voters in total. + pub fn len(&self) -> usize { + let mut all_len = 0usize; + all_len = all_len.saturating_add(self.votes1.len()); + all_len = all_len.saturating_add(self.votes2.len()); + all_len = all_len.saturating_add(self.votes3.len()); + all_len = all_len.saturating_add(self.votes4.len()); + all_len = all_len.saturating_add(self.votes5.len()); + all_len = all_len.saturating_add(self.votes6.len()); + all_len = all_len.saturating_add(self.votes7.len()); + all_len = all_len.saturating_add(self.votes8.len()); + all_len = all_len.saturating_add(self.votes9.len()); + all_len = all_len.saturating_add(self.votes10.len()); + all_len = all_len.saturating_add(self.votes11.len()); + all_len = all_len.saturating_add(self.votes12.len()); + all_len = all_len.saturating_add(self.votes13.len()); + all_len = all_len.saturating_add(self.votes14.len()); + all_len = all_len.saturating_add(self.votes15.len()); + all_len = all_len.saturating_add(self.votes16.len()); + all_len + } + /// Get the total count of edges. + pub fn edge_count(&self) -> usize { + let mut all_edges = 0usize; + all_edges = all_edges.saturating_add(self.votes1.len().saturating_mul(1usize as usize)); + all_edges = all_edges.saturating_add(self.votes2.len().saturating_mul(2usize as usize)); + all_edges = all_edges.saturating_add(self.votes3.len().saturating_mul(3usize as usize)); + all_edges = all_edges.saturating_add(self.votes4.len().saturating_mul(4usize as usize)); + all_edges = all_edges.saturating_add(self.votes5.len().saturating_mul(5usize as usize)); + all_edges = all_edges.saturating_add(self.votes6.len().saturating_mul(6usize as usize)); + all_edges = all_edges.saturating_add(self.votes7.len().saturating_mul(7usize as usize)); + all_edges = all_edges.saturating_add(self.votes8.len().saturating_mul(8usize as usize)); + all_edges = all_edges.saturating_add(self.votes9.len().saturating_mul(9usize as usize)); + all_edges = + all_edges.saturating_add(self.votes10.len().saturating_mul(10usize as usize)); + all_edges = + all_edges.saturating_add(self.votes11.len().saturating_mul(11usize as usize)); + all_edges = + all_edges.saturating_add(self.votes12.len().saturating_mul(12usize as usize)); + all_edges = + all_edges.saturating_add(self.votes13.len().saturating_mul(13usize as usize)); + all_edges = + all_edges.saturating_add(self.votes14.len().saturating_mul(14usize as usize)); + all_edges = + all_edges.saturating_add(self.votes15.len().saturating_mul(15usize as usize)); + all_edges = + all_edges.saturating_add(self.votes16.len().saturating_mul(16usize as usize)); + all_edges + } + /// 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. + /// + /// The resulting indices are sorted. + pub fn unique_targets(&self) -> Vec { + let mut all_targets: Vec = Vec::with_capacity(self.average_edge_count()); + let mut maybe_insert_target = |t: TargetIndex| match all_targets.binary_search(&t) { + Ok(_) => (), + Err(pos) => all_targets.insert(pos, t), + }; + self.votes1.iter().for_each(|(_, t)| { + maybe_insert_target(*t); + }); + self.votes2.iter().for_each(|(_, (t1, _), t2)| { + maybe_insert_target(*t1); + maybe_insert_target(*t2); + }); + self.votes3.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes4.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes5.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes6.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes7.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes8.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes9.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes10.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes11.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes12.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes13.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes14.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes15.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes16.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + all_targets + } + /// Get the average edge count. + pub fn average_edge_count(&self) -> usize { + self.edge_count().checked_div(self.len()).unwrap_or(0) + } + /// 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 from + /// `self.len()`. + pub fn remove_voter(&mut self, to_remove: VoterIndex) -> bool { + if let Some(idx) = self.votes1.iter().position(|(x, _)| *x == to_remove) { + self.votes1.remove(idx); + return true; + } + if let Some(idx) = self.votes2.iter().position(|(x, _, _)| *x == to_remove) { + self.votes2.remove(idx); + return true; + } + if let Some(idx) = self.votes3.iter().position(|(x, _, _)| *x == to_remove) { + self.votes3.remove(idx); + return true; + } + if let Some(idx) = self.votes4.iter().position(|(x, _, _)| *x == to_remove) { + self.votes4.remove(idx); + return true; + } + if let Some(idx) = self.votes5.iter().position(|(x, _, _)| *x == to_remove) { + self.votes5.remove(idx); + return true; + } + if let Some(idx) = self.votes6.iter().position(|(x, _, _)| *x == to_remove) { + self.votes6.remove(idx); + return true; + } + if let Some(idx) = self.votes7.iter().position(|(x, _, _)| *x == to_remove) { + self.votes7.remove(idx); + return true; + } + if let Some(idx) = self.votes8.iter().position(|(x, _, _)| *x == to_remove) { + self.votes8.remove(idx); + return true; + } + if let Some(idx) = self.votes9.iter().position(|(x, _, _)| *x == to_remove) { + self.votes9.remove(idx); + return true; + } + if let Some(idx) = self.votes10.iter().position(|(x, _, _)| *x == to_remove) { + self.votes10.remove(idx); + return true; + } + if let Some(idx) = self.votes11.iter().position(|(x, _, _)| *x == to_remove) { + self.votes11.remove(idx); + return true; + } + if let Some(idx) = self.votes12.iter().position(|(x, _, _)| *x == to_remove) { + self.votes12.remove(idx); + return true; + } + if let Some(idx) = self.votes13.iter().position(|(x, _, _)| *x == to_remove) { + self.votes13.remove(idx); + return true; + } + if let Some(idx) = self.votes14.iter().position(|(x, _, _)| *x == to_remove) { + self.votes14.remove(idx); + return true; + } + if let Some(idx) = self.votes15.iter().position(|(x, _, _)| *x == to_remove) { + self.votes15.remove(idx); + return true; + } + if let Some(idx) = self.votes16.iter().position(|(x, _, _)| *x == to_remove) { + self.votes16.remove(idx); + return true; + } + return false; + } + } + use _npos::__OrInvalidIndex; + impl CompactAssignments { + pub fn from_assignment( + assignments: Vec<_npos::Assignment>, + index_of_voter: FV, + index_of_target: FT, + ) -> Result + where + A: _npos::IdentifierT, + for<'r> FV: Fn(&'r A) -> Option, + for<'r> FT: Fn(&'r A) -> Option, + { + let mut compact: CompactAssignments = Default::default(); + for _npos::Assignment { who, distribution } in assignments { + match distribution.len() { + 0 => continue, + 1 => compact.votes1.push(( + index_of_voter(&who).or_invalid_index()?, + index_of_target(&distribution[0].0).or_invalid_index()?, + )), + 2 => compact.votes2.push(( + index_of_voter(&who).or_invalid_index()?, + ( + index_of_target(&distribution[0].0).or_invalid_index()?, + distribution[0].1, + ), + index_of_target(&distribution[1].0).or_invalid_index()?, + )), + 3usize => compact.votes3.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ], + index_of_target(&distribution[2usize].0).or_invalid_index()?, + )), + 4usize => compact.votes4.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ], + index_of_target(&distribution[3usize].0).or_invalid_index()?, + )), + 5usize => compact.votes5.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ], + index_of_target(&distribution[4usize].0).or_invalid_index()?, + )), + 6usize => compact.votes6.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ], + index_of_target(&distribution[5usize].0).or_invalid_index()?, + )), + 7usize => compact.votes7.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ], + index_of_target(&distribution[6usize].0).or_invalid_index()?, + )), + 8usize => compact.votes8.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ], + index_of_target(&distribution[7usize].0).or_invalid_index()?, + )), + 9usize => compact.votes9.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ], + index_of_target(&distribution[8usize].0).or_invalid_index()?, + )), + 10usize => compact.votes10.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ], + index_of_target(&distribution[9usize].0).or_invalid_index()?, + )), + 11usize => compact.votes11.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ], + index_of_target(&distribution[10usize].0).or_invalid_index()?, + )), + 12usize => compact.votes12.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ], + index_of_target(&distribution[11usize].0).or_invalid_index()?, + )), + 13usize => compact.votes13.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ], + index_of_target(&distribution[12usize].0).or_invalid_index()?, + )), + 14usize => compact.votes14.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ( + index_of_target(&distribution[12usize].0).or_invalid_index()?, + distribution[12usize].1, + ), + ], + index_of_target(&distribution[13usize].0).or_invalid_index()?, + )), + 15usize => compact.votes15.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ( + index_of_target(&distribution[12usize].0).or_invalid_index()?, + distribution[12usize].1, + ), + ( + index_of_target(&distribution[13usize].0).or_invalid_index()?, + distribution[13usize].1, + ), + ], + index_of_target(&distribution[14usize].0).or_invalid_index()?, + )), + 16usize => compact.votes16.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ( + index_of_target(&distribution[12usize].0).or_invalid_index()?, + distribution[12usize].1, + ), + ( + index_of_target(&distribution[13usize].0).or_invalid_index()?, + distribution[13usize].1, + ), + ( + index_of_target(&distribution[14usize].0).or_invalid_index()?, + distribution[14usize].1, + ), + ], + index_of_target(&distribution[15usize].0).or_invalid_index()?, + )), + _ => { + return Err(_npos::Error::CompactTargetOverflow); + } + } + } + Ok(compact) + } + pub fn into_assignment( + self, + voter_at: impl Fn(VoterIndex) -> Option, + target_at: impl Fn(TargetIndex) -> Option, + ) -> Result>, _npos::Error> { + let mut assignments: Vec<_npos::Assignment> = Default::default(); + for (voter_index, target_index) in self.votes1 { + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: <[_]>::into_vec(box [( + target_at(target_index).or_invalid_index()?, + OffchainAccuracy::one(), + )]), + }) + } + for (voter_index, (t1_idx, p1), t2_idx) in self.votes2 { + if p1 >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p2 = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + p1, + ); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: <[_]>::into_vec(box [ + (target_at(t1_idx).or_invalid_index()?, p1), + (target_at(t2_idx).or_invalid_index()?, p2), + ]), + }); + } + for (voter_index, inners, t_last_idx) in self.votes3 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes4 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes5 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes6 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes7 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes8 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes9 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes10 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes11 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes12 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes13 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes14 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes15 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes16 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + Ok(assignments) + } + } + pub enum Phase { + Off, + Signed, + Unsigned(bool), + } + impl ::core::marker::StructuralPartialEq for Phase {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Phase { + #[inline] + fn eq(&self, other: &Phase) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &Phase) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + _ => false, + } + } else { + true + } + } + } + } + impl ::core::marker::StructuralEq for Phase {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Phase { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Phase { + #[inline] + fn clone(&self) -> Phase { + { + let _: ::core::clone::AssertParamIsClone; + *self + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for Phase {} + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for Phase { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + Phase::Off => { + dest.push_byte(0usize as u8); + } + Phase::Signed => { + dest.push_byte(1usize as u8); + } + Phase::Unsigned(ref aa) => { + dest.push_byte(2usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for Phase {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for Phase { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(Phase::Off), + x if x == 1usize as u8 => Ok(Phase::Signed), + x if x == 2usize as u8 => Ok(Phase::Unsigned({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field Phase :: Unsigned.0".into()), + Ok(a) => a, + } + })), + x => Err("No such variant in enum Phase".into()), + } + } + } + }; + impl core::fmt::Debug for Phase { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::Off => fmt.debug_tuple("Phase::Off").finish(), + Self::Signed => fmt.debug_tuple("Phase::Signed").finish(), + Self::Unsigned(ref a0) => fmt.debug_tuple("Phase::Unsigned").field(a0).finish(), + _ => Ok(()), + } + } + } + impl Default for Phase { + fn default() -> Self { + Phase::Off + } + } + impl Phase { + pub fn is_signed(&self) -> bool { + match self { + Phase::Signed => true, + _ => false, + } + } + pub fn is_unsigned(&self) -> bool { + match self { + Phase::Unsigned(_) => true, + _ => false, + } + } + pub fn is_unsigned_open(&self) -> bool { + match self { + Phase::Unsigned(true) => true, + _ => false, + } + } + pub fn is_off(&self) -> bool { + match self { + Phase::Off => true, + _ => false, + } + } + } + pub enum ElectionCompute { + OnChain, + Signed, + Unsigned, + } + impl ::core::marker::StructuralPartialEq for ElectionCompute {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for ElectionCompute { + #[inline] + fn eq(&self, other: &ElectionCompute) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + _ => true, + } + } else { + false + } + } + } + } + impl ::core::marker::StructuralEq for ElectionCompute {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for ElectionCompute { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + {} + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for ElectionCompute { + #[inline] + fn clone(&self) -> ElectionCompute { + { + *self + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for ElectionCompute {} + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for ElectionCompute { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + ElectionCompute::OnChain => { + dest.push_byte(0usize as u8); + } + ElectionCompute::Signed => { + dest.push_byte(1usize as u8); + } + ElectionCompute::Unsigned => { + dest.push_byte(2usize as u8); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for ElectionCompute {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for ElectionCompute { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(ElectionCompute::OnChain), + x if x == 1usize as u8 => Ok(ElectionCompute::Signed), + x if x == 2usize as u8 => Ok(ElectionCompute::Unsigned), + x => Err("No such variant in enum ElectionCompute".into()), + } + } + } + }; + impl core::fmt::Debug for ElectionCompute { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::OnChain => fmt.debug_tuple("ElectionCompute::OnChain").finish(), + Self::Signed => fmt.debug_tuple("ElectionCompute::Signed").finish(), + Self::Unsigned => fmt.debug_tuple("ElectionCompute::Unsigned").finish(), + _ => Ok(()), + } + } + } + pub struct RawSolution { + winners: Vec, + compact: CompactAssignments, + score: ElectionScore, + } + impl ::core::marker::StructuralPartialEq for RawSolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for RawSolution { + #[inline] + fn eq(&self, other: &RawSolution) -> bool { + match *other { + RawSolution { + winners: ref __self_1_0, + compact: ref __self_1_1, + score: ref __self_1_2, + } => match *self { + RawSolution { + winners: ref __self_0_0, + compact: ref __self_0_1, + score: ref __self_0_2, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + } + }, + } + } + #[inline] + fn ne(&self, other: &RawSolution) -> bool { + match *other { + RawSolution { + winners: ref __self_1_0, + compact: ref __self_1_1, + score: ref __self_1_2, + } => match *self { + RawSolution { + winners: ref __self_0_0, + compact: ref __self_0_1, + score: ref __self_0_2, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) + || (*__self_0_2) != (*__self_1_2) + } + }, + } + } + } + impl ::core::marker::StructuralEq for RawSolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for RawSolution { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for RawSolution { + #[inline] + fn clone(&self) -> RawSolution { + match *self { + RawSolution { + winners: ref __self_0_0, + compact: ref __self_0_1, + score: ref __self_0_2, + } => RawSolution { + winners: ::core::clone::Clone::clone(&(*__self_0_0)), + compact: ::core::clone::Clone::clone(&(*__self_0_1)), + score: ::core::clone::Clone::clone(&(*__self_0_2)), + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for RawSolution { + fn encode_to(&self, dest: &mut EncOut) { + dest.push(&self.winners); + dest.push(&self.compact); + dest.push(&self.score); + } + } + impl _parity_scale_codec::EncodeLike for RawSolution {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for RawSolution { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(RawSolution { + winners: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field RawSolution.winners".into()), + Ok(a) => a, + } + }, + compact: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field RawSolution.compact".into()), + Ok(a) => a, + } + }, + score: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field RawSolution.score".into()), + Ok(a) => a, + } + }, + }) + } + } + }; + impl core::fmt::Debug for RawSolution { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("RawSolution") + .field("winners", &self.winners) + .field("compact", &self.compact) + .field("score", &self.score) + .finish() + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for RawSolution { + #[inline] + fn default() -> RawSolution { + RawSolution { + winners: ::core::default::Default::default(), + compact: ::core::default::Default::default(), + score: ::core::default::Default::default(), + } + } + } + pub struct SignedSubmission { + who: AccountId, + deposit: Balance, + reward: Balance, + solution: RawSolution, + } + impl ::core::marker::StructuralPartialEq + for SignedSubmission + { + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl + ::core::cmp::PartialEq for SignedSubmission + { + #[inline] + fn eq(&self, other: &SignedSubmission) -> bool { + match *other { + SignedSubmission { + who: ref __self_1_0, + deposit: ref __self_1_1, + reward: ref __self_1_2, + solution: ref __self_1_3, + } => match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + && (*__self_0_3) == (*__self_1_3) + } + }, + } + } + #[inline] + fn ne(&self, other: &SignedSubmission) -> bool { + match *other { + SignedSubmission { + who: ref __self_1_0, + deposit: ref __self_1_1, + reward: ref __self_1_2, + solution: ref __self_1_3, + } => match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) + || (*__self_0_2) != (*__self_1_2) + || (*__self_0_3) != (*__self_1_3) + } + }, + } + } + } + impl ::core::marker::StructuralEq + for SignedSubmission + { + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq + for SignedSubmission + { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl + ::core::clone::Clone for SignedSubmission + { + #[inline] + fn clone(&self) -> SignedSubmission { + match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => SignedSubmission { + who: ::core::clone::Clone::clone(&(*__self_0_0)), + deposit: ::core::clone::Clone::clone(&(*__self_0_1)), + reward: ::core::clone::Clone::clone(&(*__self_0_2)), + solution: ::core::clone::Clone::clone(&(*__self_0_3)), + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode + for SignedSubmission + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + dest.push(&self.who); + dest.push(&self.deposit); + dest.push(&self.reward); + dest.push(&self.solution); + } + } + impl _parity_scale_codec::EncodeLike + for SignedSubmission + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode + for SignedSubmission + where + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + Balance: _parity_scale_codec::Decode, + Balance: _parity_scale_codec::Decode, + Balance: _parity_scale_codec::Decode, + Balance: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(SignedSubmission { + who: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.who".into()) + } + Ok(a) => a, + } + }, + deposit: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.deposit".into()) + } + Ok(a) => a, + } + }, + reward: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.reward".into()) + } + Ok(a) => a, + } + }, + solution: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.solution".into()) + } + Ok(a) => a, + } + }, + }) + } + } + }; + impl core::fmt::Debug for SignedSubmission + where + AccountId: core::fmt::Debug, + Balance: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("SignedSubmission") + .field("who", &self.who) + .field("deposit", &self.deposit) + .field("reward", &self.reward) + .field("solution", &self.solution) + .finish() + } + } + /// A parsed solution, ready to be enacted. + pub struct ReadySolution { + winners: Vec, + supports: FlatSupportMap, + } + impl ::core::marker::StructuralPartialEq for ReadySolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for ReadySolution { + #[inline] + fn eq(&self, other: &ReadySolution) -> bool { + match *other { + ReadySolution { + winners: ref __self_1_0, + supports: ref __self_1_1, + } => match *self { + ReadySolution { + winners: ref __self_0_0, + supports: ref __self_0_1, + } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), + }, + } + } + #[inline] + fn ne(&self, other: &ReadySolution) -> bool { + match *other { + ReadySolution { + winners: ref __self_1_0, + supports: ref __self_1_1, + } => match *self { + ReadySolution { + winners: ref __self_0_0, + supports: ref __self_0_1, + } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), + }, + } + } + } + impl ::core::marker::StructuralEq for ReadySolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for ReadySolution { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for ReadySolution { + #[inline] + fn clone(&self) -> ReadySolution { + match *self { + ReadySolution { + winners: ref __self_0_0, + supports: ref __self_0_1, + } => ReadySolution { + winners: ::core::clone::Clone::clone(&(*__self_0_0)), + supports: ::core::clone::Clone::clone(&(*__self_0_1)), + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for ReadySolution + where + Vec: _parity_scale_codec::Encode, + Vec: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + dest.push(&self.winners); + dest.push(&self.supports); + } + } + impl _parity_scale_codec::EncodeLike for ReadySolution + where + Vec: _parity_scale_codec::Encode, + Vec: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for ReadySolution + where + Vec: _parity_scale_codec::Decode, + Vec: _parity_scale_codec::Decode, + FlatSupportMap: _parity_scale_codec::Decode, + FlatSupportMap: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(ReadySolution { + winners: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field ReadySolution.winners".into()) + } + Ok(a) => a, + } + }, + supports: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field ReadySolution.supports".into()) + } + Ok(a) => a, + } + }, + }) + } + } + }; + impl core::fmt::Debug for ReadySolution + where + AccountId: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("ReadySolution") + .field("winners", &self.winners) + .field("supports", &self.supports) + .finish() + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for ReadySolution { + #[inline] + fn default() -> ReadySolution { + ReadySolution { + winners: ::core::default::Default::default(), + supports: ::core::default::Default::default(), + } + } + } + pub trait WeightInfo {} + impl WeightInfo for () {} + pub trait Trait: frame_system::Trait { + type Event: From + Into<::Event>; + type Currency: ReservableCurrency + Currency; + type SignedPhase: Get; + type UnsignedPhase: Get; + type MaxSignedSubmissions: Get; + type SignedRewardBase: Get>; + type SignedRewardFactor: Get; + type SignedDepositBase: Get>; + type SignedDepositByte: Get>; + type SignedDepositWeight: Get>; + type SolutionImprovementThreshold: Get; + type SlashHandler: OnUnbalanced>; + type RewardHandler: OnUnbalanced>; + type ElectionDataProvider: ElectionDataProvider; + type WeightInfo: WeightInfo; + } + use self::sp_api_hidden_includes_decl_storage::hidden_include::{ + IterableStorageDoubleMap as _, IterableStorageMap as _, StorageDoubleMap as _, + StorageMap as _, StoragePrefixedMap as _, StorageValue as _, + }; + #[doc(hidden)] + mod sp_api_hidden_includes_decl_storage { + pub extern crate frame_support as hidden_include; + } + trait Store { + type CurrentPhase; + type SignedSubmissions; + type QueuedSolution; + type SnapshotTargets; + type SnapshotVoters; + type DesiredTargets; + } + impl Store for Module { + type CurrentPhase = CurrentPhase; + type SignedSubmissions = SignedSubmissions; + type QueuedSolution = QueuedSolution; + type SnapshotTargets = SnapshotTargets; + type SnapshotVoters = SnapshotVoters; + type DesiredTargets = DesiredTargets; + } + impl Module { + /// Current phase. + pub fn current_phase() -> Phase { + < CurrentPhase < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase > > :: get ( ) + } + /// Sorted list of unchecked, signed solutions. + pub fn signed_submissions() -> Vec>> { + < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > > > > > :: get ( ) + } + /// Current, best, unsigned solution. + pub fn queued_solution() -> Option> { + < QueuedSolution < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < ReadySolution < T :: AccountId > > > :: get ( ) + } + /// Snapshot of all Voters. The indices if this will be used in election. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub fn snapshot_targets() -> Option> { + < SnapshotTargets < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < T :: AccountId > > > :: get ( ) + } + /// Snapshot of all targets. The indices if this will be used in election. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub fn snapshot_voters() -> Option)>> { + < SnapshotVoters < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < ( T :: AccountId , VoteWeight , Vec < T :: AccountId > ) > > > :: get ( ) + } + /// Desired number of targets to elect + pub fn desired_targets() -> u32 { + < DesiredTargets < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) + } + } + #[doc(hidden)] + pub struct __GetByteStructCurrentPhase( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_CurrentPhase: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructCurrentPhase + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_CurrentPhase + .get_or_init(|| { + let def_val: Phase = Phase::Off; + ::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructCurrentPhase {} + unsafe impl Sync for __GetByteStructCurrentPhase {} + #[doc(hidden)] + pub struct __GetByteStructSignedSubmissions( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_SignedSubmissions: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructSignedSubmissions + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_SignedSubmissions + .get_or_init(|| { + let def_val: Vec>> = + Default::default(); + >> as Encode>::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructSignedSubmissions {} + unsafe impl Sync for __GetByteStructSignedSubmissions {} + #[doc(hidden)] + pub struct __GetByteStructQueuedSolution( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_QueuedSolution: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructQueuedSolution + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_QueuedSolution + .get_or_init(|| { + let def_val: Option> = Default::default(); + > as Encode>::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructQueuedSolution {} + unsafe impl Sync for __GetByteStructQueuedSolution {} + #[doc(hidden)] + pub struct __GetByteStructSnapshotTargets( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_SnapshotTargets: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructSnapshotTargets + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_SnapshotTargets + .get_or_init(|| { + let def_val: Option> = Default::default(); + > as Encode>::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructSnapshotTargets {} + unsafe impl Sync for __GetByteStructSnapshotTargets {} + #[doc(hidden)] + pub struct __GetByteStructSnapshotVoters( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_SnapshotVoters: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructSnapshotVoters + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_SnapshotVoters + .get_or_init(|| { + let def_val: Option)>> = + Default::default(); + )>> as Encode>::encode( + &def_val, + ) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructSnapshotVoters {} + unsafe impl Sync for __GetByteStructSnapshotVoters {} + #[doc(hidden)] + pub struct __GetByteStructDesiredTargets( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_DesiredTargets: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructDesiredTargets + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_DesiredTargets + .get_or_init(|| { + let def_val: u32 = Default::default(); + ::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructDesiredTargets {} + unsafe impl Sync for __GetByteStructDesiredTargets {} + impl Module { + #[doc(hidden)] + pub fn storage_metadata( + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::StorageMetadata { + self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current, best, unsigned solution." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters. The indices if this will be used in election." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets. The indices if this will be used in election." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect" ] ) , } ] [ .. ] ) , } + } + } + /// Hidden instance generated to be internally used when module is used without + /// instance. + #[doc(hidden)] + pub struct __InherentHiddenInstance; + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for __InherentHiddenInstance { + #[inline] + fn clone(&self) -> __InherentHiddenInstance { + match *self { + __InherentHiddenInstance => __InherentHiddenInstance, + } + } + } + impl ::core::marker::StructuralEq for __InherentHiddenInstance {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for __InherentHiddenInstance { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + {} + } + } + impl ::core::marker::StructuralPartialEq for __InherentHiddenInstance {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for __InherentHiddenInstance { + #[inline] + fn eq(&self, other: &__InherentHiddenInstance) -> bool { + match *other { + __InherentHiddenInstance => match *self { + __InherentHiddenInstance => true, + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for __InherentHiddenInstance { + fn encode_to(&self, dest: &mut EncOut) {} + } + impl _parity_scale_codec::EncodeLike for __InherentHiddenInstance {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for __InherentHiddenInstance { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(__InherentHiddenInstance) + } + } + }; + impl core::fmt::Debug for __InherentHiddenInstance { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_tuple("__InherentHiddenInstance").finish() + } + } + impl self::sp_api_hidden_includes_decl_storage::hidden_include::traits::Instance + for __InherentHiddenInstance + { + const PREFIX: &'static str = "TwoPhaseElectionProvider"; + } + /// Current phase. + pub struct CurrentPhase( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Phase, + > for CurrentPhase + { + type Query = Phase; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"CurrentPhase" + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + v.unwrap_or_else(|| Phase::Off) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + Some(v) + } + } + /// Sorted list of unchecked, signed solutions. + pub struct SignedSubmissions( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Vec>>, + > for SignedSubmissions + { + type Query = Vec>>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"SignedSubmissions" + } + fn from_optional_value_to_query( + v: Option>>>, + ) -> Self::Query { + v.unwrap_or_else(|| Default::default()) + } + fn from_query_to_optional_value( + v: Self::Query, + ) -> Option>>> { + Some(v) + } + } + /// Current, best, unsigned solution. + pub struct QueuedSolution( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + ReadySolution, + > for QueuedSolution + { + type Query = Option>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"QueuedSolution" + } + fn from_optional_value_to_query(v: Option>) -> Self::Query { + v.or_else(|| Default::default()) + } + fn from_query_to_optional_value(v: Self::Query) -> Option> { + v + } + } + /// Snapshot of all Voters. The indices if this will be used in election. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub struct SnapshotTargets( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Vec, + > for SnapshotTargets + { + type Query = Option>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"SnapshotTargets" + } + fn from_optional_value_to_query(v: Option>) -> Self::Query { + v.or_else(|| Default::default()) + } + fn from_query_to_optional_value(v: Self::Query) -> Option> { + v + } + } + /// Snapshot of all targets. The indices if this will be used in election. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub struct SnapshotVoters( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Vec<(T::AccountId, VoteWeight, Vec)>, + > for SnapshotVoters + { + type Query = Option)>>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"SnapshotVoters" + } + fn from_optional_value_to_query( + v: Option)>>, + ) -> Self::Query { + v.or_else(|| Default::default()) + } + fn from_query_to_optional_value( + v: Self::Query, + ) -> Option)>> { + v + } + } + /// Desired number of targets to elect + pub struct DesiredTargets( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + u32, + > for DesiredTargets + { + type Query = u32; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"DesiredTargets" + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + v.unwrap_or_else(|| Default::default()) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + Some(v) + } + } + /// Events for this module. + /// + pub enum Event { + SolutionStored(ElectionCompute), + ElectionFinalized(ElectionCompute), + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Event { + #[inline] + fn clone(&self) -> Event { + match (&*self,) { + (&Event::SolutionStored(ref __self_0),) => { + Event::SolutionStored(::core::clone::Clone::clone(&(*__self_0))) + } + (&Event::ElectionFinalized(ref __self_0),) => { + Event::ElectionFinalized(::core::clone::Clone::clone(&(*__self_0))) + } + } + } + } + impl ::core::marker::StructuralPartialEq for Event {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Event { + #[inline] + fn eq(&self, other: &Event) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &Event::SolutionStored(ref __self_0), + &Event::SolutionStored(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + ( + &Event::ElectionFinalized(ref __self_0), + &Event::ElectionFinalized(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => unsafe { ::core::intrinsics::unreachable() }, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &Event) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &Event::SolutionStored(ref __self_0), + &Event::SolutionStored(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + ( + &Event::ElectionFinalized(ref __self_0), + &Event::ElectionFinalized(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => unsafe { ::core::intrinsics::unreachable() }, + } + } else { + true + } + } + } + } + impl ::core::marker::StructuralEq for Event {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Event { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for Event { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + Event::SolutionStored(ref aa) => { + dest.push_byte(0usize as u8); + dest.push(aa); + } + Event::ElectionFinalized(ref aa) => { + dest.push_byte(1usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for Event {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for Event { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(Event::SolutionStored({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field Event :: SolutionStored.0".into()) + } + Ok(a) => a, + } + })), + x if x == 1usize as u8 => Ok(Event::ElectionFinalized({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err( + "Error decoding field Event :: ElectionFinalized.0".into() + ) + } + Ok(a) => a, + } + })), + x => Err("No such variant in enum Event".into()), + } + } + } + }; + impl core::fmt::Debug for Event { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::SolutionStored(ref a0) => { + fmt.debug_tuple("Event::SolutionStored").field(a0).finish() + } + Self::ElectionFinalized(ref a0) => fmt + .debug_tuple("Event::ElectionFinalized") + .field(a0) + .finish(), + _ => Ok(()), + } + } + } + impl From for () { + fn from(_: Event) -> () { + () + } + } + impl Event { + #[allow(dead_code)] + #[doc(hidden)] + pub fn metadata() -> &'static [::frame_support::event::EventMetadata] { + &[ + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("SolutionStored"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&[ + "ElectionCompute", + ]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[]), + }, + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("ElectionFinalized"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&[ + "ElectionCompute", + ]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[]), + }, + ] + } + } + pub enum PalletError { + #[doc(hidden)] + __Ignore( + ::frame_support::sp_std::marker::PhantomData<(T,)>, + ::frame_support::Never, + ), + EarlySubmission, + QueueFull, + SubmissionQueuedFull, + CannotPayDeposit, + } + impl ::frame_support::sp_std::fmt::Debug for PalletError { + fn fmt( + &self, + f: &mut ::frame_support::sp_std::fmt::Formatter<'_>, + ) -> ::frame_support::sp_std::fmt::Result { + f.write_str(self.as_str()) + } + } + impl PalletError { + fn as_u8(&self) -> u8 { + match self { + PalletError::__Ignore(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"`__Ignore` can never be constructed",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + PalletError::EarlySubmission => 0, + PalletError::QueueFull => 0 + 1, + PalletError::SubmissionQueuedFull => 0 + 1 + 1, + PalletError::CannotPayDeposit => 0 + 1 + 1 + 1, + } + } + fn as_str(&self) -> &'static str { + match self { + Self::__Ignore(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"`__Ignore` can never be constructed",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + PalletError::EarlySubmission => "EarlySubmission", + PalletError::QueueFull => "QueueFull", + PalletError::SubmissionQueuedFull => "SubmissionQueuedFull", + PalletError::CannotPayDeposit => "CannotPayDeposit", + } + } + } + impl From> for &'static str { + fn from(err: PalletError) -> &'static str { + err.as_str() + } + } + impl From> for ::frame_support::sp_runtime::DispatchError { + fn from(err: PalletError) -> Self { + let index = ::index::>() + .expect("Every active module has an index in the runtime; qed") as u8; + ::frame_support::sp_runtime::DispatchError::Module { + index, + error: err.as_u8(), + message: Some(err.as_str()), + } + } + } + impl ::frame_support::error::ModuleErrorMetadata for PalletError { + fn metadata() -> &'static [::frame_support::error::ErrorMetadata] { + &[ + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("EarlySubmission"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + }, + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("QueueFull"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + }, + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("SubmissionQueuedFull"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + }, + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("CannotPayDeposit"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + }, + ] + } + } + pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>); + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Module { + #[inline] + fn clone(&self) -> Module { + match *self { + Module(ref __self_0_0) => Module(::core::clone::Clone::clone(&(*__self_0_0))), + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for Module {} + impl ::core::marker::StructuralPartialEq for Module {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Module { + #[inline] + fn eq(&self, other: &Module) -> bool { + match *other { + Module(ref __self_1_0) => match *self { + Module(ref __self_0_0) => (*__self_0_0) == (*__self_1_0), + }, + } + } + #[inline] + fn ne(&self, other: &Module) -> bool { + match *other { + Module(ref __self_1_0) => match *self { + Module(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), + }, + } + } + } + impl ::core::marker::StructuralEq for Module {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Module { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq< + ::frame_support::sp_std::marker::PhantomData<(T,)>, + >; + } + } + } + impl core::fmt::Debug for Module + where + T: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_tuple("Module").field(&self.0).finish() + } + } + impl + ::frame_support::traits::OnInitialize<::BlockNumber> for Module + { + fn on_initialize(now: T::BlockNumber) -> Weight { + let __within_span__ = { + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + { + use ::tracing::__macro_support::*; + let callsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "on_initialize", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(227u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + static CALLSITE: MacroCallsite = MacroCallsite::new(&META); + CALLSITE.register(); + &CALLSITE + }; + if callsite.is_enabled() { + let meta = callsite.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + ::tracing::Span::none() + } + } else { + ::tracing::Span::none() + } + }; + let __tracing_guard__ = __within_span__.enter(); + { + let next_election = T::ElectionDataProvider::next_election_prediction(now); + let next_election = next_election.max(now); + let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); + let unsigned_deadline = T::UnsignedPhase::get(); + let remaining = next_election - now; + match Self::current_phase() { + Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { + CurrentPhase::put(Phase::Signed); + Self::start_signed_phase(); + } + Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { + let found_solution = Self::finalize_signed_phase(); + CurrentPhase::put(Phase::Unsigned(!found_solution)); + } + _ => {} + } + Default::default() + } + } + } + impl ::frame_support::traits::OnRuntimeUpgrade for Module {} + impl + ::frame_support::traits::OnFinalize<::BlockNumber> for Module + { + } + impl + ::frame_support::traits::OffchainWorker<::BlockNumber> for Module + { + fn offchain_worker(n: T::BlockNumber) {} + } + impl Module { + /// Deposits an event using `frame_system::Module::deposit_event`. + fn deposit_event(event: impl Into<::Event>) { + >::deposit_event(event.into()) + } + } + #[cfg(feature = "std")] + impl ::frame_support::traits::IntegrityTest for Module {} + /// Can also be called using [`Call`]. + /// + /// [`Call`]: enum.Call.html + impl Module { + /// + /// NOTE: Calling this function will bypass origin filters. + fn submit(origin: T::Origin, solution: RawSolution) -> DispatchResultWithPostInfo { + let __within_span__ = { + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + { + use ::tracing::__macro_support::*; + let callsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "submit", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(227u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + static CALLSITE: MacroCallsite = MacroCallsite::new(&META); + CALLSITE.register(); + &CALLSITE + }; + if callsite.is_enabled() { + let meta = callsite.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + ::tracing::Span::none() + } + } else { + ::tracing::Span::none() + } + }; + let __tracing_guard__ = __within_span__.enter(); + let who = ensure_signed(origin)?; + { + if !Self::current_phase().is_signed() { + { + return Err(PalletError::::EarlySubmission.into()); + }; + } + }; + let queue_size = >::decode_len().unwrap_or_default() as u32; + { + if !(queue_size <= T::MaxSignedSubmissions::get()) { + { + return Err(PalletError::::SubmissionQueuedFull.into()); + }; + } + }; + let mut signed_submissions = Self::signed_submissions(); + let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution); + { + if !maybe_index.is_some() { + { + return Err(PalletError::::QueueFull.into()); + }; + } + }; + let index = maybe_index.expect("Option checked to be `Some`; qed."); + let deposit = signed_submissions[index].deposit; + T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; + if true { + { + match (&(signed_submissions.len() as u32), &(queue_size + 1)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }; + >::put(signed_submissions); + Ok(None.into()) + } + #[allow(unreachable_code)] + /// + /// NOTE: Calling this function will bypass origin filters. + fn submit_unsigned( + origin: T::Origin, + solution: RawSolution, + ) -> ::frame_support::dispatch::DispatchResult { + let __within_span__ = { + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + { + use ::tracing::__macro_support::*; + let callsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "submit_unsigned", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(227u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + static CALLSITE: MacroCallsite = MacroCallsite::new(&META); + CALLSITE.register(); + &CALLSITE + }; + if callsite.is_enabled() { + let meta = callsite.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + ::tracing::Span::none() + } + } else { + ::tracing::Span::none() + } + }; + let __tracing_guard__ = __within_span__.enter(); + { + ensure_none(origin)?; + { + ::std::rt::begin_panic("not implemented") + } + } + Ok(()) + } + } + /// Dispatchable calls. + /// + /// Each variant of this enum maps to a dispatchable function from the associated module. + pub enum Call { + #[doc(hidden)] + #[codec(skip)] + __PhantomItem( + ::frame_support::sp_std::marker::PhantomData<(T,)>, + ::frame_support::Never, + ), + #[allow(non_camel_case_types)] + submit(RawSolution), + #[allow(non_camel_case_types)] + submit_unsigned(RawSolution), + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for Call { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + Call::submit(ref aa) => { + dest.push_byte(0usize as u8); + dest.push(aa); + } + Call::submit_unsigned(ref aa) => { + dest.push_byte(1usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for Call {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for Call { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(Call::submit({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field Call :: submit.0".into()), + Ok(a) => a, + } + })), + x if x == 1usize as u8 => Ok(Call::submit_unsigned({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field Call :: submit_unsigned.0".into()) + } + Ok(a) => a, + } + })), + x => Err("No such variant in enum Call".into()), + } + } + } + }; + impl ::frame_support::dispatch::GetDispatchInfo for Call { + fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { + match *self { + Call::submit(ref solution) => { + let base_weight = 0; + let weight = + >::weigh_data( + &base_weight, + (solution,), + ); + let class = < dyn :: frame_support :: dispatch :: ClassifyDispatch < ( & RawSolution , ) > > :: classify_dispatch ( & base_weight , ( solution , ) ) ; + let pays_fee = + >::pays_fee( + &base_weight, + (solution,), + ); + ::frame_support::dispatch::DispatchInfo { + weight, + class, + pays_fee, + } + } + Call::submit_unsigned(ref solution) => { + let base_weight = 0; + let weight = + >::weigh_data( + &base_weight, + (solution,), + ); + let class = < dyn :: frame_support :: dispatch :: ClassifyDispatch < ( & RawSolution , ) > > :: classify_dispatch ( & base_weight , ( solution , ) ) ; + let pays_fee = + >::pays_fee( + &base_weight, + (solution,), + ); + ::frame_support::dispatch::DispatchInfo { + weight, + class, + pays_fee, + } + } + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__PhantomItem should never be used.",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + } + } + impl ::frame_support::dispatch::GetCallName for Call { + fn get_call_name(&self) -> &'static str { + match *self { + Call::submit(ref solution) => { + let _ = (solution); + "submit" + } + Call::submit_unsigned(ref solution) => { + let _ = (solution); + "submit_unsigned" + } + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__PhantomItem should never be used.",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + } + fn get_call_names() -> &'static [&'static str] { + &["submit", "submit_unsigned"] + } + } + impl ::frame_support::dispatch::Clone for Call { + fn clone(&self) -> Self { + match *self { + Call::submit(ref solution) => Call::submit((*solution).clone()), + Call::submit_unsigned(ref solution) => Call::submit_unsigned((*solution).clone()), + _ => ::std::rt::begin_panic("internal error: entered unreachable code"), + } + } + } + impl ::frame_support::dispatch::PartialEq for Call { + fn eq(&self, _other: &Self) -> bool { + match *self { + Call::submit(ref solution) => { + let self_params = (solution,); + if let Call::submit(ref solution) = *_other { + self_params == (solution,) + } else { + match *_other { + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic("internal error: entered unreachable code") + } + _ => false, + } + } + } + Call::submit_unsigned(ref solution) => { + let self_params = (solution,); + if let Call::submit_unsigned(ref solution) = *_other { + self_params == (solution,) + } else { + match *_other { + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic("internal error: entered unreachable code") + } + _ => false, + } + } + } + _ => ::std::rt::begin_panic("internal error: entered unreachable code"), + } + } + } + impl ::frame_support::dispatch::Eq for Call {} + impl ::frame_support::dispatch::fmt::Debug for Call { + fn fmt( + &self, + _f: &mut ::frame_support::dispatch::fmt::Formatter, + ) -> ::frame_support::dispatch::result::Result<(), ::frame_support::dispatch::fmt::Error> { + match *self { + Call::submit(ref solution) => _f.write_fmt(::core::fmt::Arguments::new_v1( + &["", ""], + &match (&"submit", &(solution.clone(),)) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), + ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), + ], + }, + )), + Call::submit_unsigned(ref solution) => { + _f.write_fmt(::core::fmt::Arguments::new_v1( + &["", ""], + &match (&"submit_unsigned", &(solution.clone(),)) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), + ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), + ], + }, + )) + } + _ => ::std::rt::begin_panic("internal error: entered unreachable code"), + } + } + } + impl ::frame_support::traits::UnfilteredDispatchable for Call { + type Origin = T::Origin; + fn dispatch_bypass_filter( + self, + _origin: Self::Origin, + ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { + match self { + Call::submit(solution) => >::submit(_origin, solution) + .map(Into::into) + .map_err(Into::into), + Call::submit_unsigned(solution) => >::submit_unsigned(_origin, solution) + .map(Into::into) + .map_err(Into::into), + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__PhantomItem should never be used.",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + } + } + impl ::frame_support::dispatch::Callable for Module { + type Call = Call; + } + impl Module { + #[doc(hidden)] + #[allow(dead_code)] + pub fn call_functions() -> &'static [::frame_support::dispatch::FunctionMetadata] { + &[ + ::frame_support::dispatch::FunctionMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("submit"), + arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + ::frame_support::dispatch::FunctionArgumentMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), + ty: ::frame_support::dispatch::DecodeDifferent::Encode("RawSolution"), + }, + ]), + documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[]), + }, + ::frame_support::dispatch::FunctionMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("submit_unsigned"), + arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + ::frame_support::dispatch::FunctionArgumentMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), + ty: ::frame_support::dispatch::DecodeDifferent::Encode("RawSolution"), + }, + ]), + documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[]), + }, + ] + } + } + impl Module { + #[doc(hidden)] + #[allow(dead_code)] + pub fn module_constants_metadata( + ) -> &'static [::frame_support::dispatch::ModuleConstantMetadata] { + &[] + } + } + impl ::frame_support::dispatch::ModuleErrorMetadata for Module { + fn metadata() -> &'static [::frame_support::dispatch::ErrorMetadata] { + <&'static str as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() + } + } + pub enum FeasibilityError { + /// Wrong number of winners presented. + WrongWinnerCount, + /// The snapshot is not available. + /// + /// This must be an internal error of the chain. + SnapshotUnavailable, + /// Internal error from the election crate. + NposElectionError(sp_npos_elections::Error), + /// A vote is invalid. + InvalidVote, + /// A voter is invalid. + InvalidVoter, + /// A winner is invalid. + InvalidWinner, + /// The given score was invalid. + InvalidScore, + } + impl From for FeasibilityError { + fn from(e: sp_npos_elections::Error) -> Self { + FeasibilityError::NposElectionError(e) + } + } + impl Module { + /// Checks the feasibility of a solution. + fn feasibility_check( + solution: RawSolution, + ) -> Result, FeasibilityError> { + let RawSolution { + winners, + compact, + score, + } = solution; + { + if !(compact.unique_targets().len() == winners.len()) { + { + return Err(FeasibilityError::WrongWinnerCount.into()); + }; + } + }; + { + if !(winners.len() as u32 == Self::desired_targets()) { + { + return Err(FeasibilityError::WrongWinnerCount.into()); + }; + } + }; + let snapshot_voters = + Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; + let snapshot_targets = + Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; + let voter_at = |i: VoterIndex| -> Option { + snapshot_voters.get(i as usize).map(|(x, _, _)| x).cloned() + }; + let target_at = |i: TargetIndex| -> Option { + snapshot_targets.get(i as usize).cloned() + }; + let winners = winners + .into_iter() + .map(|i| target_at(i).ok_or(FeasibilityError::InvalidWinner)) + .collect::, FeasibilityError>>()?; + let assignments = compact + .into_assignment(voter_at, target_at) + .map_err::(Into::into)?; + let _ = assignments + .iter() + .map(|Assignment { who, distribution }| { + snapshot_voters.iter().find(|(v, _, _)| v == who).map_or( + Err(FeasibilityError::InvalidVoter), + |(_, _, t)| { + if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) + && T::ElectionDataProvider::feasibility_check_assignment::< + OffchainAccuracy, + >(who, distribution) + { + Ok(()) + } else { + Err(FeasibilityError::InvalidVote) + } + }, + ) + }) + .collect::>()?; + let stake_of = |who: &T::AccountId| -> crate::VoteWeight { + snapshot_voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + }; + use sp_npos_elections::{assignment_ratio_to_staked_normalized, build_support_map}; + let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) + .map_err::(Into::into)?; + let supports = build_support_map(&winners, &staked_assignments) + .map_err::(Into::into)?; + let known_score = evaluate_support(&supports); + { + if !(known_score == score) { + { + return Err(FeasibilityError::InvalidScore.into()); + }; + } + }; + let supports = supports.flatten(); + Ok(ReadySolution { winners, supports }) + } + fn onchain_fallback() -> Result, crate::Error> { + let desired_targets = Self::desired_targets() as usize; + let voters = Self::snapshot_voters().ok_or(crate::Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(crate::Error::SnapshotUnAvailable)?; + >::elect::( + desired_targets, + targets, + voters, + ) + } + } + impl crate::ElectionProvider for Module { + fn elect( + _to_elect: usize, + _targets: Vec, + _voters: Vec<(T::AccountId, VoteWeight, Vec)>, + ) -> Result, crate::Error> + where + ExtendedBalance: From<

::Inner>, + P: sp_std::ops::Mul, + { + Self::queued_solution() + .map_or_else( + || Self::onchain_fallback(), + |ReadySolution { supports, .. }| Ok(supports), + ) + .map(|result| { + CurrentPhase::put(Phase::Off); + >::kill(); + >::kill(); + result + }) + } + fn ongoing() -> bool { + match Self::current_phase() { + Phase::Signed | Phase::Unsigned(_) => true, + _ => false, + } + } + } + #[cfg(test)] + mod tests { + use super::{mock::*, *}; + use crate::ElectionProvider; + use frame_support::traits::OnInitialize; + use sp_npos_elections::Support; + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const phase_rotation_works: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::tests::phase_rotation_works"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(phase_rotation_works())), + }; + fn phase_rotation_works() { + ExtBuilder::default().build_and_execute(|| { + { + match (&System::block_number(), &0) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&TwoPhase::current_phase(), &Phase::Off) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + roll_to(4); + { + match (&TwoPhase::current_phase(), &Phase::Off) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::snapshot_voters().is_none() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::snapshot_voters().is_none()", + ) + } + }; + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::snapshot_voters().is_some() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::snapshot_voters().is_some()", + ) + } + }; + roll_to(14); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::snapshot_voters().is_some() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::snapshot_voters().is_some()", + ) + } + }; + roll_to(15); + { + match (&TwoPhase::current_phase(), &Phase::Unsigned(true)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::snapshot_voters().is_some() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::snapshot_voters().is_some()", + ) + } + }; + roll_to(19); + { + match (&TwoPhase::current_phase(), &Phase::Unsigned(true)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::snapshot_voters().is_some() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::snapshot_voters().is_some()", + ) + } + }; + roll_to(20); + { + match (&TwoPhase::current_phase(), &Phase::Unsigned(true)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::snapshot_voters().is_some() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::snapshot_voters().is_some()", + ) + } + }; + roll_to(21); + { + match (&TwoPhase::current_phase(), &Phase::Unsigned(true)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::snapshot_voters().is_some() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::snapshot_voters().is_some()", + ) + } + }; + TwoPhase::elect::(2, Default::default(), Default::default()) + .unwrap(); + { + match (&TwoPhase::current_phase(), &Phase::Off) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::snapshot_voters().is_none() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::snapshot_voters().is_none()", + ) + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const onchain_backup_works: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::tests::onchain_backup_works"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(onchain_backup_works())), + }; + fn onchain_backup_works() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + roll_to(20); + { + match (&TwoPhase::current_phase(), &Phase::Unsigned(true)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let supports = TwoPhase::elect::( + 2, + Default::default(), + Default::default(), + ) + .unwrap(); + { + match ( + &supports, + &<[_]>::into_vec(box [ + ( + 30, + Support { + total: 40, + voters: <[_]>::into_vec(box [(2, 5), (4, 5), (30, 30)]), + }, + ), + ( + 40, + Support { + total: 60, + voters: <[_]>::into_vec(box [ + (2, 5), + (3, 10), + (4, 5), + (40, 40), + ]), + }, + ), + ]), + ) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + } + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const can_only_submit_threshold_better: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::tests::can_only_submit_threshold_better"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(can_only_submit_threshold_better()) + }), + }; + fn can_only_submit_threshold_better() {} + } +} +use sp_arithmetic::PerThing; +#[doc(hidden)] +pub use sp_npos_elections::VoteWeight; +use sp_npos_elections::{ExtendedBalance, FlatSupportMap}; +use sp_runtime::RuntimeDebug; +#[doc(hidden)] +pub use sp_std::convert::TryInto; +/// A bridge between the entity requesting a long-lasting election from something that implements +/// [`ElectionProvider`], such as the [`two_phase`] module. +pub trait ElectionDataProvider { + fn targets() -> Vec; + fn voters() -> Vec<(AccountId, VoteWeight, Vec)>; + fn desired_targets() -> u32; + fn feasibility_check_assignment( + who: &AccountId, + distribution: &[(AccountId, P)], + ) -> bool; + fn next_election_prediction(now: B) -> B; +} +#[cfg(feature = "std")] +impl ElectionDataProvider for () { + fn targets() -> Vec { + Default::default() + } + fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { + Default::default() + } + fn desired_targets() -> u32 { + Default::default() + } + fn feasibility_check_assignment(_: &AccountId, _: &[(AccountId, P)]) -> bool { + Default::default() + } + fn next_election_prediction(_: B) -> B { + Default::default() + } +} +/// Something that can compute the result of an election and pass it back to a pallet. +pub trait ElectionProvider { + /// Elect a new set of winners. + /// + /// The result is returned in a target major format, namely as a support map. + fn elect( + to_elect: usize, + targets: Vec, + voters: Vec<(AccountId, VoteWeight, Vec)>, + ) -> Result, Error> + where + ExtendedBalance: From<

::Inner>, + P: sp_std::ops::Mul; + /// Returns true if an election is still ongoing. + fn ongoing() -> bool; +} +pub enum Error { + ElectionFailed, + SnapshotUnAvailable, + Internal(sp_npos_elections::Error), +} +impl core::fmt::Debug for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::ElectionFailed => fmt.debug_tuple("Error::ElectionFailed").finish(), + Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), + Self::Internal(ref a0) => fmt.debug_tuple("Error::Internal").field(a0).finish(), + _ => Ok(()), + } + } +} +impl ::core::marker::StructuralEq for Error {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } +} +impl ::core::marker::StructuralPartialEq for Error {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Internal(ref __self_0), &Error::Internal(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Internal(ref __self_0), &Error::Internal(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + _ => false, + } + } else { + true + } + } + } +} +impl From for Error { + fn from(err: sp_npos_elections::Error) -> Self { + Error::Internal(err) + } +} +#[main] +pub fn main() -> () { + extern crate test; + test::test_main_static(&[ + &cannot_submit_too_early, + &should_pay_deposit, + &good_solution_is_rewarded, + &bad_solution_is_slashed, + &queue_is_always_sorted, + &can_submit_until_queue_full, + &weakest_is_removed_if_better_provided, + &cannot_submit_worse_with_full_queue, + &suppressed_solution_gets_bond_back, + &solutions_are_sorted, + &all_in_one_singed_submission, + &phase_rotation_works, + &onchain_backup_works, + &can_only_submit_threshold_better, + ]) +} diff --git a/frame/election-providers/expanded.rs b/frame/election-providers/expanded.rs new file mode 100644 index 0000000000000..887cbf3b5f288 --- /dev/null +++ b/frame/election-providers/expanded.rs @@ -0,0 +1,5567 @@ +#![feature(prelude_import)] +#[prelude_import] +use std::prelude::v1::*; +#[macro_use] +extern crate std; +use sp_std::prelude::*; +pub mod onchain { + use crate::{ElectionProvider, Error}; + use sp_arithmetic::PerThing; + use sp_npos_elections::{ + ElectionResult, ExtendedBalance, FlatSupportMap, FlattenSupportMap, IdentifierT, VoteWeight, + }; + use sp_std::{collections::btree_map::BTreeMap, prelude::*}; + pub struct OnChainSequentialPhragmen; + impl ElectionProvider for OnChainSequentialPhragmen { + fn elect( + to_elect: usize, + targets: Vec, + voters: Vec<(AccountId, VoteWeight, Vec)>, + ) -> Result, Error> + where + ExtendedBalance: From<

::Inner>, + P: sp_std::ops::Mul, + { + let mut stake_map: BTreeMap = BTreeMap::new(); + voters.iter().for_each(|(v, s, _)| { + stake_map.insert(v.clone(), *s); + }); + let stake_of = Box::new(|w: &AccountId| -> VoteWeight { + stake_map.get(w).cloned().unwrap_or_default() + }); + sp_npos_elections::seq_phragmen::<_, P>(to_elect, targets, voters, None) + .and_then(|e| { + let ElectionResult { + winners, + assignments, + } = e; + let staked = sp_npos_elections::assignment_ratio_to_staked_normalized( + assignments, + &stake_of, + )?; + let winners = sp_npos_elections::to_without_backing(winners); + sp_npos_elections::build_support_map(&winners, &staked).map(|s| s.flatten()) + }) + .map_err(From::from) + } + fn ongoing() -> bool { + false + } + } +} +pub mod two_phase { + use crate::{onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider}; + use codec::{Decode, Encode, HasCompact}; + use frame_support::{ + decl_error, decl_event, decl_module, decl_storage, + dispatch::DispatchResultWithPostInfo, + ensure, + traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, + weights::Weight, + }; + use frame_system::{ensure_none, ensure_signed}; + use sp_npos_elections::{ + evaluate_support, generate_solution_type, Assignment, ElectionScore, ExtendedBalance, + FlatSupportMap, FlattenSupportMap, VoteWeight, + }; + use sp_runtime::{traits::Zero, PerThing, PerU16, Perbill, RuntimeDebug}; + use sp_std::{mem::size_of, prelude::*}; + pub mod signed { + use crate::two_phase::*; + use codec::Encode; + use sp_arithmetic::traits::SaturatedConversion; + use sp_npos_elections::is_score_better; + impl Module { + /// Start the signed phase. + /// + /// Upon calling this, auxillary data for election is stored and signed solutions will be + /// accepted. + /// + /// The signed phase must always start before the unsigned phase. + pub fn start_signed_phase() { + let targets = T::ElectionDataProvider::targets(); + let voters = T::ElectionDataProvider::voters(); + let desired_targets = T::ElectionDataProvider::desired_targets(); + >::put(targets); + >::put(voters); + DesiredTargets::put(desired_targets); + } + /// Finish the singed phase. + /// + /// Returns true if we have a good solution in the signed phase. + pub fn finalize_signed_phase() -> bool { + let mut all_submission: Vec> = + >::take(); + let mut found_solution = false; + while let Some(best) = all_submission.pop() { + let SignedSubmission { + solution, + who, + deposit, + reward, + } = best; + match Self::feasibility_check(solution, ElectionCompute::Signed) { + Ok(ready_solution) => { + >::put(ready_solution); + let _remaining = T::Currency::unreserve(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic( + "assertion failed: _remaining.is_zero()", + ) + } + }; + }; + let positive_imbalance = T::Currency::deposit_creating(&who, reward); + T::RewardHandler::on_unbalanced(positive_imbalance); + found_solution = true; + break; + } + Err(_) => { + let (negative_imbalance, _remaining) = + T::Currency::slash_reserved(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic( + "assertion failed: _remaining.is_zero()", + ) + } + }; + }; + T::SlashHandler::on_unbalanced(negative_imbalance); + } + } + } + all_submission.into_iter().for_each(|not_processed| { + match ¬_processed { + tmp => { + { + ::std::io::_eprint(::core::fmt::Arguments::new_v1_formatted( + &["[", ":", "] ", " = ", "\n"], + &match ( + &"frame/election-providers/src/two_phase/signed.rs", + &65u32, + &"¬_processed", + &&tmp, + ) { + (arg0, arg1, arg2, arg3) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg2, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg3, + ::core::fmt::Debug::fmt, + ), + ], + }, + &[ + ::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 1usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 2usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 3usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ], + )); + }; + tmp + } + }; + let SignedSubmission { who, deposit, .. } = not_processed; + let _remaining = T::Currency::unreserve(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic("assertion failed: _remaining.is_zero()") + } + }; + }; + }); + found_solution + } + /// Find a proper position in the queue for the signed queue, whilst maintaining the order of + /// solution quality. + pub fn insert_submission( + who: &T::AccountId, + queue: &mut Vec>>, + solution: RawSolution, + ) -> Option { + let outcome = queue + .iter() + .enumerate() + .rev() + .find_map(|(i, s)| { + if is_score_better( + solution.score, + s.solution.score, + T::SolutionImprovementThreshold::get(), + ) { + Some(i + 1) + } else { + None + } + }) + .or(Some(0)) + .and_then(|at| { + if at == 0 && queue.len() as u32 >= T::MaxSignedSubmissions::get() { + None + } else { + let reward = Self::reward_for(&solution); + let deposit = Self::deposit_for(&solution); + let submission = SignedSubmission { + who: who.clone(), + deposit, + reward, + solution, + }; + queue.insert(at, submission); + if queue.len() as u32 > T::MaxSignedSubmissions::get() { + queue.remove(0); + Some(at - 1) + } else { + Some(at) + } + } + }); + if true { + if !(queue.len() as u32 <= T::MaxSignedSubmissions::get()) { + { + :: std :: rt :: begin_panic ( "assertion failed: queue.len() as u32 <= T::MaxSignedSubmissions::get()" ) + } + }; + }; + outcome + } + pub fn deposit_for(solution: &RawSolution) -> BalanceOf { + let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); + T::SignedDepositBase::get() + T::SignedDepositByte::get() * encoded_len + } + pub fn reward_for(solution: &RawSolution) -> BalanceOf { + T::SignedRewardBase::get() + + T::SignedRewardFactor::get() + * solution.score[0].saturated_into::>() + } + } + } + pub mod unsigned {} + type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + type PositiveImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::PositiveImbalance; + type NegativeImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::NegativeImbalance; + /// Accuracy used for on-chain election. + pub type ChainAccuracy = Perbill; + /// Accuracy used for off-chain election. This better be small. + pub type OffchainAccuracy = PerU16; + /// Data type used to index nominators in the compact type. + pub type VoterIndex = u32; + /// Data type used to index validators in the compact type. + pub type TargetIndex = u16; + #[allow(unknown_lints, eq_op)] + const _: [(); 0 - !{ + const ASSERT: bool = size_of::() <= size_of::(); + ASSERT + } as usize] = []; + #[allow(unknown_lints, eq_op)] + const _: [(); 0 - !{ + const ASSERT: bool = size_of::() <= size_of::(); + ASSERT + } as usize] = []; + #[allow(unknown_lints, eq_op)] + const _: [(); 0 - !{ + const ASSERT: bool = size_of::() <= size_of::(); + ASSERT + } as usize] = []; + #[allow(unknown_lints, eq_op)] + const _: [(); 0 - !{ + const ASSERT: bool = size_of::() <= size_of::(); + ASSERT + } as usize] = []; + extern crate sp_npos_elections as _npos; + /// A struct to encode a election assignment in a compact way. + impl _npos::codec::Encode for CompactAssignments { + fn encode(&self) -> Vec { + let mut r = ::alloc::vec::Vec::new(); + let votes1 = self + .votes1 + .iter() + .map(|(v, t)| { + ( + _npos::codec::Compact(v.clone()), + _npos::codec::Compact(t.clone()), + ) + }) + .collect::>(); + votes1.encode_to(&mut r); + let votes2 = self + .votes2 + .iter() + .map(|(v, (t1, w), t2)| { + ( + _npos::codec::Compact(v.clone()), + ( + _npos::codec::Compact(t1.clone()), + _npos::codec::Compact(w.clone()), + ), + _npos::codec::Compact(t2.clone()), + ) + }) + .collect::>(); + votes2.encode_to(&mut r); + let votes3 = self + .votes3 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes3.encode_to(&mut r); + let votes4 = self + .votes4 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes4.encode_to(&mut r); + let votes5 = self + .votes5 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes5.encode_to(&mut r); + let votes6 = self + .votes6 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes6.encode_to(&mut r); + let votes7 = self + .votes7 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes7.encode_to(&mut r); + let votes8 = self + .votes8 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes8.encode_to(&mut r); + let votes9 = self + .votes9 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes9.encode_to(&mut r); + let votes10 = self + .votes10 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes10.encode_to(&mut r); + let votes11 = self + .votes11 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes11.encode_to(&mut r); + let votes12 = self + .votes12 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes12.encode_to(&mut r); + let votes13 = self + .votes13 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes13.encode_to(&mut r); + let votes14 = self + .votes14 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[12usize].0.clone()), + _npos::codec::Compact(inner[12usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes14.encode_to(&mut r); + let votes15 = self + .votes15 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[12usize].0.clone()), + _npos::codec::Compact(inner[12usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[13usize].0.clone()), + _npos::codec::Compact(inner[13usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes15.encode_to(&mut r); + let votes16 = self + .votes16 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[12usize].0.clone()), + _npos::codec::Compact(inner[12usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[13usize].0.clone()), + _npos::codec::Compact(inner[13usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[14usize].0.clone()), + _npos::codec::Compact(inner[14usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes16.encode_to(&mut r); + r + } + } + impl _npos::codec::Decode for CompactAssignments { + fn decode(value: &mut I) -> Result { + let votes1 = , + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes1 = votes1 + .into_iter() + .map(|(v, t)| (v.0, t.0)) + .collect::>(); + let votes2 = , + ( + _npos::codec::Compact, + _npos::codec::Compact, + ), + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes2 = votes2 + .into_iter() + .map(|(v, (t1, w), t2)| (v.0, (t1.0, w.0), t2.0)) + .collect::>(); + let votes3 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 3usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes3 = votes3 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes4 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 4usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes4 = votes4 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes5 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 5usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes5 = votes5 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes6 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 6usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes6 = votes6 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes7 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 7usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes7 = votes7 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes8 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 8usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes8 = votes8 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes9 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 9usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes9 = votes9 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes10 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 10usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes10 = votes10 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes11 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 11usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes11 = votes11 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes12 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 12usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes12 = votes12 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes13 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 13usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes13 = votes13 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes14 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 14usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes14 = votes14 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ((inner[12usize].0).0, (inner[12usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes15 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 15usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes15 = votes15 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ((inner[12usize].0).0, (inner[12usize].1).0), + ((inner[13usize].0).0, (inner[13usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes16 = , + [( + _npos::codec::Compact, + _npos::codec::Compact, + ); 16usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes16 = votes16 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ((inner[12usize].0).0, (inner[12usize].1).0), + ((inner[13usize].0).0, (inner[13usize].1).0), + ((inner[14usize].0).0, (inner[14usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + Ok(CompactAssignments { + votes1, + votes2, + votes3, + votes4, + votes5, + votes6, + votes7, + votes8, + votes9, + votes10, + votes11, + votes12, + votes13, + votes14, + votes15, + votes16, + }) + } + } + pub struct CompactAssignments { + votes1: Vec<(VoterIndex, TargetIndex)>, + votes2: Vec<(VoterIndex, (TargetIndex, OffchainAccuracy), TargetIndex)>, + votes3: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 2usize], + TargetIndex, + )>, + votes4: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 3usize], + TargetIndex, + )>, + votes5: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 4usize], + TargetIndex, + )>, + votes6: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 5usize], + TargetIndex, + )>, + votes7: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 6usize], + TargetIndex, + )>, + votes8: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 7usize], + TargetIndex, + )>, + votes9: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 8usize], + TargetIndex, + )>, + votes10: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 9usize], + TargetIndex, + )>, + votes11: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 10usize], + TargetIndex, + )>, + votes12: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 11usize], + TargetIndex, + )>, + votes13: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 12usize], + TargetIndex, + )>, + votes14: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 13usize], + TargetIndex, + )>, + votes15: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 14usize], + TargetIndex, + )>, + votes16: Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 15usize], + TargetIndex, + )>, + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for CompactAssignments { + #[inline] + fn default() -> CompactAssignments { + CompactAssignments { + votes1: ::core::default::Default::default(), + votes2: ::core::default::Default::default(), + votes3: ::core::default::Default::default(), + votes4: ::core::default::Default::default(), + votes5: ::core::default::Default::default(), + votes6: ::core::default::Default::default(), + votes7: ::core::default::Default::default(), + votes8: ::core::default::Default::default(), + votes9: ::core::default::Default::default(), + votes10: ::core::default::Default::default(), + votes11: ::core::default::Default::default(), + votes12: ::core::default::Default::default(), + votes13: ::core::default::Default::default(), + votes14: ::core::default::Default::default(), + votes15: ::core::default::Default::default(), + votes16: ::core::default::Default::default(), + } + } + } + impl ::core::marker::StructuralPartialEq for CompactAssignments {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for CompactAssignments { + #[inline] + fn eq(&self, other: &CompactAssignments) -> bool { + match *other { + CompactAssignments { + votes1: ref __self_1_0, + votes2: ref __self_1_1, + votes3: ref __self_1_2, + votes4: ref __self_1_3, + votes5: ref __self_1_4, + votes6: ref __self_1_5, + votes7: ref __self_1_6, + votes8: ref __self_1_7, + votes9: ref __self_1_8, + votes10: ref __self_1_9, + votes11: ref __self_1_10, + votes12: ref __self_1_11, + votes13: ref __self_1_12, + votes14: ref __self_1_13, + votes15: ref __self_1_14, + votes16: ref __self_1_15, + } => match *self { + CompactAssignments { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + && (*__self_0_3) == (*__self_1_3) + && (*__self_0_4) == (*__self_1_4) + && (*__self_0_5) == (*__self_1_5) + && (*__self_0_6) == (*__self_1_6) + && (*__self_0_7) == (*__self_1_7) + && (*__self_0_8) == (*__self_1_8) + && (*__self_0_9) == (*__self_1_9) + && (*__self_0_10) == (*__self_1_10) + && (*__self_0_11) == (*__self_1_11) + && (*__self_0_12) == (*__self_1_12) + && (*__self_0_13) == (*__self_1_13) + && (*__self_0_14) == (*__self_1_14) + && (*__self_0_15) == (*__self_1_15) + } + }, + } + } + #[inline] + fn ne(&self, other: &CompactAssignments) -> bool { + match *other { + CompactAssignments { + votes1: ref __self_1_0, + votes2: ref __self_1_1, + votes3: ref __self_1_2, + votes4: ref __self_1_3, + votes5: ref __self_1_4, + votes6: ref __self_1_5, + votes7: ref __self_1_6, + votes8: ref __self_1_7, + votes9: ref __self_1_8, + votes10: ref __self_1_9, + votes11: ref __self_1_10, + votes12: ref __self_1_11, + votes13: ref __self_1_12, + votes14: ref __self_1_13, + votes15: ref __self_1_14, + votes16: ref __self_1_15, + } => match *self { + CompactAssignments { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) + || (*__self_0_2) != (*__self_1_2) + || (*__self_0_3) != (*__self_1_3) + || (*__self_0_4) != (*__self_1_4) + || (*__self_0_5) != (*__self_1_5) + || (*__self_0_6) != (*__self_1_6) + || (*__self_0_7) != (*__self_1_7) + || (*__self_0_8) != (*__self_1_8) + || (*__self_0_9) != (*__self_1_9) + || (*__self_0_10) != (*__self_1_10) + || (*__self_0_11) != (*__self_1_11) + || (*__self_0_12) != (*__self_1_12) + || (*__self_0_13) != (*__self_1_13) + || (*__self_0_14) != (*__self_1_14) + || (*__self_0_15) != (*__self_1_15) + } + }, + } + } + } + impl ::core::marker::StructuralEq for CompactAssignments {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for CompactAssignments { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq< + Vec<(VoterIndex, (TargetIndex, OffchainAccuracy), TargetIndex)>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 2usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 3usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 4usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 5usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 6usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 7usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 8usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 9usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 10usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 11usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 12usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 13usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 14usize], + TargetIndex, + )>, + >; + let _: ::core::cmp::AssertParamIsEq< + Vec<( + VoterIndex, + [(TargetIndex, OffchainAccuracy); 15usize], + TargetIndex, + )>, + >; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for CompactAssignments { + #[inline] + fn clone(&self) -> CompactAssignments { + match *self { + CompactAssignments { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => CompactAssignments { + votes1: ::core::clone::Clone::clone(&(*__self_0_0)), + votes2: ::core::clone::Clone::clone(&(*__self_0_1)), + votes3: ::core::clone::Clone::clone(&(*__self_0_2)), + votes4: ::core::clone::Clone::clone(&(*__self_0_3)), + votes5: ::core::clone::Clone::clone(&(*__self_0_4)), + votes6: ::core::clone::Clone::clone(&(*__self_0_5)), + votes7: ::core::clone::Clone::clone(&(*__self_0_6)), + votes8: ::core::clone::Clone::clone(&(*__self_0_7)), + votes9: ::core::clone::Clone::clone(&(*__self_0_8)), + votes10: ::core::clone::Clone::clone(&(*__self_0_9)), + votes11: ::core::clone::Clone::clone(&(*__self_0_10)), + votes12: ::core::clone::Clone::clone(&(*__self_0_11)), + votes13: ::core::clone::Clone::clone(&(*__self_0_12)), + votes14: ::core::clone::Clone::clone(&(*__self_0_13)), + votes15: ::core::clone::Clone::clone(&(*__self_0_14)), + votes16: ::core::clone::Clone::clone(&(*__self_0_15)), + }, + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::fmt::Debug for CompactAssignments { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match *self { + CompactAssignments { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => { + let mut debug_trait_builder = f.debug_struct("CompactAssignments"); + let _ = debug_trait_builder.field("votes1", &&(*__self_0_0)); + let _ = debug_trait_builder.field("votes2", &&(*__self_0_1)); + let _ = debug_trait_builder.field("votes3", &&(*__self_0_2)); + let _ = debug_trait_builder.field("votes4", &&(*__self_0_3)); + let _ = debug_trait_builder.field("votes5", &&(*__self_0_4)); + let _ = debug_trait_builder.field("votes6", &&(*__self_0_5)); + let _ = debug_trait_builder.field("votes7", &&(*__self_0_6)); + let _ = debug_trait_builder.field("votes8", &&(*__self_0_7)); + let _ = debug_trait_builder.field("votes9", &&(*__self_0_8)); + let _ = debug_trait_builder.field("votes10", &&(*__self_0_9)); + let _ = debug_trait_builder.field("votes11", &&(*__self_0_10)); + let _ = debug_trait_builder.field("votes12", &&(*__self_0_11)); + let _ = debug_trait_builder.field("votes13", &&(*__self_0_12)); + let _ = debug_trait_builder.field("votes14", &&(*__self_0_13)); + let _ = debug_trait_builder.field("votes15", &&(*__self_0_14)); + let _ = debug_trait_builder.field("votes16", &&(*__self_0_15)); + debug_trait_builder.finish() + } + } + } + } + impl _npos::VotingLimit for CompactAssignments { + const LIMIT: usize = 16usize; + } + impl CompactAssignments { + /// Get the length of all the assignments that this type is encoding. This is basically + /// the same as the number of assignments, or the number of voters in total. + pub fn len(&self) -> usize { + let mut all_len = 0usize; + all_len = all_len.saturating_add(self.votes1.len()); + all_len = all_len.saturating_add(self.votes2.len()); + all_len = all_len.saturating_add(self.votes3.len()); + all_len = all_len.saturating_add(self.votes4.len()); + all_len = all_len.saturating_add(self.votes5.len()); + all_len = all_len.saturating_add(self.votes6.len()); + all_len = all_len.saturating_add(self.votes7.len()); + all_len = all_len.saturating_add(self.votes8.len()); + all_len = all_len.saturating_add(self.votes9.len()); + all_len = all_len.saturating_add(self.votes10.len()); + all_len = all_len.saturating_add(self.votes11.len()); + all_len = all_len.saturating_add(self.votes12.len()); + all_len = all_len.saturating_add(self.votes13.len()); + all_len = all_len.saturating_add(self.votes14.len()); + all_len = all_len.saturating_add(self.votes15.len()); + all_len = all_len.saturating_add(self.votes16.len()); + all_len + } + /// Get the total count of edges. + pub fn edge_count(&self) -> usize { + let mut all_edges = 0usize; + all_edges = all_edges.saturating_add(self.votes1.len().saturating_mul(1usize as usize)); + all_edges = all_edges.saturating_add(self.votes2.len().saturating_mul(2usize as usize)); + all_edges = all_edges.saturating_add(self.votes3.len().saturating_mul(3usize as usize)); + all_edges = all_edges.saturating_add(self.votes4.len().saturating_mul(4usize as usize)); + all_edges = all_edges.saturating_add(self.votes5.len().saturating_mul(5usize as usize)); + all_edges = all_edges.saturating_add(self.votes6.len().saturating_mul(6usize as usize)); + all_edges = all_edges.saturating_add(self.votes7.len().saturating_mul(7usize as usize)); + all_edges = all_edges.saturating_add(self.votes8.len().saturating_mul(8usize as usize)); + all_edges = all_edges.saturating_add(self.votes9.len().saturating_mul(9usize as usize)); + all_edges = + all_edges.saturating_add(self.votes10.len().saturating_mul(10usize as usize)); + all_edges = + all_edges.saturating_add(self.votes11.len().saturating_mul(11usize as usize)); + all_edges = + all_edges.saturating_add(self.votes12.len().saturating_mul(12usize as usize)); + all_edges = + all_edges.saturating_add(self.votes13.len().saturating_mul(13usize as usize)); + all_edges = + all_edges.saturating_add(self.votes14.len().saturating_mul(14usize as usize)); + all_edges = + all_edges.saturating_add(self.votes15.len().saturating_mul(15usize as usize)); + all_edges = + all_edges.saturating_add(self.votes16.len().saturating_mul(16usize as usize)); + all_edges + } + /// 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. + /// + /// The resulting indices are sorted. + pub fn unique_targets(&self) -> Vec { + let mut all_targets: Vec = Vec::with_capacity(self.average_edge_count()); + let mut maybe_insert_target = |t: TargetIndex| match all_targets.binary_search(&t) { + Ok(_) => (), + Err(pos) => all_targets.insert(pos, t), + }; + self.votes1.iter().for_each(|(_, t)| { + maybe_insert_target(*t); + }); + self.votes2.iter().for_each(|(_, (t1, _), t2)| { + maybe_insert_target(*t1); + maybe_insert_target(*t2); + }); + self.votes3.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes4.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes5.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes6.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes7.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes8.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes9.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes10.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes11.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes12.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes13.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes14.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes15.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes16.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + all_targets + } + /// Get the average edge count. + pub fn average_edge_count(&self) -> usize { + self.edge_count().checked_div(self.len()).unwrap_or(0) + } + /// 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 from + /// `self.len()`. + pub fn remove_voter(&mut self, to_remove: VoterIndex) -> bool { + if let Some(idx) = self.votes1.iter().position(|(x, _)| *x == to_remove) { + self.votes1.remove(idx); + return true; + } + if let Some(idx) = self.votes2.iter().position(|(x, _, _)| *x == to_remove) { + self.votes2.remove(idx); + return true; + } + if let Some(idx) = self.votes3.iter().position(|(x, _, _)| *x == to_remove) { + self.votes3.remove(idx); + return true; + } + if let Some(idx) = self.votes4.iter().position(|(x, _, _)| *x == to_remove) { + self.votes4.remove(idx); + return true; + } + if let Some(idx) = self.votes5.iter().position(|(x, _, _)| *x == to_remove) { + self.votes5.remove(idx); + return true; + } + if let Some(idx) = self.votes6.iter().position(|(x, _, _)| *x == to_remove) { + self.votes6.remove(idx); + return true; + } + if let Some(idx) = self.votes7.iter().position(|(x, _, _)| *x == to_remove) { + self.votes7.remove(idx); + return true; + } + if let Some(idx) = self.votes8.iter().position(|(x, _, _)| *x == to_remove) { + self.votes8.remove(idx); + return true; + } + if let Some(idx) = self.votes9.iter().position(|(x, _, _)| *x == to_remove) { + self.votes9.remove(idx); + return true; + } + if let Some(idx) = self.votes10.iter().position(|(x, _, _)| *x == to_remove) { + self.votes10.remove(idx); + return true; + } + if let Some(idx) = self.votes11.iter().position(|(x, _, _)| *x == to_remove) { + self.votes11.remove(idx); + return true; + } + if let Some(idx) = self.votes12.iter().position(|(x, _, _)| *x == to_remove) { + self.votes12.remove(idx); + return true; + } + if let Some(idx) = self.votes13.iter().position(|(x, _, _)| *x == to_remove) { + self.votes13.remove(idx); + return true; + } + if let Some(idx) = self.votes14.iter().position(|(x, _, _)| *x == to_remove) { + self.votes14.remove(idx); + return true; + } + if let Some(idx) = self.votes15.iter().position(|(x, _, _)| *x == to_remove) { + self.votes15.remove(idx); + return true; + } + if let Some(idx) = self.votes16.iter().position(|(x, _, _)| *x == to_remove) { + self.votes16.remove(idx); + return true; + } + return false; + } + } + use _npos::__OrInvalidIndex; + impl CompactAssignments { + pub fn from_assignment( + assignments: Vec<_npos::Assignment>, + index_of_voter: FV, + index_of_target: FT, + ) -> Result + where + A: _npos::IdentifierT, + for<'r> FV: Fn(&'r A) -> Option, + for<'r> FT: Fn(&'r A) -> Option, + { + let mut compact: CompactAssignments = Default::default(); + for _npos::Assignment { who, distribution } in assignments { + match distribution.len() { + 0 => continue, + 1 => compact.votes1.push(( + index_of_voter(&who).or_invalid_index()?, + index_of_target(&distribution[0].0).or_invalid_index()?, + )), + 2 => compact.votes2.push(( + index_of_voter(&who).or_invalid_index()?, + ( + index_of_target(&distribution[0].0).or_invalid_index()?, + distribution[0].1, + ), + index_of_target(&distribution[1].0).or_invalid_index()?, + )), + 3usize => compact.votes3.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ], + index_of_target(&distribution[2usize].0).or_invalid_index()?, + )), + 4usize => compact.votes4.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ], + index_of_target(&distribution[3usize].0).or_invalid_index()?, + )), + 5usize => compact.votes5.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ], + index_of_target(&distribution[4usize].0).or_invalid_index()?, + )), + 6usize => compact.votes6.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ], + index_of_target(&distribution[5usize].0).or_invalid_index()?, + )), + 7usize => compact.votes7.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ], + index_of_target(&distribution[6usize].0).or_invalid_index()?, + )), + 8usize => compact.votes8.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ], + index_of_target(&distribution[7usize].0).or_invalid_index()?, + )), + 9usize => compact.votes9.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ], + index_of_target(&distribution[8usize].0).or_invalid_index()?, + )), + 10usize => compact.votes10.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ], + index_of_target(&distribution[9usize].0).or_invalid_index()?, + )), + 11usize => compact.votes11.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ], + index_of_target(&distribution[10usize].0).or_invalid_index()?, + )), + 12usize => compact.votes12.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ], + index_of_target(&distribution[11usize].0).or_invalid_index()?, + )), + 13usize => compact.votes13.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ], + index_of_target(&distribution[12usize].0).or_invalid_index()?, + )), + 14usize => compact.votes14.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ( + index_of_target(&distribution[12usize].0).or_invalid_index()?, + distribution[12usize].1, + ), + ], + index_of_target(&distribution[13usize].0).or_invalid_index()?, + )), + 15usize => compact.votes15.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ( + index_of_target(&distribution[12usize].0).or_invalid_index()?, + distribution[12usize].1, + ), + ( + index_of_target(&distribution[13usize].0).or_invalid_index()?, + distribution[13usize].1, + ), + ], + index_of_target(&distribution[14usize].0).or_invalid_index()?, + )), + 16usize => compact.votes16.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ( + index_of_target(&distribution[12usize].0).or_invalid_index()?, + distribution[12usize].1, + ), + ( + index_of_target(&distribution[13usize].0).or_invalid_index()?, + distribution[13usize].1, + ), + ( + index_of_target(&distribution[14usize].0).or_invalid_index()?, + distribution[14usize].1, + ), + ], + index_of_target(&distribution[15usize].0).or_invalid_index()?, + )), + _ => { + return Err(_npos::Error::CompactTargetOverflow); + } + } + } + Ok(compact) + } + pub fn into_assignment( + self, + voter_at: impl Fn(VoterIndex) -> Option, + target_at: impl Fn(TargetIndex) -> Option, + ) -> Result>, _npos::Error> { + let mut assignments: Vec<_npos::Assignment> = Default::default(); + for (voter_index, target_index) in self.votes1 { + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: <[_]>::into_vec(box [( + target_at(target_index).or_invalid_index()?, + OffchainAccuracy::one(), + )]), + }) + } + for (voter_index, (t1_idx, p1), t2_idx) in self.votes2 { + if p1 >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p2 = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + p1, + ); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: <[_]>::into_vec(box [ + (target_at(t1_idx).or_invalid_index()?, p1), + (target_at(t2_idx).or_invalid_index()?, p2), + ]), + }); + } + for (voter_index, inners, t_last_idx) in self.votes3 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes4 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes5 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes6 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes7 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes8 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes9 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes10 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes11 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes12 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes13 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes14 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes15 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes16 { + let mut sum = OffchainAccuracy::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= OffchainAccuracy::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + OffchainAccuracy::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + Ok(assignments) + } + } + const LOG_TARGET: &'static str = "two-phase-submission"; + pub enum Phase { + Off, + Signed, + Unsigned(bool), + } + impl ::core::marker::StructuralPartialEq for Phase {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Phase { + #[inline] + fn eq(&self, other: &Phase) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &Phase) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + _ => false, + } + } else { + true + } + } + } + } + impl ::core::marker::StructuralEq for Phase {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Phase { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Phase { + #[inline] + fn clone(&self) -> Phase { + { + let _: ::core::clone::AssertParamIsClone; + *self + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for Phase {} + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for Phase { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + Phase::Off => { + dest.push_byte(0usize as u8); + } + Phase::Signed => { + dest.push_byte(1usize as u8); + } + Phase::Unsigned(ref aa) => { + dest.push_byte(2usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for Phase {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for Phase { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(Phase::Off), + x if x == 1usize as u8 => Ok(Phase::Signed), + x if x == 2usize as u8 => Ok(Phase::Unsigned({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field Phase :: Unsigned.0".into()), + Ok(a) => a, + } + })), + x => Err("No such variant in enum Phase".into()), + } + } + } + }; + impl core::fmt::Debug for Phase { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::Off => fmt.debug_tuple("Phase::Off").finish(), + Self::Signed => fmt.debug_tuple("Phase::Signed").finish(), + Self::Unsigned(ref a0) => fmt.debug_tuple("Phase::Unsigned").field(a0).finish(), + _ => Ok(()), + } + } + } + impl Default for Phase { + fn default() -> Self { + Phase::Off + } + } + impl Phase { + pub fn is_signed(&self) -> bool { + match self { + Phase::Signed => true, + _ => false, + } + } + pub fn is_unsigned(&self) -> bool { + match self { + Phase::Unsigned(_) => true, + _ => false, + } + } + pub fn is_unsigned_open(&self) -> bool { + match self { + Phase::Unsigned(true) => true, + _ => false, + } + } + pub fn is_off(&self) -> bool { + match self { + Phase::Off => true, + _ => false, + } + } + } + pub enum ElectionCompute { + OnChain, + Signed, + Unsigned, + } + impl ::core::marker::StructuralPartialEq for ElectionCompute {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for ElectionCompute { + #[inline] + fn eq(&self, other: &ElectionCompute) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + _ => true, + } + } else { + false + } + } + } + } + impl ::core::marker::StructuralEq for ElectionCompute {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for ElectionCompute { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + {} + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for ElectionCompute { + #[inline] + fn clone(&self) -> ElectionCompute { + { + *self + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for ElectionCompute {} + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for ElectionCompute { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + ElectionCompute::OnChain => { + dest.push_byte(0usize as u8); + } + ElectionCompute::Signed => { + dest.push_byte(1usize as u8); + } + ElectionCompute::Unsigned => { + dest.push_byte(2usize as u8); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for ElectionCompute {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for ElectionCompute { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(ElectionCompute::OnChain), + x if x == 1usize as u8 => Ok(ElectionCompute::Signed), + x if x == 2usize as u8 => Ok(ElectionCompute::Unsigned), + x => Err("No such variant in enum ElectionCompute".into()), + } + } + } + }; + impl core::fmt::Debug for ElectionCompute { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::OnChain => fmt.debug_tuple("ElectionCompute::OnChain").finish(), + Self::Signed => fmt.debug_tuple("ElectionCompute::Signed").finish(), + Self::Unsigned => fmt.debug_tuple("ElectionCompute::Unsigned").finish(), + _ => Ok(()), + } + } + } + impl Default for ElectionCompute { + fn default() -> Self { + ElectionCompute::OnChain + } + } + pub struct RawSolution { + winners: Vec, + compact: CompactAssignments, + score: ElectionScore, + } + impl ::core::marker::StructuralPartialEq for RawSolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for RawSolution { + #[inline] + fn eq(&self, other: &RawSolution) -> bool { + match *other { + RawSolution { + winners: ref __self_1_0, + compact: ref __self_1_1, + score: ref __self_1_2, + } => match *self { + RawSolution { + winners: ref __self_0_0, + compact: ref __self_0_1, + score: ref __self_0_2, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + } + }, + } + } + #[inline] + fn ne(&self, other: &RawSolution) -> bool { + match *other { + RawSolution { + winners: ref __self_1_0, + compact: ref __self_1_1, + score: ref __self_1_2, + } => match *self { + RawSolution { + winners: ref __self_0_0, + compact: ref __self_0_1, + score: ref __self_0_2, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) + || (*__self_0_2) != (*__self_1_2) + } + }, + } + } + } + impl ::core::marker::StructuralEq for RawSolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for RawSolution { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for RawSolution { + #[inline] + fn clone(&self) -> RawSolution { + match *self { + RawSolution { + winners: ref __self_0_0, + compact: ref __self_0_1, + score: ref __self_0_2, + } => RawSolution { + winners: ::core::clone::Clone::clone(&(*__self_0_0)), + compact: ::core::clone::Clone::clone(&(*__self_0_1)), + score: ::core::clone::Clone::clone(&(*__self_0_2)), + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for RawSolution { + fn encode_to(&self, dest: &mut EncOut) { + dest.push(&self.winners); + dest.push(&self.compact); + dest.push(&self.score); + } + } + impl _parity_scale_codec::EncodeLike for RawSolution {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for RawSolution { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(RawSolution { + winners: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field RawSolution.winners".into()), + Ok(a) => a, + } + }, + compact: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field RawSolution.compact".into()), + Ok(a) => a, + } + }, + score: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field RawSolution.score".into()), + Ok(a) => a, + } + }, + }) + } + } + }; + impl core::fmt::Debug for RawSolution { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("RawSolution") + .field("winners", &self.winners) + .field("compact", &self.compact) + .field("score", &self.score) + .finish() + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for RawSolution { + #[inline] + fn default() -> RawSolution { + RawSolution { + winners: ::core::default::Default::default(), + compact: ::core::default::Default::default(), + score: ::core::default::Default::default(), + } + } + } + pub struct SignedSubmission { + who: AccountId, + deposit: Balance, + reward: Balance, + solution: RawSolution, + } + impl ::core::marker::StructuralPartialEq + for SignedSubmission + { + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl + ::core::cmp::PartialEq for SignedSubmission + { + #[inline] + fn eq(&self, other: &SignedSubmission) -> bool { + match *other { + SignedSubmission { + who: ref __self_1_0, + deposit: ref __self_1_1, + reward: ref __self_1_2, + solution: ref __self_1_3, + } => match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + && (*__self_0_3) == (*__self_1_3) + } + }, + } + } + #[inline] + fn ne(&self, other: &SignedSubmission) -> bool { + match *other { + SignedSubmission { + who: ref __self_1_0, + deposit: ref __self_1_1, + reward: ref __self_1_2, + solution: ref __self_1_3, + } => match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) + || (*__self_0_2) != (*__self_1_2) + || (*__self_0_3) != (*__self_1_3) + } + }, + } + } + } + impl ::core::marker::StructuralEq + for SignedSubmission + { + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq + for SignedSubmission + { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl + ::core::clone::Clone for SignedSubmission + { + #[inline] + fn clone(&self) -> SignedSubmission { + match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => SignedSubmission { + who: ::core::clone::Clone::clone(&(*__self_0_0)), + deposit: ::core::clone::Clone::clone(&(*__self_0_1)), + reward: ::core::clone::Clone::clone(&(*__self_0_2)), + solution: ::core::clone::Clone::clone(&(*__self_0_3)), + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode + for SignedSubmission + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + dest.push(&self.who); + dest.push(&self.deposit); + dest.push(&self.reward); + dest.push(&self.solution); + } + } + impl _parity_scale_codec::EncodeLike + for SignedSubmission + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + Balance: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode + for SignedSubmission + where + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + Balance: _parity_scale_codec::Decode, + Balance: _parity_scale_codec::Decode, + Balance: _parity_scale_codec::Decode, + Balance: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(SignedSubmission { + who: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.who".into()) + } + Ok(a) => a, + } + }, + deposit: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.deposit".into()) + } + Ok(a) => a, + } + }, + reward: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.reward".into()) + } + Ok(a) => a, + } + }, + solution: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.solution".into()) + } + Ok(a) => a, + } + }, + }) + } + } + }; + impl core::fmt::Debug for SignedSubmission + where + AccountId: core::fmt::Debug, + Balance: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("SignedSubmission") + .field("who", &self.who) + .field("deposit", &self.deposit) + .field("reward", &self.reward) + .field("solution", &self.solution) + .finish() + } + } + /// A parsed solution, ready to be enacted. + pub struct ReadySolution { + winners: Vec, + supports: FlatSupportMap, + compute: ElectionCompute, + } + impl ::core::marker::StructuralPartialEq for ReadySolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for ReadySolution { + #[inline] + fn eq(&self, other: &ReadySolution) -> bool { + match *other { + ReadySolution { + winners: ref __self_1_0, + supports: ref __self_1_1, + compute: ref __self_1_2, + } => match *self { + ReadySolution { + winners: ref __self_0_0, + supports: ref __self_0_1, + compute: ref __self_0_2, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + } + }, + } + } + #[inline] + fn ne(&self, other: &ReadySolution) -> bool { + match *other { + ReadySolution { + winners: ref __self_1_0, + supports: ref __self_1_1, + compute: ref __self_1_2, + } => match *self { + ReadySolution { + winners: ref __self_0_0, + supports: ref __self_0_1, + compute: ref __self_0_2, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) + || (*__self_0_2) != (*__self_1_2) + } + }, + } + } + } + impl ::core::marker::StructuralEq for ReadySolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for ReadySolution { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for ReadySolution { + #[inline] + fn clone(&self) -> ReadySolution { + match *self { + ReadySolution { + winners: ref __self_0_0, + supports: ref __self_0_1, + compute: ref __self_0_2, + } => ReadySolution { + winners: ::core::clone::Clone::clone(&(*__self_0_0)), + supports: ::core::clone::Clone::clone(&(*__self_0_1)), + compute: ::core::clone::Clone::clone(&(*__self_0_2)), + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for ReadySolution + where + Vec: _parity_scale_codec::Encode, + Vec: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + dest.push(&self.winners); + dest.push(&self.supports); + dest.push(&self.compute); + } + } + impl _parity_scale_codec::EncodeLike for ReadySolution + where + Vec: _parity_scale_codec::Encode, + Vec: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for ReadySolution + where + Vec: _parity_scale_codec::Decode, + Vec: _parity_scale_codec::Decode, + FlatSupportMap: _parity_scale_codec::Decode, + FlatSupportMap: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(ReadySolution { + winners: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field ReadySolution.winners".into()) + } + Ok(a) => a, + } + }, + supports: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field ReadySolution.supports".into()) + } + Ok(a) => a, + } + }, + compute: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field ReadySolution.compute".into()) + } + Ok(a) => a, + } + }, + }) + } + } + }; + impl core::fmt::Debug for ReadySolution + where + AccountId: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("ReadySolution") + .field("winners", &self.winners) + .field("supports", &self.supports) + .field("compute", &self.compute) + .finish() + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for ReadySolution { + #[inline] + fn default() -> ReadySolution { + ReadySolution { + winners: ::core::default::Default::default(), + supports: ::core::default::Default::default(), + compute: ::core::default::Default::default(), + } + } + } + pub trait WeightInfo {} + impl WeightInfo for () {} + pub trait Trait: frame_system::Trait { + type Event: From> + Into<::Event>; + type Currency: ReservableCurrency + Currency; + type SignedPhase: Get; + type UnsignedPhase: Get; + type MaxSignedSubmissions: Get; + type SignedRewardBase: Get>; + type SignedRewardFactor: Get; + type SignedDepositBase: Get>; + type SignedDepositByte: Get>; + type SignedDepositWeight: Get>; + type SolutionImprovementThreshold: Get; + type SlashHandler: OnUnbalanced>; + type RewardHandler: OnUnbalanced>; + type ElectionDataProvider: ElectionDataProvider; + type WeightInfo: WeightInfo; + } + use self::sp_api_hidden_includes_decl_storage::hidden_include::{ + IterableStorageDoubleMap as _, IterableStorageMap as _, StorageDoubleMap as _, + StorageMap as _, StoragePrefixedMap as _, StorageValue as _, + }; + #[doc(hidden)] + mod sp_api_hidden_includes_decl_storage { + pub extern crate frame_support as hidden_include; + } + trait Store { + type CurrentPhase; + type SignedSubmissions; + type QueuedSolution; + type SnapshotTargets; + type SnapshotVoters; + type DesiredTargets; + } + impl Store for Module { + type CurrentPhase = CurrentPhase; + type SignedSubmissions = SignedSubmissions; + type QueuedSolution = QueuedSolution; + type SnapshotTargets = SnapshotTargets; + type SnapshotVoters = SnapshotVoters; + type DesiredTargets = DesiredTargets; + } + impl Module { + /// Current phase. + pub fn current_phase() -> Phase { + < CurrentPhase < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase > > :: get ( ) + } + /// Sorted list of unchecked, signed solutions. + pub fn signed_submissions() -> Vec>> { + < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > > > > > :: get ( ) + } + /// Current, best, unsigned solution. + pub fn queued_solution() -> Option> { + < QueuedSolution < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < ReadySolution < T :: AccountId > > > :: get ( ) + } + /// Snapshot of all Voters. The indices if this will be used in election. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub fn snapshot_targets() -> Option> { + < SnapshotTargets < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < T :: AccountId > > > :: get ( ) + } + /// Snapshot of all targets. The indices if this will be used in election. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub fn snapshot_voters() -> Option)>> { + < SnapshotVoters < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < ( T :: AccountId , VoteWeight , Vec < T :: AccountId > ) > > > :: get ( ) + } + /// Desired number of targets to elect + pub fn desired_targets() -> u32 { + < DesiredTargets < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) + } + } + #[doc(hidden)] + pub struct __GetByteStructCurrentPhase( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_CurrentPhase: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructCurrentPhase + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_CurrentPhase + .get_or_init(|| { + let def_val: Phase = Phase::Off; + ::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructCurrentPhase {} + unsafe impl Sync for __GetByteStructCurrentPhase {} + #[doc(hidden)] + pub struct __GetByteStructSignedSubmissions( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_SignedSubmissions: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructSignedSubmissions + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_SignedSubmissions + .get_or_init(|| { + let def_val: Vec>> = + Default::default(); + >> as Encode>::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructSignedSubmissions {} + unsafe impl Sync for __GetByteStructSignedSubmissions {} + #[doc(hidden)] + pub struct __GetByteStructQueuedSolution( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_QueuedSolution: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructQueuedSolution + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_QueuedSolution + .get_or_init(|| { + let def_val: Option> = Default::default(); + > as Encode>::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructQueuedSolution {} + unsafe impl Sync for __GetByteStructQueuedSolution {} + #[doc(hidden)] + pub struct __GetByteStructSnapshotTargets( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_SnapshotTargets: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructSnapshotTargets + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_SnapshotTargets + .get_or_init(|| { + let def_val: Option> = Default::default(); + > as Encode>::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructSnapshotTargets {} + unsafe impl Sync for __GetByteStructSnapshotTargets {} + #[doc(hidden)] + pub struct __GetByteStructSnapshotVoters( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_SnapshotVoters: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructSnapshotVoters + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_SnapshotVoters + .get_or_init(|| { + let def_val: Option)>> = + Default::default(); + )>> as Encode>::encode( + &def_val, + ) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructSnapshotVoters {} + unsafe impl Sync for __GetByteStructSnapshotVoters {} + #[doc(hidden)] + pub struct __GetByteStructDesiredTargets( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_DesiredTargets: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructDesiredTargets + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_DesiredTargets + .get_or_init(|| { + let def_val: u32 = Default::default(); + ::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructDesiredTargets {} + unsafe impl Sync for __GetByteStructDesiredTargets {} + impl Module { + #[doc(hidden)] + pub fn storage_metadata( + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::StorageMetadata { + self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current, best, unsigned solution." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters. The indices if this will be used in election." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets. The indices if this will be used in election." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect" ] ) , } ] [ .. ] ) , } + } + } + /// Hidden instance generated to be internally used when module is used without + /// instance. + #[doc(hidden)] + pub struct __InherentHiddenInstance; + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for __InherentHiddenInstance { + #[inline] + fn clone(&self) -> __InherentHiddenInstance { + match *self { + __InherentHiddenInstance => __InherentHiddenInstance, + } + } + } + impl ::core::marker::StructuralEq for __InherentHiddenInstance {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for __InherentHiddenInstance { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + {} + } + } + impl ::core::marker::StructuralPartialEq for __InherentHiddenInstance {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for __InherentHiddenInstance { + #[inline] + fn eq(&self, other: &__InherentHiddenInstance) -> bool { + match *other { + __InherentHiddenInstance => match *self { + __InherentHiddenInstance => true, + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for __InherentHiddenInstance { + fn encode_to(&self, dest: &mut EncOut) {} + } + impl _parity_scale_codec::EncodeLike for __InherentHiddenInstance {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for __InherentHiddenInstance { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(__InherentHiddenInstance) + } + } + }; + impl core::fmt::Debug for __InherentHiddenInstance { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_tuple("__InherentHiddenInstance").finish() + } + } + impl self::sp_api_hidden_includes_decl_storage::hidden_include::traits::Instance + for __InherentHiddenInstance + { + const PREFIX: &'static str = "TwoPhaseElectionProvider"; + } + /// Current phase. + pub struct CurrentPhase( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Phase, + > for CurrentPhase + { + type Query = Phase; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"CurrentPhase" + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + v.unwrap_or_else(|| Phase::Off) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + Some(v) + } + } + /// Sorted list of unchecked, signed solutions. + pub struct SignedSubmissions( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Vec>>, + > for SignedSubmissions + { + type Query = Vec>>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"SignedSubmissions" + } + fn from_optional_value_to_query( + v: Option>>>, + ) -> Self::Query { + v.unwrap_or_else(|| Default::default()) + } + fn from_query_to_optional_value( + v: Self::Query, + ) -> Option>>> { + Some(v) + } + } + /// Current, best, unsigned solution. + pub struct QueuedSolution( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + ReadySolution, + > for QueuedSolution + { + type Query = Option>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"QueuedSolution" + } + fn from_optional_value_to_query(v: Option>) -> Self::Query { + v.or_else(|| Default::default()) + } + fn from_query_to_optional_value(v: Self::Query) -> Option> { + v + } + } + /// Snapshot of all Voters. The indices if this will be used in election. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub struct SnapshotTargets( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Vec, + > for SnapshotTargets + { + type Query = Option>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"SnapshotTargets" + } + fn from_optional_value_to_query(v: Option>) -> Self::Query { + v.or_else(|| Default::default()) + } + fn from_query_to_optional_value(v: Self::Query) -> Option> { + v + } + } + /// Snapshot of all targets. The indices if this will be used in election. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub struct SnapshotVoters( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Vec<(T::AccountId, VoteWeight, Vec)>, + > for SnapshotVoters + { + type Query = Option)>>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"SnapshotVoters" + } + fn from_optional_value_to_query( + v: Option)>>, + ) -> Self::Query { + v.or_else(|| Default::default()) + } + fn from_query_to_optional_value( + v: Self::Query, + ) -> Option)>> { + v + } + } + /// Desired number of targets to elect + pub struct DesiredTargets( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + u32, + > for DesiredTargets + { + type Query = u32; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"DesiredTargets" + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + v.unwrap_or_else(|| Default::default()) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + Some(v) + } + } + /// [`RawEvent`] specialized for the configuration [`Trait`] + /// + /// [`RawEvent`]: enum.RawEvent.html + /// [`Trait`]: trait.Trait.html + pub type Event = RawEvent<::AccountId>; + /// Events for this module. + /// + pub enum RawEvent { + /// A solution was sot + SolutionStored(ElectionCompute), + ElectionFinalized(Option), + Rewarded(AccountId), + Slashed(AccountId), + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for RawEvent { + #[inline] + fn clone(&self) -> RawEvent { + match (&*self,) { + (&RawEvent::SolutionStored(ref __self_0),) => { + RawEvent::SolutionStored(::core::clone::Clone::clone(&(*__self_0))) + } + (&RawEvent::ElectionFinalized(ref __self_0),) => { + RawEvent::ElectionFinalized(::core::clone::Clone::clone(&(*__self_0))) + } + (&RawEvent::Rewarded(ref __self_0),) => { + RawEvent::Rewarded(::core::clone::Clone::clone(&(*__self_0))) + } + (&RawEvent::Slashed(ref __self_0),) => { + RawEvent::Slashed(::core::clone::Clone::clone(&(*__self_0))) + } + } + } + } + impl ::core::marker::StructuralPartialEq for RawEvent {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for RawEvent { + #[inline] + fn eq(&self, other: &RawEvent) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &RawEvent::SolutionStored(ref __self_0), + &RawEvent::SolutionStored(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + ( + &RawEvent::ElectionFinalized(ref __self_0), + &RawEvent::ElectionFinalized(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + _ => unsafe { ::core::intrinsics::unreachable() }, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &RawEvent) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &RawEvent::SolutionStored(ref __self_0), + &RawEvent::SolutionStored(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + ( + &RawEvent::ElectionFinalized(ref __self_0), + &RawEvent::ElectionFinalized(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + _ => unsafe { ::core::intrinsics::unreachable() }, + } + } else { + true + } + } + } + } + impl ::core::marker::StructuralEq for RawEvent {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for RawEvent { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for RawEvent + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + RawEvent::SolutionStored(ref aa) => { + dest.push_byte(0usize as u8); + dest.push(aa); + } + RawEvent::ElectionFinalized(ref aa) => { + dest.push_byte(1usize as u8); + dest.push(aa); + } + RawEvent::Rewarded(ref aa) => { + dest.push_byte(2usize as u8); + dest.push(aa); + } + RawEvent::Slashed(ref aa) => { + dest.push_byte(3usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for RawEvent + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for RawEvent + where + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(RawEvent::SolutionStored({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err( + "Error decoding field RawEvent :: SolutionStored.0".into() + ) + } + Ok(a) => a, + } + })), + x if x == 1usize as u8 => Ok(RawEvent::ElectionFinalized({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err( + "Error decoding field RawEvent :: ElectionFinalized.0".into() + ) + } + Ok(a) => a, + } + })), + x if x == 2usize as u8 => Ok(RawEvent::Rewarded({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field RawEvent :: Rewarded.0".into()) + } + Ok(a) => a, + } + })), + x if x == 3usize as u8 => Ok(RawEvent::Slashed({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field RawEvent :: Slashed.0".into()) + } + Ok(a) => a, + } + })), + x => Err("No such variant in enum RawEvent".into()), + } + } + } + }; + impl core::fmt::Debug for RawEvent + where + AccountId: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::SolutionStored(ref a0) => fmt + .debug_tuple("RawEvent::SolutionStored") + .field(a0) + .finish(), + Self::ElectionFinalized(ref a0) => fmt + .debug_tuple("RawEvent::ElectionFinalized") + .field(a0) + .finish(), + Self::Rewarded(ref a0) => fmt.debug_tuple("RawEvent::Rewarded").field(a0).finish(), + Self::Slashed(ref a0) => fmt.debug_tuple("RawEvent::Slashed").field(a0).finish(), + _ => Ok(()), + } + } + } + impl From> for () { + fn from(_: RawEvent) -> () { + () + } + } + impl RawEvent { + #[allow(dead_code)] + #[doc(hidden)] + pub fn metadata() -> &'static [::frame_support::event::EventMetadata] { + &[ + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("SolutionStored"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&[ + "ElectionCompute", + ]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" A solution was sot", + ]), + }, + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("ElectionFinalized"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&[ + "Option", + ]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[]), + }, + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("Rewarded"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[]), + }, + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("Slashed"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[]), + }, + ] + } + } + pub enum PalletError { + #[doc(hidden)] + __Ignore( + ::frame_support::sp_std::marker::PhantomData<(T,)>, + ::frame_support::Never, + ), + EarlySubmission, + QueueFull, + SubmissionQueuedFull, + CannotPayDeposit, + } + impl ::frame_support::sp_std::fmt::Debug for PalletError { + fn fmt( + &self, + f: &mut ::frame_support::sp_std::fmt::Formatter<'_>, + ) -> ::frame_support::sp_std::fmt::Result { + f.write_str(self.as_str()) + } + } + impl PalletError { + fn as_u8(&self) -> u8 { + match self { + PalletError::__Ignore(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"`__Ignore` can never be constructed",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + PalletError::EarlySubmission => 0, + PalletError::QueueFull => 0 + 1, + PalletError::SubmissionQueuedFull => 0 + 1 + 1, + PalletError::CannotPayDeposit => 0 + 1 + 1 + 1, + } + } + fn as_str(&self) -> &'static str { + match self { + Self::__Ignore(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"`__Ignore` can never be constructed",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + PalletError::EarlySubmission => "EarlySubmission", + PalletError::QueueFull => "QueueFull", + PalletError::SubmissionQueuedFull => "SubmissionQueuedFull", + PalletError::CannotPayDeposit => "CannotPayDeposit", + } + } + } + impl From> for &'static str { + fn from(err: PalletError) -> &'static str { + err.as_str() + } + } + impl From> for ::frame_support::sp_runtime::DispatchError { + fn from(err: PalletError) -> Self { + let index = ::index::>() + .expect("Every active module has an index in the runtime; qed") as u8; + ::frame_support::sp_runtime::DispatchError::Module { + index, + error: err.as_u8(), + message: Some(err.as_str()), + } + } + } + impl ::frame_support::error::ModuleErrorMetadata for PalletError { + fn metadata() -> &'static [::frame_support::error::ErrorMetadata] { + &[ + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("EarlySubmission"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + }, + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("QueueFull"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + }, + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("SubmissionQueuedFull"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + }, + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("CannotPayDeposit"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + }, + ] + } + } + pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>); + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Module { + #[inline] + fn clone(&self) -> Module { + match *self { + Module(ref __self_0_0) => Module(::core::clone::Clone::clone(&(*__self_0_0))), + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for Module {} + impl ::core::marker::StructuralPartialEq for Module {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Module { + #[inline] + fn eq(&self, other: &Module) -> bool { + match *other { + Module(ref __self_1_0) => match *self { + Module(ref __self_0_0) => (*__self_0_0) == (*__self_1_0), + }, + } + } + #[inline] + fn ne(&self, other: &Module) -> bool { + match *other { + Module(ref __self_1_0) => match *self { + Module(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), + }, + } + } + } + impl ::core::marker::StructuralEq for Module {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Module { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq< + ::frame_support::sp_std::marker::PhantomData<(T,)>, + >; + } + } + } + impl core::fmt::Debug for Module + where + T: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_tuple("Module").field(&self.0).finish() + } + } + impl + ::frame_support::traits::OnInitialize<::BlockNumber> for Module + { + fn on_initialize(now: T::BlockNumber) -> Weight { + let __within_span__ = { + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + { + use ::tracing::__macro_support::*; + let callsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "on_initialize", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(250u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + static CALLSITE: MacroCallsite = MacroCallsite::new(&META); + CALLSITE.register(); + &CALLSITE + }; + if callsite.is_enabled() { + let meta = callsite.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + ::tracing::Span::none() + } + } else { + ::tracing::Span::none() + } + }; + let __tracing_guard__ = __within_span__.enter(); + { + let next_election = T::ElectionDataProvider::next_election_prediction(now); + let next_election = next_election.max(now); + let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); + let unsigned_deadline = T::UnsignedPhase::get(); + let remaining = next_election - now; + match Self::current_phase() { + Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { + CurrentPhase::put(Phase::Signed); + Self::start_signed_phase(); + } + Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { + let found_solution = Self::finalize_signed_phase(); + CurrentPhase::put(Phase::Unsigned(!found_solution)); + } + _ => {} + } + Default::default() + } + } + } + impl ::frame_support::traits::OnRuntimeUpgrade for Module {} + impl + ::frame_support::traits::OnFinalize<::BlockNumber> for Module + { + } + impl + ::frame_support::traits::OffchainWorker<::BlockNumber> for Module + { + fn offchain_worker(n: T::BlockNumber) {} + } + impl Module { + /// Deposits an event using `frame_system::Module::deposit_event`. + fn deposit_event(event: impl Into<::Event>) { + >::deposit_event(event.into()) + } + } + #[cfg(feature = "std")] + impl ::frame_support::traits::IntegrityTest for Module {} + /// Can also be called using [`Call`]. + /// + /// [`Call`]: enum.Call.html + impl Module { + /// + /// NOTE: Calling this function will bypass origin filters. + fn submit(origin: T::Origin, solution: RawSolution) -> DispatchResultWithPostInfo { + let __within_span__ = { + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + { + use ::tracing::__macro_support::*; + let callsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "submit", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(250u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + static CALLSITE: MacroCallsite = MacroCallsite::new(&META); + CALLSITE.register(); + &CALLSITE + }; + if callsite.is_enabled() { + let meta = callsite.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + ::tracing::Span::none() + } + } else { + ::tracing::Span::none() + } + }; + let __tracing_guard__ = __within_span__.enter(); + let who = ensure_signed(origin)?; + { + if !Self::current_phase().is_signed() { + { + return Err(PalletError::::EarlySubmission.into()); + }; + } + }; + let queue_size = >::decode_len().unwrap_or_default() as u32; + { + if !(queue_size <= T::MaxSignedSubmissions::get()) { + { + return Err(PalletError::::SubmissionQueuedFull.into()); + }; + } + }; + let mut signed_submissions = Self::signed_submissions(); + let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution); + { + if !maybe_index.is_some() { + { + return Err(PalletError::::QueueFull.into()); + }; + } + }; + let index = maybe_index.expect("Option checked to be `Some`; qed."); + let deposit = signed_submissions[index].deposit; + T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; + if true { + if !(signed_submissions.len() as u32 == queue_size + 1 + || signed_submissions.len() as u32 == T::MaxSignedSubmissions::get()) + { + { + :: std :: rt :: begin_panic ( "assertion failed: signed_submissions.len() as u32 == queue_size + 1 ||\n signed_submissions.len() as u32 == T::MaxSignedSubmissions::get()" ) + } + }; + }; + >::put(signed_submissions); + Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Signed)); + Ok(None.into()) + } + #[allow(unreachable_code)] + /// + /// NOTE: Calling this function will bypass origin filters. + fn submit_unsigned( + origin: T::Origin, + solution: RawSolution, + ) -> ::frame_support::dispatch::DispatchResult { + let __within_span__ = { + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + { + use ::tracing::__macro_support::*; + let callsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "submit_unsigned", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(250u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + static CALLSITE: MacroCallsite = MacroCallsite::new(&META); + CALLSITE.register(); + &CALLSITE + }; + if callsite.is_enabled() { + let meta = callsite.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + ::tracing::Span::none() + } + } else { + ::tracing::Span::none() + } + }; + let __tracing_guard__ = __within_span__.enter(); + { + ensure_none(origin)?; + Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); + { + ::std::rt::begin_panic("not implemented") + } + } + Ok(()) + } + } + /// Dispatchable calls. + /// + /// Each variant of this enum maps to a dispatchable function from the associated module. + pub enum Call { + #[doc(hidden)] + #[codec(skip)] + __PhantomItem( + ::frame_support::sp_std::marker::PhantomData<(T,)>, + ::frame_support::Never, + ), + #[allow(non_camel_case_types)] + submit(RawSolution), + #[allow(non_camel_case_types)] + submit_unsigned(RawSolution), + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for Call { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + Call::submit(ref aa) => { + dest.push_byte(0usize as u8); + dest.push(aa); + } + Call::submit_unsigned(ref aa) => { + dest.push_byte(1usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for Call {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for Call { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(Call::submit({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field Call :: submit.0".into()), + Ok(a) => a, + } + })), + x if x == 1usize as u8 => Ok(Call::submit_unsigned({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field Call :: submit_unsigned.0".into()) + } + Ok(a) => a, + } + })), + x => Err("No such variant in enum Call".into()), + } + } + } + }; + impl ::frame_support::dispatch::GetDispatchInfo for Call { + fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { + match *self { + Call::submit(ref solution) => { + let base_weight = 0; + let weight = + >::weigh_data( + &base_weight, + (solution,), + ); + let class = < dyn :: frame_support :: dispatch :: ClassifyDispatch < ( & RawSolution , ) > > :: classify_dispatch ( & base_weight , ( solution , ) ) ; + let pays_fee = + >::pays_fee( + &base_weight, + (solution,), + ); + ::frame_support::dispatch::DispatchInfo { + weight, + class, + pays_fee, + } + } + Call::submit_unsigned(ref solution) => { + let base_weight = 0; + let weight = + >::weigh_data( + &base_weight, + (solution,), + ); + let class = < dyn :: frame_support :: dispatch :: ClassifyDispatch < ( & RawSolution , ) > > :: classify_dispatch ( & base_weight , ( solution , ) ) ; + let pays_fee = + >::pays_fee( + &base_weight, + (solution,), + ); + ::frame_support::dispatch::DispatchInfo { + weight, + class, + pays_fee, + } + } + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__PhantomItem should never be used.",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + } + } + impl ::frame_support::dispatch::GetCallName for Call { + fn get_call_name(&self) -> &'static str { + match *self { + Call::submit(ref solution) => { + let _ = (solution); + "submit" + } + Call::submit_unsigned(ref solution) => { + let _ = (solution); + "submit_unsigned" + } + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__PhantomItem should never be used.",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + } + fn get_call_names() -> &'static [&'static str] { + &["submit", "submit_unsigned"] + } + } + impl ::frame_support::dispatch::Clone for Call { + fn clone(&self) -> Self { + match *self { + Call::submit(ref solution) => Call::submit((*solution).clone()), + Call::submit_unsigned(ref solution) => Call::submit_unsigned((*solution).clone()), + _ => ::std::rt::begin_panic("internal error: entered unreachable code"), + } + } + } + impl ::frame_support::dispatch::PartialEq for Call { + fn eq(&self, _other: &Self) -> bool { + match *self { + Call::submit(ref solution) => { + let self_params = (solution,); + if let Call::submit(ref solution) = *_other { + self_params == (solution,) + } else { + match *_other { + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic("internal error: entered unreachable code") + } + _ => false, + } + } + } + Call::submit_unsigned(ref solution) => { + let self_params = (solution,); + if let Call::submit_unsigned(ref solution) = *_other { + self_params == (solution,) + } else { + match *_other { + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic("internal error: entered unreachable code") + } + _ => false, + } + } + } + _ => ::std::rt::begin_panic("internal error: entered unreachable code"), + } + } + } + impl ::frame_support::dispatch::Eq for Call {} + impl ::frame_support::dispatch::fmt::Debug for Call { + fn fmt( + &self, + _f: &mut ::frame_support::dispatch::fmt::Formatter, + ) -> ::frame_support::dispatch::result::Result<(), ::frame_support::dispatch::fmt::Error> { + match *self { + Call::submit(ref solution) => _f.write_fmt(::core::fmt::Arguments::new_v1( + &["", ""], + &match (&"submit", &(solution.clone(),)) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), + ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), + ], + }, + )), + Call::submit_unsigned(ref solution) => { + _f.write_fmt(::core::fmt::Arguments::new_v1( + &["", ""], + &match (&"submit_unsigned", &(solution.clone(),)) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), + ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), + ], + }, + )) + } + _ => ::std::rt::begin_panic("internal error: entered unreachable code"), + } + } + } + impl ::frame_support::traits::UnfilteredDispatchable for Call { + type Origin = T::Origin; + fn dispatch_bypass_filter( + self, + _origin: Self::Origin, + ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { + match self { + Call::submit(solution) => >::submit(_origin, solution) + .map(Into::into) + .map_err(Into::into), + Call::submit_unsigned(solution) => >::submit_unsigned(_origin, solution) + .map(Into::into) + .map_err(Into::into), + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__PhantomItem should never be used.",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + } + } + impl ::frame_support::dispatch::Callable for Module { + type Call = Call; + } + impl Module { + #[doc(hidden)] + #[allow(dead_code)] + pub fn call_functions() -> &'static [::frame_support::dispatch::FunctionMetadata] { + &[ + ::frame_support::dispatch::FunctionMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("submit"), + arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + ::frame_support::dispatch::FunctionArgumentMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), + ty: ::frame_support::dispatch::DecodeDifferent::Encode("RawSolution"), + }, + ]), + documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[]), + }, + ::frame_support::dispatch::FunctionMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("submit_unsigned"), + arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + ::frame_support::dispatch::FunctionArgumentMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), + ty: ::frame_support::dispatch::DecodeDifferent::Encode("RawSolution"), + }, + ]), + documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[]), + }, + ] + } + } + impl Module { + #[doc(hidden)] + #[allow(dead_code)] + pub fn module_constants_metadata( + ) -> &'static [::frame_support::dispatch::ModuleConstantMetadata] { + &[] + } + } + impl ::frame_support::dispatch::ModuleErrorMetadata for Module { + fn metadata() -> &'static [::frame_support::dispatch::ErrorMetadata] { + <&'static str as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() + } + } + pub enum FeasibilityError { + /// Wrong number of winners presented. + WrongWinnerCount, + /// The snapshot is not available. + /// + /// This must be an internal error of the chain. + SnapshotUnavailable, + /// Internal error from the election crate. + NposElectionError(sp_npos_elections::Error), + /// A vote is invalid. + InvalidVote, + /// A voter is invalid. + InvalidVoter, + /// A winner is invalid. + InvalidWinner, + /// The given score was invalid. + InvalidScore, + } + impl From for FeasibilityError { + fn from(e: sp_npos_elections::Error) -> Self { + FeasibilityError::NposElectionError(e) + } + } + impl Module { + /// Checks the feasibility of a solution. + fn feasibility_check( + solution: RawSolution, + compute: ElectionCompute, + ) -> Result, FeasibilityError> { + let RawSolution { + winners, + compact, + score, + } = solution; + { + if !(compact.unique_targets().len() == winners.len()) { + { + return Err(FeasibilityError::WrongWinnerCount.into()); + }; + } + }; + { + if !(winners.len() as u32 == Self::desired_targets()) { + { + return Err(FeasibilityError::WrongWinnerCount.into()); + }; + } + }; + let snapshot_voters = + Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; + let snapshot_targets = + Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; + let voter_at = |i: VoterIndex| -> Option { + snapshot_voters.get(i as usize).map(|(x, _, _)| x).cloned() + }; + let target_at = |i: TargetIndex| -> Option { + snapshot_targets.get(i as usize).cloned() + }; + let winners = winners + .into_iter() + .map(|i| target_at(i).ok_or(FeasibilityError::InvalidWinner)) + .collect::, FeasibilityError>>()?; + let assignments = compact + .into_assignment(voter_at, target_at) + .map_err::(Into::into)?; + let _ = assignments + .iter() + .map(|Assignment { who, distribution }| { + snapshot_voters.iter().find(|(v, _, _)| v == who).map_or( + Err(FeasibilityError::InvalidVoter), + |(_, _, t)| { + if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) + && T::ElectionDataProvider::feasibility_check_assignment::< + OffchainAccuracy, + >(who, distribution) + { + Ok(()) + } else { + Err(FeasibilityError::InvalidVote) + } + }, + ) + }) + .collect::>()?; + let stake_of = |who: &T::AccountId| -> crate::VoteWeight { + snapshot_voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + }; + use sp_npos_elections::{assignment_ratio_to_staked_normalized, build_support_map}; + let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) + .map_err::(Into::into)?; + let supports = build_support_map(&winners, &staked_assignments) + .map_err::(Into::into)?; + let known_score = evaluate_support(&supports); + { + if !(known_score == score) { + { + return Err(FeasibilityError::InvalidScore.into()); + }; + } + }; + let supports = supports.flatten(); + Ok(ReadySolution { + winners, + supports, + compute, + }) + } + fn onchain_fallback() -> Result, crate::Error> { + let desired_targets = Self::desired_targets() as usize; + let voters = Self::snapshot_voters().ok_or(crate::Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(crate::Error::SnapshotUnAvailable)?; + >::elect::( + desired_targets, + targets, + voters, + ) + } + } + impl crate::ElectionProvider for Module { + fn elect( + _to_elect: usize, + _targets: Vec, + _voters: Vec<(T::AccountId, VoteWeight, Vec)>, + ) -> Result, crate::Error> + where + ExtendedBalance: From<

::Inner>, + P: sp_std::ops::Mul, + { + Self::queued_solution() + .map_or_else( + || Self::onchain_fallback().map(|r| (r, ElectionCompute::OnChain)), + |ReadySolution { + supports, compute, .. + }| Ok((supports, compute)), + ) + .map(|(supports, compute)| { + CurrentPhase::put(Phase::Off); + >::kill(); + >::kill(); + Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); + supports + }) + .map_err(|err| { + Self::deposit_event(RawEvent::ElectionFinalized(None)); + err + }) + } + fn ongoing() -> bool { + match Self::current_phase() { + Phase::Signed | Phase::Unsigned(_) => true, + _ => false, + } + } + } +} +use sp_arithmetic::PerThing; +#[doc(hidden)] +pub use sp_npos_elections::VoteWeight; +use sp_npos_elections::{ExtendedBalance, FlatSupportMap}; +use sp_runtime::RuntimeDebug; +#[doc(hidden)] +pub use sp_std::convert::TryInto; +/// A bridge between the entity requesting a long-lasting election from something that implements +/// [`ElectionProvider`], such as the [`two_phase`] module. +pub trait ElectionDataProvider { + fn targets() -> Vec; + fn voters() -> Vec<(AccountId, VoteWeight, Vec)>; + fn desired_targets() -> u32; + fn feasibility_check_assignment( + who: &AccountId, + distribution: &[(AccountId, P)], + ) -> bool; + fn next_election_prediction(now: B) -> B; +} +#[cfg(feature = "std")] +impl ElectionDataProvider for () { + fn targets() -> Vec { + Default::default() + } + fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { + Default::default() + } + fn desired_targets() -> u32 { + Default::default() + } + fn feasibility_check_assignment(_: &AccountId, _: &[(AccountId, P)]) -> bool { + Default::default() + } + fn next_election_prediction(_: B) -> B { + Default::default() + } +} +/// Something that can compute the result of an election and pass it back to a pallet. +pub trait ElectionProvider { + /// Elect a new set of winners. + /// + /// The result is returned in a target major format, namely as a support map. + fn elect( + to_elect: usize, + targets: Vec, + voters: Vec<(AccountId, VoteWeight, Vec)>, + ) -> Result, Error> + where + ExtendedBalance: From<

::Inner>, + P: sp_std::ops::Mul; + /// Returns true if an election is still ongoing. + fn ongoing() -> bool; +} +pub enum Error { + ElectionFailed, + SnapshotUnAvailable, + Internal(sp_npos_elections::Error), +} +impl core::fmt::Debug for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::ElectionFailed => fmt.debug_tuple("Error::ElectionFailed").finish(), + Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), + Self::Internal(ref a0) => fmt.debug_tuple("Error::Internal").field(a0).finish(), + _ => Ok(()), + } + } +} +impl ::core::marker::StructuralEq for Error {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } +} +impl ::core::marker::StructuralPartialEq for Error {} +#[automatically_derived] +#[allow(unused_qualifications)] +impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Internal(ref __self_0), &Error::Internal(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Internal(ref __self_0), &Error::Internal(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + _ => false, + } + } else { + true + } + } + } +} +impl From for Error { + fn from(err: sp_npos_elections::Error) -> Self { + Error::Internal(err) + } +} diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs index a190b83876632..193f9e798c057 100644 --- a/frame/election-providers/src/lib.rs +++ b/frame/election-providers/src/lib.rs @@ -1,12 +1,44 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Reusable Election Providers. +//! +//! The core functionality of this crate is around [`ElectionProvider`]. An election provider is a +//! struct, module, or anything else that implements [`ElectionProvider`]. Such types can then be +//! passed around to other crates and pallets that need election functionality. +//! +//! Two main election providers are implemented in this crate. +//! +//! 1. [`onchain`]: A `struct` that perform the election onchain (i.e. in the fly). This type is +//! likely to be expensive for most chains and damage the block time. Only use when you are sure +//! that the inputs are bounded and small enough. +//! 2. [`two_phase`]: An individual `pallet` that performs the election in two phases, signed and +//! unsigned. Needless to say, the pallet needs to be included in the final runtime. + #![cfg_attr(not(feature = "std"), no_std)] use sp_std::prelude::*; +/// The onchain module. pub mod onchain; +/// The two-phase module. pub mod two_phase; use sp_arithmetic::PerThing; -use sp_npos_elections::{ExtendedBalance, FlatSupportMap}; -use sp_runtime::RuntimeDebug; +use sp_npos_elections::{ExtendedBalance, Support, SupportMap}; // for the helper macros #[doc(hidden)] @@ -14,10 +46,73 @@ pub use sp_npos_elections::VoteWeight; #[doc(hidden)] pub use sp_std::convert::TryInto; +/// A flat variant of [`sp_npos_elections::SupportMap`]. +/// +/// The main advantage of this is that it is encodable. +pub type FlatSupportMap = Vec<(A, Support)>; + +/// Helper trait to convert from a support map to a flat support vector. +pub trait FlattenSupportMap { + fn flatten(self) -> FlatSupportMap; +} + +impl FlattenSupportMap for SupportMap { + fn flatten(self) -> FlatSupportMap { + self.into_iter().map(|(k, v)| (k, v)).collect::>() + } +} + +/// Something that can provide the data to something else that implements [`ElectionProvider`], such +/// as the [`two_phase`] module. +/// +/// The underlying purpose of this is to provide auxillary data to long-lasting election providers. +/// For example, the [`two_phase`] election provider needs to know the voters/targets list well in +/// advance and before a call to [`ElectionProvider::elect`]. +/// +/// For example, if pallet A wants to use the two-phase election: +/// +/// ```rust,ignore +/// pub trait TraitA { +/// type ElectionProvider: ElectionProvider<_, _>; +/// } +/// +/// // these function will be called by `Self::ElectionProvider` whenever needed. +/// impl ElectionDataProvider for PalletA { /* .. */ } +/// +/// impl Module { +/// fn do_election() { +/// // finalize the election. +/// T::ElectionProvider::elect( /* .. */ ); +/// } +/// } +/// ``` pub trait ElectionDataProvider { + type CompactSolution: codec::Codec + Default + PartialEq + Eq; + /// All possible targets for the election, i.e. the candidates. fn targets() -> Vec; + + /// All possible voters for the election. + /// + /// Note that if a notion of self-vote exists, it should be represented here. fn voters() -> Vec<(AccountId, VoteWeight, Vec)>; + + /// The number of targets to elect. fn desired_targets() -> u32; + + /// Check the feasibility of a single assignment for the underlying `ElectionProvider`. In other + /// words, check if `who` having a weight distribution described as `distribution` is correct or + /// not. + /// + /// This might be called by the [`ElectionProvider`] upon processing solutions. + fn feasibility_check_assignment( + who: &AccountId, + distribution: &[(AccountId, P)], + ) -> bool; + + /// Provide a best effort prediction about when the next election is about to happen. + /// + /// In essence, `Self` should predict with this function when it will trigger the + /// `ElectionDataProvider::elect`. fn next_election_prediction(now: B) -> B; } @@ -32,21 +127,34 @@ impl ElectionDataProvider for () { fn desired_targets() -> u32 { Default::default() } + fn feasibility_check_assignment(_: &AccountId, _: &[(AccountId, P)]) -> bool { + Default::default() + } fn next_election_prediction(_: B) -> B { Default::default() } } -/// Something that can compute the result of an election and pass it back to a pallet. +/// Something that can compute the result of an election and pass it back to the caller. pub trait ElectionProvider { + /// Indicate weather this election provider needs data when calling [`elect`] or not. + const NEEDS_ELECT_DATA: bool; + + /// The error type that is returned by the provider. + type Error; + /// Elect a new set of winners. /// /// The result is returned in a target major format, namely as a support map. + /// + /// Note that based on the logic of the type that will implement this trait, the input data may + /// or may not be used. To hint about this to the call site, [`NEEDS_ELECT_DATA`] should be + /// properly set. fn elect( to_elect: usize, // TODO: consider making this u32 targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Error> + ) -> Result, Self::Error> where // TODO: Okay about these two, I get that we probably need the first one, but can't we // alleviate the latter one? I think we can say that all PerThing are Mul of some types. @@ -55,19 +163,8 @@ pub trait ElectionProvider { ExtendedBalance: From<

::Inner>, P: sp_std::ops::Mul; - /// Returns true if an election is still ongoing. + /// Returns true if an election is still ongoing. This can be used by the call site to + /// dynamically check of a long-lasting election (such as [`two_phase`]) is still on-going or + /// not. fn ongoing() -> bool; } - -#[derive(RuntimeDebug, Eq, PartialEq)] -pub enum Error { - ElectionFailed, - SnapshotUnAvailable, - Internal(sp_npos_elections::Error), -} - -impl From for Error { - fn from(err: sp_npos_elections::Error) -> Self { - Error::Internal(err) - } -} diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs index 43ed95e866c76..1d839b7c741ea 100644 --- a/frame/election-providers/src/onchain.rs +++ b/frame/election-providers/src/onchain.rs @@ -1,15 +1,33 @@ -use crate::{ElectionProvider, Error}; +use crate::{ElectionProvider, FlatSupportMap, FlattenSupportMap}; use sp_arithmetic::PerThing; -use sp_npos_elections::{ElectionResult, ExtendedBalance, FlatSupportMap, IdentifierT, VoteWeight}; +use sp_npos_elections::{ElectionResult, ExtendedBalance, IdentifierT, VoteWeight}; +use sp_runtime::RuntimeDebug; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; +/// Errors of the on-chain election. +#[derive(RuntimeDebug, Eq, PartialEq)] +pub enum Error { + /// An internal error in the NPoS elections crate. + NposElections(sp_npos_elections::Error), +} + +impl From for Error { + fn from(e: sp_npos_elections::Error) -> Self { + Error::NposElections(e) + } +} + pub struct OnChainSequentialPhragmen; impl ElectionProvider for OnChainSequentialPhragmen { + type Error = Error; + + const NEEDS_ELECT_DATA: bool = true; + fn elect( to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, P: sp_std::ops::Mul, @@ -42,7 +60,7 @@ impl ElectionProvider for OnChainSequentialPh let winners = sp_npos_elections::to_without_backing(winners); sp_npos_elections::build_support_map(&winners, &staked) - .map(|s| s.into_iter().map(|(k, v)| (k, v)).collect::>()) + .map(|s| s.flatten()) }) .map_err(From::from) } diff --git a/frame/election-providers/src/two_phase/macros.rs b/frame/election-providers/src/two_phase/macros.rs new file mode 100644 index 0000000000000..c75fd67b28d2f --- /dev/null +++ b/frame/election-providers/src/two_phase/macros.rs @@ -0,0 +1,66 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Some helper macros for this crate. + +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + frame_support::debug::$level!( + target: crate::LOG_TARGET, + $patter $(, $values)* + ) + }; +} + +#[macro_export] +macro_rules! voter_index_fn { + ($voters:ident, $acc:ty) => { + |who: &$acc| -> Option<$crate::two_phase::VoterIndex> { + $voters + .iter() + .position(|(x, _, _)| x == who) + .and_then(|i| >::try_into(i).ok()) + } + }; +} + +#[macro_export] +macro_rules! target_index_fn { + ($targets:ident, $acc:ty) => { + |who: &$acc| -> Option<$crate::two_phase::TargetIndex> { + $targets + .iter() + .position(|x| x == who) + .and_then(|i| >::try_into(i).ok()) + } + }; +} + +// TODO: these can use a cache. +#[macro_export] +macro_rules! stake_of_fn { + ($voters:ident, $acc:ty) => { + |who: &$acc| -> $crate::VoteWeight { + $voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + } + }; +} diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index cd663333b36eb..70b52e278d5c6 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -1,7 +1,6 @@ use super::*; -use frame_support::{parameter_types, traits::OnInitialize, weights::Weight}; +use frame_support::{parameter_types, traits::OnInitialize}; use sp_core::H256; -use sp_npos_elections::FlatSupportMap; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, @@ -35,14 +34,14 @@ pub fn balances(who: &AccountId) -> (Balance, Balance) { /// Spit out a verifiable raw solution. /// /// This is a good example of what an offchain miner would do. -pub fn raw_solution() -> RawSolution { +pub fn raw_solution() -> RawSolution { let voters = TwoPhase::snapshot_voters().unwrap(); let targets = TwoPhase::snapshot_targets().unwrap(); let desired = TwoPhase::desired_targets() as usize; // closures - let voter_at = crate::voter_at_fn!(voters, AccountId); - let target_at = crate::target_at_fn!(targets, AccountId); + let voter_index = crate::voter_index_fn!(voters, AccountId); + let target_index = crate::target_index_fn!(targets, AccountId); let stake_of = crate::stake_of_fn!(voters, AccountId); use sp_npos_elections::{seq_phragmen, to_without_backing, ElectionResult}; @@ -59,11 +58,16 @@ pub fn raw_solution() -> RawSolution { let support = sp_npos_elections::build_support_map(&winners, &staked).unwrap(); sp_npos_elections::evaluate_support(&support) }; - let compact = CompactAssignments::from_assignment(assignments, &voter_at, &target_at).unwrap(); + let compact = + CompactAssignments::from_assignment(assignments, &voter_index, &target_index).unwrap(); + let winners = winners + .into_iter() + .map(|w| target_index(&w).unwrap()) + .collect::>(); RawSolution { - compact, winners, + compact, score, } } @@ -170,22 +174,7 @@ parameter_types_thread_local! { ]; static DESIRED_TARGETS: u32 = 2; static SIGNED_DEPOSIT_BASE: Balance = 5; - static SIGNED_REWARD_BASE: Balance = 5; -} - -impl crate::ElectionDataProvider for ExtBuilder { - fn targets() -> Vec { - Targets::get() - } - fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { - Voters::get() - } - fn desired_targets() -> u32 { - DesiredTargets::get() - } - fn next_election_prediction(now: u64) -> u64 { - now + 20 - now % 20 - } + static SIGNED_REWARD_BASE: Balance = 7; } impl crate::two_phase::Trait for Runtime { @@ -207,21 +196,43 @@ impl crate::two_phase::Trait for Runtime { } pub struct ExtBuilder { - signed_phase: u64, - unsigned_phase: u64, + max_signed_submissions: u32, } impl Default for ExtBuilder { fn default() -> Self { Self { - signed_phase: SignedPhase::get(), - unsigned_phase: UnsignedPhase::get(), + max_signed_submissions: MaxSignedSubmissions::get(), } } } +impl crate::ElectionDataProvider for ExtBuilder { + fn targets() -> Vec { + Targets::get() + } + fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { + Voters::get() + } + fn desired_targets() -> u32 { + DesiredTargets::get() + } + fn feasibility_check_assignment(_: &AccountId, _: &[(AccountId, P)]) -> bool { + true + } + fn next_election_prediction(now: u64) -> u64 { + now + 20 - now % 20 + } +} + impl ExtBuilder { - fn set_constants(&self) {} + fn set_constants(&self) { + MAX_SIGNED_SUBMISSIONS.with(|v| *v.borrow_mut() = self.max_signed_submissions) + } + pub(crate) fn max_signed_submission(mut self, count: u32) -> Self { + self.max_signed_submissions = count; + self + } pub fn build_and_execute(self, test: impl FnOnce() -> ()) { self.set_constants(); let mut storage = frame_system::GenesisConfig::default() @@ -229,7 +240,12 @@ impl ExtBuilder { .unwrap(); let _ = pallet_balances::GenesisConfig:: { - balances: vec![(99, 100)], + balances: vec![ + // bunch of account for submitting stuff only. + (99, 100), + (999, 100), + (9999, 100), + ], } .assimilate_storage(&mut storage); diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 79a953bb90b7a..efdf994706ee7 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -1,4 +1,108 @@ -use crate::{onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, Error}; +// This file is part of Substrate. + +// Copyright (C) 2020 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Two phase election provider pallet. +//! +//! As the name suggests, this election provider has two distinct phases (see [`Phase`]), signed and +//! unsigned. +//! +//! ## Phases +//! +//! The timeline of pallet is as follows. At each block, +//! [`ElectionDataProvider::next_election_prediction`] is used to estimate the time remaining to the +//! next call to `elect`. Based on this, a phase is chosen. The timeline is as follows. +//! +//! ```ignore +//! elect() +//! + <--T::SignedPhase--> + <--T::UnsignedPhase--> + +//! +-------------------------------------------------------------------+ +//! Phase::Off + Phase::Signed + Phase::Unsigned + +//! +//! Note that the unsigned phase starts `T::UnsignedPhase` blocks before the +//! `next_election_prediction`, but only ends when a call to `ElectionProvider::elect` happens. +//! +//! ``` +//! ### Signed Phase +//! +//! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A +//! deposit is reserved, based on the size of the solution, for the cost of keeping this solution +//! on-chain for a number of blocks. A maximum of [`Trait::MaxSignedSubmissions`] solutions are +//! stored. The queue is always sorted based on score (worse -> best). +//! +//! Upon arrival of a new solution: +//! +//! 1. If the queue is not full, it is stored. +//! 2. If the queue is full but the submitted solution is better than one of the queued ones, the +//! worse solution is discarded (TODO: what to do with the bond?) and the new solution is stored +//! in the correct index. +//! 3. If the queue is full and the solution is not an improvement compared to any of the queued +//! ones, it is instantly rejected and no additional bond is reserved. +//! +//! A signed solution cannot be reversed, taken back, updated, or retracted. In other words, the +//! origin can not bail out in any way. +//! +//! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed +//! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure +//! the score claimed by this score was correct, among other checks. At each step, if the current +//! best solution is passes the feasibility check, it is considered to be the best one. The sender +//! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without +//! being checked. +//! +//! The following example covers all of the cases at the end of the signed phase: +//! +//! ```ignore +//! Queue +//! +-------------------------------+ +//! |Solution(score=20, valid=false)| +--> Slashed +//! +-------------------------------+ +//! |Solution(score=15, valid=true )| +--> Rewarded +//! +-------------------------------+ +//! |Solution(score=10, valid=true )| +--> Discarded +//! +-------------------------------+ +//! |Solution(score=05, valid=false)| +--> Discarded +//! +-------------------------------+ +//! | None | +//! +-------------------------------+ +//! ``` +//! +//! Note that both of the bottom solutions end up being discarded and get their deposit back, +//! despite one of them being invalid. +//! +//! ## Unsigned Phase +//! +//! If signed phase ends with a good solution, then the unsigned phase will be `active` +//! ([`Phase::Unsigned(true)`]), else the unsigned phase will be `passive`. +//! +//! TODO +//! +//! ### Fallback +//! +//! If we reach the end of both phases (i.e. call to `ElectionProvider::elect` happens) and no good +//! solution is queued, then we fallback to an on-chain election. The on-chain election is slow, and +//! contains to balancing or reduction post-processing. +//! +//! ## Correct Submission +//! +//! TODO + +use crate::{ + onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, FlatSupportMap, + FlattenSupportMap, +}; use codec::{Decode, Encode, HasCompact}; use frame_support::{ decl_error, decl_event, decl_module, decl_storage, @@ -9,7 +113,7 @@ use frame_support::{ }; use frame_system::{ensure_none, ensure_signed}; use sp_npos_elections::{ - generate_solution_type, is_score_better, ElectionScore, ExtendedBalance, FlatSupportMap, + evaluate_support, generate_solution_type, Assignment, ElectionScore, ExtendedBalance, VoteWeight, }; use sp_runtime::{traits::Zero, PerThing, PerU16, Perbill, RuntimeDebug}; @@ -17,6 +121,9 @@ use sp_std::{mem::size_of, prelude::*}; #[cfg(test)] mod mock; +#[macro_use] +pub(crate) mod macros; + pub mod signed; pub mod unsigned; @@ -34,10 +141,10 @@ pub type ChainAccuracy = Perbill; /// Accuracy used for off-chain election. This better be small. pub type OffchainAccuracy = PerU16; -/// Data type used to index nominators in the compact type. +/// Data type used to index voter in the compact type. pub type VoterIndex = u32; -/// Data type used to index validators in the compact type. +/// Data type used to index target in the compact type. pub type TargetIndex = u16; // Ensure the size of both TargetIndex and VoterIndex. They both need to be well below usize. @@ -52,49 +159,16 @@ generate_solution_type!( pub struct CompactAssignments::(16) ); -#[macro_export] -macro_rules! voter_at_fn { - ($voters:ident, $acc:ty) => { - |who: &$acc| -> Option<$crate::two_phase::VoterIndex> { - $voters - .iter() - .position(|(x, _, _)| x == who) - .and_then(|i| >::try_into(i).ok()) - } - }; -} - -#[macro_export] -macro_rules! target_at_fn { - ($targets:ident, $acc:ty) => { - |who: &$acc| -> Option<$crate::two_phase::TargetIndex> { - $targets - .iter() - .position(|x| x == who) - .and_then(|i| >::try_into(i).ok()) - } - }; -} - -// TODO: these can use a cache. -// TODO: move these to test if they are not used.. They most likely will be used in offchain. -#[macro_export] -macro_rules! stake_of_fn { - ($voters:ident, $acc:ty) => { - |who: &$acc| -> $crate::VoteWeight { - $voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - } - }; -} +const LOG_TARGET: &'static str = "two-phase-submission"; +/// Current phase of the pallet. #[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] pub enum Phase { + /// Nothing, the election is not happening. Off, + /// Signed phase is open. Signed, + /// Unsigned phase is open. Unsigned(bool), } @@ -105,79 +179,164 @@ impl Default for Phase { } impl Phase { + /// Weather the phase is signed or not. pub fn is_signed(&self) -> bool { matches!(self, Phase::Signed) } + /// Weather the phase is unsigned or not. pub fn is_unsigned(&self) -> bool { matches!(self, Phase::Unsigned(_)) } + /// Weather the phase is unsigned and open or not. pub fn is_unsigned_open(&self) -> bool { matches!(self, Phase::Unsigned(true)) } + /// Weather the phase is off or not. pub fn is_off(&self) -> bool { matches!(self, Phase::Off) } } +/// The type of `Computation` that provided this election data. #[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] pub enum ElectionCompute { + /// Election was computed on-chain. OnChain, + /// Election was computed with a signed submission. Signed, + /// Election was computed with an unsigned submission. Unsigned, } +impl Default for ElectionCompute { + fn default() -> Self { + ElectionCompute::OnChain + } +} + +/// A raw, unchecked solution. +/// +/// Such a solution should never become effective in anyway before being checked by the +/// [`Module::feasibility_check`] #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] -pub struct RawSolution { - winners: Vec, +pub struct RawSolution { + /// The winners indices. + winners: Vec, + /// Compact election edges. compact: CompactAssignments, + /// The _claimed_ score of the solution. score: ElectionScore, } +/// A raw, unchecked signed submission. +/// +/// This is just a wrapper around [`RawSolution`] and some additional info. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] pub struct SignedSubmission { + /// Who submitted this solution. who: AccountId, + /// The deposit reserved for storing this solution. deposit: Balance, + /// The reward that should be given to this solution, if chosen the as the final one. reward: Balance, - solution: RawSolution, + /// The raw solution itself. + solution: RawSolution, } -/// A parsed solution, ready to be enacted. +/// A checked and parsed solution, ready to be enacted. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] pub struct ReadySolution { - winners: Vec, + /// The final supports of the solution. This is target-major vector, storing each winners, total + /// backing, and each individual backer. supports: FlatSupportMap, + /// How this election was computed. + compute: ElectionCompute, +} + +/// The crate errors. Note that this is different from the [`PalletError`]. +#[derive(RuntimeDebug, Eq, PartialEq)] +pub enum Error { + /// A feasibility error. + Feasibility(FeasibilityError), + /// An error in the on-chain fallback. + OnChainFallback(crate::onchain::Error), + /// Snapshot data was unavailable unexpectedly. + SnapshotUnAvailable, +} + +impl From for Error { + fn from(e: crate::onchain::Error) -> Self { + Error::OnChainFallback(e) + } +} + +/// Errors that can happen in the feasibility check. +#[derive(RuntimeDebug, Eq, PartialEq)] +pub enum FeasibilityError { + /// Wrong number of winners presented. + WrongWinnerCount, + /// The snapshot is not available. + /// + /// This must be an internal error of the chain. + SnapshotUnavailable, + /// Internal error from the election crate. + NposElectionError(sp_npos_elections::Error), + /// A vote is invalid. + InvalidVote, + /// A voter is invalid. + InvalidVoter, + /// A winner is invalid. + InvalidWinner, + /// The given score was invalid. + InvalidScore, +} + +impl From for FeasibilityError { + fn from(e: sp_npos_elections::Error) -> Self { + FeasibilityError::NposElectionError(e) + } } +/// The weights for this pallet. pub trait WeightInfo {} impl WeightInfo for () {} pub trait Trait: frame_system::Trait { - type Event: From + Into<::Event>; + /// Event type. + type Event: From> + Into<::Event>; + /// Currency type. type Currency: ReservableCurrency + Currency; + /// Duration of the signed phase. type SignedPhase: Get; + /// Duration of the unsigned phase. type UnsignedPhase: Get; - + /// Maximum number of singed submissions that can be queued. type MaxSignedSubmissions: Get; + // TODO: these need input from the research team type SignedRewardBase: Get>; type SignedRewardFactor: Get; - type SignedDepositBase: Get>; type SignedDepositByte: Get>; type SignedDepositWeight: Get>; + /// The minimum amount of improvement to the solution score that defines a solution as "better". type SolutionImprovementThreshold: Get; + /// Handler for the slashed deposits. type SlashHandler: OnUnbalanced>; + /// Handler for the rewards. type RewardHandler: OnUnbalanced>; + /// Something that will provide the election data. type ElectionDataProvider: ElectionDataProvider; + /// The weight of the pallet. type WeightInfo: WeightInfo; } @@ -186,39 +345,53 @@ decl_storage! { /// Current phase. pub CurrentPhase get(fn current_phase): Phase = Phase::Off; - /// Sorted list of unchecked, signed solutions. + /// Sorted (worse -> best) list of unchecked, signed solutions. pub SignedSubmissions get(fn signed_submissions): Vec>>; - /// Current, best, unsigned solution. + /// Current best solution, signed or unsigned. pub QueuedSolution get(fn queued_solution): Option>; - /// Snapshot of all Voters. The indices if this will be used in election. + /// Snapshot of all Voters. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub SnapshotTargets get(fn snapshot_targets): Option>; - /// Snapshot of all targets. The indices if this will be used in election. + /// Snapshot of all targets. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub SnapshotVoters get(fn snapshot_voters): Option)>>; - /// Desired number of targets to elect + /// Desired number of targets to elect. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub DesiredTargets get(fn desired_targets): u32; } } decl_event!( - pub enum Event { + pub enum Event where ::AccountId { + /// A solution was stored with the given compute. + /// + /// If the solution is signed, this means that it hasn't yet been processed. If the solution + /// is unsigned, this means that it has also been processed. SolutionStored(ElectionCompute), - ElectionFinalized(ElectionCompute), + /// The election has been finalized, with `Some` of the given computation, or else if the + /// election failed, `None`. + ElectionFinalized(Option), + /// An account has been rewarded for their signed submission being finalized. + Rewarded(AccountId), + /// An account has been slashed for submitting an invalid signed submission. + Slashed(AccountId), } ); decl_error! { pub enum PalletError for Module { + /// Submission was too early. EarlySubmission, - LowScoreSubmission, - SubmissionQueuedFull, + /// The queue was full, and the solution was not better than any of the existing ones. + QueueFull, + /// The origin failed to pay the deposit. CannotPayDeposit, } } @@ -229,7 +402,6 @@ decl_module! { fn on_initialize(now: T::BlockNumber) -> Weight { let next_election = T::ElectionDataProvider::next_election_prediction(now); - // TODO: document this invariant. let next_election = next_election.max(now); let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); @@ -252,98 +424,203 @@ decl_module! { } } - Default::default() } - fn offchain_worker(n: T::BlockNumber) { - - } + fn offchain_worker(n: T::BlockNumber) {} + /// Submit a solution for the signed phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// The solution potentially queued, based on the claimed score and processed at the end of + /// the signed phase. + /// + /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution + /// might be rewarded, slashed, or get all or a part of the deposit back. #[weight = 0] - fn submit(origin, solution: RawSolution) -> DispatchResultWithPostInfo { + fn submit(origin, solution: RawSolution) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; // ensure solution is timely. ensure!(Self::current_phase().is_signed(), PalletError::::EarlySubmission); - // ensure queued is not full. - let queue_size = >::decode_len().unwrap_or_default() as u32; - ensure!( - queue_size <= T::MaxSignedSubmissions::get(), - PalletError::::SubmissionQueuedFull, - ); - // ensure solution claims is better. let mut signed_submissions = Self::signed_submissions(); let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution); - ensure!(maybe_index.is_some(), PalletError::::LowScoreSubmission); + ensure!(maybe_index.is_some(), PalletError::::QueueFull); let index = maybe_index.expect("Option checked to be `Some`; qed."); - // ensure... what else? - // TODO - // collect deposit. Thereafter, the function cannot fail. let deposit = signed_submissions[index].deposit; T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; // store the new signed submission. - debug_assert_eq!(signed_submissions.len() as u32, queue_size + 1); + debug_assert!(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()); >::put(signed_submissions); + Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Signed)); Ok(None.into()) } #[weight = 0] - fn submit_unsigned(origin, solution: RawSolution) { + fn submit_unsigned(origin, solution: RawSolution) { ensure_none(origin)?; + Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); unimplemented!() } } } -// General stuff impl Module { + /// Checks the feasibility of a solution. + /// + /// This checks the solution for the following: + /// + /// 0. **all** of the used indices must be correct. + /// 1. present correct number of winners. + /// 2. any assignment is checked to match with `SnapshotVoters`. + /// 3. for each assignment, the check of `ElectionDataProvider` is also examined. + /// 4. the claimed score is valid. fn feasibility_check( - solution: RawSolution, - ) -> Result, ()> { - unimplemented!() + solution: RawSolution, + compute: ElectionCompute, + ) -> Result, FeasibilityError> { + let RawSolution { + winners, + compact, + score, + } = solution; + + // Ensure that the compact and winners have equal number of winners. + ensure!( + compact.unique_targets().len() == winners.len(), + FeasibilityError::WrongWinnerCount + ); + + // Ensure that we have received enough winners. + ensure!( + winners.len() as u32 == Self::desired_targets(), + FeasibilityError::WrongWinnerCount + ); + + // ----- Start building. First, we need some closures. + let snapshot_voters = + Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; + let snapshot_targets = + Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; + + let voter_at = |i: VoterIndex| -> Option { + snapshot_voters.get(i as usize).map(|(x, _, _)| x).cloned() + }; + let target_at = + |i: TargetIndex| -> Option { snapshot_targets.get(i as usize).cloned() }; + + // first, make sure that all the winners are sane. + let winners = winners + .into_iter() + .map(|i| target_at(i).ok_or(FeasibilityError::InvalidWinner)) + .collect::, FeasibilityError>>()?; + + // Then convert compact -> Assignment. + let assignments = compact + .into_assignment(voter_at, target_at) + .map_err::(Into::into)?; + + // Ensure that assignments is correct. We perform two checks: 1. local match against the + // given snapshot, and check with the `ElectionDataProvider`. + let _ = assignments + .iter() + .map(|Assignment { who, distribution }| { + snapshot_voters.iter().find(|(v, _, _)| v == who).map_or( + Err(FeasibilityError::InvalidVoter), + |(_, _, t)| { + if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) + && T::ElectionDataProvider::feasibility_check_assignment::< + OffchainAccuracy, + >(who, distribution) + { + Ok(()) + } else { + Err(FeasibilityError::InvalidVote) + } + }, + ) + }) + .collect::>()?; + + // ----- Start building support. First, we need some more closures. + let stake_of = stake_of_fn!(snapshot_voters, T::AccountId); + + use sp_npos_elections::{assignment_ratio_to_staked_normalized, build_support_map}; + // This might fail if the normalization fails. Very unlikely. + let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) + .map_err::(Into::into)?; + // This might fail if one of the voter edges is pointing to a non-winner. + let supports = build_support_map(&winners, &staked_assignments) + .map_err::(Into::into)?; + + // Finally, check that the claimed score was indeed correct. + // TODO: evaluate support could accept both types of support. + let known_score = evaluate_support(&supports); + ensure!(known_score == score, FeasibilityError::InvalidScore); + + let supports = supports.flatten(); + Ok(ReadySolution { supports, compute }) } - fn onchain_fallback() -> Result, crate::Error> { + /// On-chain fallback of election. + fn onchain_fallback() -> Result, Error> { let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(crate::Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(crate::Error::SnapshotUnAvailable)?; + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; >::elect::( desired_targets, targets, voters, ) + .map_err(Into::into) } } impl crate::ElectionProvider for Module { + type Error = Error; + + const NEEDS_ELECT_DATA: bool = false; + fn elect( _to_elect: usize, _targets: Vec, _voters: Vec<(T::AccountId, VoteWeight, Vec)>, - ) -> Result, crate::Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, P: sp_std::ops::Mul, { Self::queued_solution() .map_or_else( - || Self::onchain_fallback(), - |ReadySolution { supports, .. }| Ok(supports), + || { + Self::onchain_fallback() + .map(|r| (r, ElectionCompute::OnChain)) + .map_err(Into::into) + }, + |ReadySolution { + supports, compute, .. + }| Ok((supports, compute)), ) - .map(|result| { + .map(|(supports, compute)| { // reset phase. CurrentPhase::put(Phase::Off); // clear snapshots. >::kill(); >::kill(); - result + + Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); + supports + }) + .map_err(|err| { + Self::deposit_event(RawEvent::ElectionFinalized(None)); + err }) } @@ -356,7 +633,6 @@ impl crate::ElectionProvider for Module { mod tests { use super::{mock::*, *}; use crate::ElectionProvider; - use frame_support::traits::OnInitialize; use sp_npos_elections::Support; #[test] diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index 0b9defaf71eb6..452e3ac1d170e 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -1,6 +1,26 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The signed phase implementation. + use crate::two_phase::*; use codec::Encode; use sp_arithmetic::traits::SaturatedConversion; +use sp_npos_elections::is_score_better; impl Module { /// Start the signed phase. @@ -11,7 +31,6 @@ impl Module { /// The signed phase must always start before the unsigned phase. pub fn start_signed_phase() { let targets = T::ElectionDataProvider::targets(); - // TODO: this module is not aware at all of self-vote. Clarify this. let voters = T::ElectionDataProvider::voters(); let desired_targets = T::ElectionDataProvider::desired_targets(); @@ -34,8 +53,9 @@ impl Module { deposit, reward, } = best; - match Self::feasibility_check(solution) { + match Self::feasibility_check(solution, ElectionCompute::Signed) { Ok(ready_solution) => { + // write this ready solution. >::put(ready_solution); // unreserve deposit. @@ -61,6 +81,7 @@ impl Module { // Any unprocessed solution is not pointless to even ponder upon. Feasible or malicious, // they didn't end up being used. Unreserve the bonds. all_submission.into_iter().for_each(|not_processed| { + dbg!(¬_processed); let SignedSubmission { who, deposit, .. } = not_processed; let _remaining = T::Currency::unreserve(&who, deposit); debug_assert!(_remaining.is_zero()); @@ -74,11 +95,12 @@ impl Module { pub fn insert_submission( who: &T::AccountId, queue: &mut Vec>>, - solution: RawSolution, + solution: RawSolution, ) -> Option { - use sp_npos_elections::is_score_better; - // consider using VecDeQue or sth like that? + // TODO: consider using VecDeQue or sth like that? + // from the last score, compare and see if the current one is better. If none, then the + // awarded index is 0. let outcome = queue .iter() .enumerate() @@ -100,7 +122,7 @@ impl Module { // if this is worse than all, and the queue is full, don't bother. None } else { - // add to the designated spo. If the length is too much, remove one. + // add to the designated spot. If the length is too much, remove one. let reward = Self::reward_for(&solution); let deposit = Self::deposit_for(&solution); let submission = SignedSubmission { @@ -111,7 +133,7 @@ impl Module { }; // TODO: write proof that this cannot panic queue.insert(at, submission); - if queue.len() as u32 >= T::MaxSignedSubmissions::get() { + if queue.len() as u32 > T::MaxSignedSubmissions::get() { queue.remove(0); Some(at - 1) } else { @@ -124,13 +146,13 @@ impl Module { outcome } - pub fn deposit_for(solution: &RawSolution) -> BalanceOf { + pub fn deposit_for(solution: &RawSolution) -> BalanceOf { let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); // TODO T::SignedDepositBase::get() + T::SignedDepositByte::get() * encoded_len } - pub fn reward_for(solution: &RawSolution) -> BalanceOf { + pub fn reward_for(solution: &RawSolution) -> BalanceOf { T::SignedRewardBase::get() + T::SignedRewardFactor::get() * solution.score[0].saturated_into::>() } @@ -139,7 +161,6 @@ impl Module { #[cfg(test)] mod tests { use super::{mock::*, *}; - use crate::*; #[test] fn cannot_submit_too_early() { @@ -153,7 +174,7 @@ mod tests { assert_noop!( TwoPhase::submit(Origin::signed(10), solution), - PalletError::::EarlySubmission + PalletError::::EarlySubmission, ); }) } @@ -180,16 +201,14 @@ mod tests { roll_to(5); assert_eq!(TwoPhase::current_phase(), Phase::Signed); - let mut solution = raw_solution(); - // cheat here. - solution.score[0] += 1; + let solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); assert_eq!(balances(&99), (95, 5)); assert!(TwoPhase::finalize_signed_phase()); - assert_eq!(balances(&99), (100 + 5, 0)); + assert_eq!(balances(&99), (100 + 7, 0)); }) } @@ -199,16 +218,51 @@ mod tests { roll_to(5); assert_eq!(TwoPhase::current_phase(), Phase::Signed); - let solution = raw_solution(); + let mut solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); + + // make the solution invalid. + solution.score[0] += 1; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); assert_eq!(balances(&99), (95, 5)); - assert!(TwoPhase::finalize_signed_phase()); + // no good solution was stored. + assert!(!TwoPhase::finalize_signed_phase()); + // and the bond is gone. assert_eq!(balances(&99), (95, 0)); }) } + #[test] + fn suppressed_solution_gets_bond_back() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + + let mut solution = raw_solution(); + assert_eq!(balances(&99), (100, 0)); + assert_eq!(balances(&999), (100, 0)); + + // submit as correct. + assert_ok!(TwoPhase::submit(Origin::signed(99), solution.clone())); + + // make the solution invalid and weaker. + solution.score[0] -= 1; + assert_ok!(TwoPhase::submit(Origin::signed(999), solution)); + assert_eq!(balances(&99), (95, 5)); + assert_eq!(balances(&999), (95, 5)); + + // _some_ good solution was stored. + assert!(TwoPhase::finalize_signed_phase()); + + // 99 is rewarded. + assert_eq!(balances(&99), (100 + 7, 0)); + // 999 gets everything back. + assert_eq!(balances(&999), (100, 0)); + }) + } + #[test] fn queue_is_always_sorted() { ExtBuilder::default().build_and_execute(|| { @@ -216,7 +270,7 @@ mod tests { assert_eq!(TwoPhase::current_phase(), Phase::Signed); let solution = RawSolution { - winners: vec![1u64], + winners: vec![1u16], score: [5, 0, 0], ..Default::default() }; @@ -224,7 +278,7 @@ mod tests { // then a worse one. let solution = RawSolution { - winners: vec![2u64], + winners: vec![2u16], score: [4, 0, 0], ..Default::default() }; @@ -232,7 +286,7 @@ mod tests { // then a better one. let solution = RawSolution { - winners: vec![3u64], + winners: vec![3u16], score: [6, 0, 0], ..Default::default() }; @@ -249,25 +303,248 @@ mod tests { } #[test] - fn can_submit_until_queue_full() {} + fn cannot_submit_worse_with_full_queue() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); - #[test] - fn weakest_is_removed_if_better_provided() {} + for s in 0..MaxSignedSubmissions::get() { + // score is always getting better + let solution = RawSolution { + winners: vec![1u16], + score: [(5 + s).into(), 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + } + + // weaker. + let solution = RawSolution { + winners: vec![1u16], + score: [4, 0, 0], + ..Default::default() + }; + + assert_noop!( + TwoPhase::submit(Origin::signed(99), solution), + PalletError::::QueueFull, + ); + }) + } #[test] - fn cannot_submit_worse_with_full_queue() {} + fn weakest_is_removed_if_better_provided() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + + for s in 0..MaxSignedSubmissions::get() { + // score is always getting better + let solution = RawSolution { + winners: vec![1u16], + score: [(5 + s).into(), 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + } + + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![5, 6, 7, 8, 9] + ); + + // better. + let solution = RawSolution { + winners: vec![1u16], + score: [20, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + + // the one with score 5 was rejected, the new one inserted. + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![6, 7, 8, 9, 20] + ); + }) + } #[test] - fn suppressed_solution_gets_bond_back() {} + fn equally_good_is_not_accepted() { + ExtBuilder::default() + .max_signed_submission(3) + .build_and_execute(|| { + roll_to(5); + + for i in 0..MaxSignedSubmissions::get() { + let solution = RawSolution { + winners: vec![1u16], + score: [(5 + i).into(), 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + } + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![5, 6, 7] + ); + + // 5 is not accepted. This will only cause processing with no benefit. + let solution = RawSolution { + winners: vec![1u16], + score: [5, 0, 0], + ..Default::default() + }; + assert_noop!( + TwoPhase::submit(Origin::signed(99), solution), + PalletError::::QueueFull + ); + }) + } #[test] - fn solutions_are_sorted() {} + fn solutions_are_always_sorted() { + ExtBuilder::default() + .max_signed_submission(3) + .build_and_execute(|| { + roll_to(5); + + let solution = RawSolution { + winners: vec![1u16], + score: [5, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![5] + ); + + let solution = RawSolution { + winners: vec![1u16], + score: [8, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![5, 8] + ); + + let solution = RawSolution { + winners: vec![1u16], + score: [3, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![3, 5, 8] + ); + + let solution = RawSolution { + winners: vec![1u16], + score: [6, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![5, 6, 8] + ); + + let solution = RawSolution { + winners: vec![1u16], + score: [6, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![6, 6, 8] + ); + + let solution = RawSolution { + winners: vec![1u16], + score: [10, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![6, 8, 10] + ); + }) + } #[test] - fn all_in_one_singed_submission() { + fn all_in_one_singed_submission_scenario() { // a combination of: // - good_solution_is_rewarded // - bad_solution_is_slashed // - suppressed_solution_gets_bond_back + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + + assert_eq!(balances(&99), (100, 0)); + assert_eq!(balances(&999), (100, 0)); + assert_eq!(balances(&9999), (100, 0)); + let mut solution = raw_solution(); + + // submit a correct one. + assert_ok!(TwoPhase::submit(Origin::signed(99), solution.clone())); + + // make the solution invalidly better and submit. This ought to be slashed. + solution.score[0] += 1; + assert_ok!(TwoPhase::submit(Origin::signed(999), solution.clone())); + + // make the solution invalidly worse and submit. This ought to be suppressed and returned. + solution.score[0] -= 1; + assert_ok!(TwoPhase::submit(Origin::signed(9999), solution)); + + assert_eq!( + TwoPhase::signed_submissions() + .iter() + .map(|x| x.who) + .collect::>(), + vec![9999, 99, 999] + ); + + // _some_ good solution was stored. + assert!(TwoPhase::finalize_signed_phase()); + + // 99 is rewarded. + assert_eq!(balances(&99), (100 + 7, 0)); + // 999 is slashed. + assert_eq!(balances(&999), (95, 0)); + // 9999 gets everything back. + assert_eq!(balances(&9999), (100, 0)); + }) } } diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index c5381a983bc12..1df1026edd9cb 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -125,6 +125,62 @@ impl __OrInvalidIndex for Option { } } +/// A common interface for all compact solutions. +/// +/// See [`compact`] for more info. +pub trait CompactSolution: Sized { + const LIMIT: usize; + type Voter; + type Target; + type VoteWeight: PerThing; + + fn from_assignment( + assignments: Vec>, + voter_index: FV, + target_index: FT, + ) -> Result + where + for<'r> FV: Fn(&'r A) -> Option, + for<'r> FT: Fn(&'r A) -> Option; + + fn into_assignment( + self, + voter_at: impl Fn(Self::Voter) -> Option, + target_at: impl Fn(Self::Target) -> Option, + ) -> Result>, Error>; + + /// Get the length of all the assignments that this type is encoding. This is basically + /// the same as the number of assignments, or the number of voters in total. + fn len(&self) -> usize; + + /// Get the total count of edges. + /// + /// This is effectively in the range of {[`Self::len`], [`Self::len`] * [`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. + /// + /// The resulting indices are sorted. + fn unique_targets(&self) -> Vec; + + /// Get the average edge count. + fn average_edge_count(&self) -> usize { + self.edge_count().checked_div(self.len()).unwrap_or(0) + } + + /// 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 from + /// `self.len()`. + fn remove_voter(&mut self, to_remove: Self::Voter) -> bool; +} + // re-export the compact solution type. pub use sp_npos_elections_compact::generate_solution_type; @@ -493,11 +549,6 @@ pub struct Support { /// A linkage from a candidate and its [`Support`]. pub type SupportMap = BTreeMap>; -/// A flat variant of [`SupportMap`]. -/// -/// The main advantage of this is that it is encodable. -pub type FlatSupportMap = Vec<(A, Support)>; - /// Build the support map from the given election result. It maps a flat structure like /// /// ```nocompile From 9c880f3dc2ec18e7278fe02b85fe746f36b97e70 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 9 Oct 2020 17:10:45 +0200 Subject: [PATCH 06/62] Finally decoupled solution from the pallet.. such a PITA. --- frame/election-providers/src/lib.rs | 41 ++--- frame/election-providers/src/onchain.rs | 6 +- .../src/two_phase/macros.rs | 20 +-- .../election-providers/src/two_phase/mock.rs | 36 ++-- frame/election-providers/src/two_phase/mod.rs | 167 +++++++++--------- .../src/two_phase/signed.rs | 44 ++--- .../npos-elections/compact/src/assignment.rs | 54 +----- primitives/npos-elections/compact/src/lib.rs | 91 +++++----- .../fuzzer/src/phragmms_balancing.rs | 8 +- primitives/npos-elections/src/helpers.rs | 23 +-- primitives/npos-elections/src/lib.rs | 64 +++---- primitives/npos-elections/src/mock.rs | 1 - primitives/npos-elections/src/phragmen.rs | 12 +- primitives/npos-elections/src/phragmms.rs | 11 +- primitives/npos-elections/src/tests.rs | 9 +- 15 files changed, 265 insertions(+), 322 deletions(-) diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs index 193f9e798c057..702a4da6b74b9 100644 --- a/frame/election-providers/src/lib.rs +++ b/frame/election-providers/src/lib.rs @@ -31,14 +31,15 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_std::prelude::*; +use sp_std::{fmt::Debug, prelude::*}; + /// The onchain module. pub mod onchain; /// The two-phase module. pub mod two_phase; use sp_arithmetic::PerThing; -use sp_npos_elections::{ExtendedBalance, Support, SupportMap}; +use sp_npos_elections::{CompactSolution, ExtendedBalance, PerThing128, Support, SupportMap}; // for the helper macros #[doc(hidden)] @@ -87,7 +88,11 @@ impl FlattenSupportMap for SupportMap { /// } /// ``` pub trait ElectionDataProvider { - type CompactSolution: codec::Codec + Default + PartialEq + Eq; + /// The compact solution type. + /// + /// This should encode the entire solution with the least possible space usage. + type CompactSolution: codec::Codec + Default + PartialEq + Eq + Clone + Debug + CompactSolution; + /// All possible targets for the election, i.e. the candidates. fn targets() -> Vec; @@ -116,25 +121,6 @@ pub trait ElectionDataProvider { fn next_election_prediction(now: B) -> B; } -#[cfg(feature = "std")] -impl ElectionDataProvider for () { - fn targets() -> Vec { - Default::default() - } - fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { - Default::default() - } - fn desired_targets() -> u32 { - Default::default() - } - fn feasibility_check_assignment(_: &AccountId, _: &[(AccountId, P)]) -> bool { - Default::default() - } - fn next_election_prediction(_: B) -> B { - Default::default() - } -} - /// Something that can compute the result of an election and pass it back to the caller. pub trait ElectionProvider { /// Indicate weather this election provider needs data when calling [`elect`] or not. @@ -150,18 +136,15 @@ pub trait ElectionProvider { /// Note that based on the logic of the type that will implement this trait, the input data may /// or may not be used. To hint about this to the call site, [`NEEDS_ELECT_DATA`] should be /// properly set. - fn elect( + /// + /// The implementation should, if possible, use the accuracy `P` to compute the election result. + fn elect( to_elect: usize, // TODO: consider making this u32 targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, ) -> Result, Self::Error> where - // TODO: Okay about these two, I get that we probably need the first one, but can't we - // alleviate the latter one? I think we can say that all PerThing are Mul of some types. - // Perhaps it is time to move the PerBill macros to something better? Yeah I think then we - // can get rid of both of these types everywhere. - ExtendedBalance: From<

::Inner>, - P: sp_std::ops::Mul; + ExtendedBalance: From<

::Inner>; /// Returns true if an election is still ongoing. This can be used by the call site to /// dynamically check of a long-lasting election (such as [`two_phase`]) is still on-going or diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs index 1d839b7c741ea..6e82395246a72 100644 --- a/frame/election-providers/src/onchain.rs +++ b/frame/election-providers/src/onchain.rs @@ -1,6 +1,6 @@ use crate::{ElectionProvider, FlatSupportMap, FlattenSupportMap}; use sp_arithmetic::PerThing; -use sp_npos_elections::{ElectionResult, ExtendedBalance, IdentifierT, VoteWeight}; +use sp_npos_elections::{ElectionResult, ExtendedBalance, IdentifierT, PerThing128, VoteWeight}; use sp_runtime::RuntimeDebug; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -23,14 +23,13 @@ impl ElectionProvider for OnChainSequentialPh const NEEDS_ELECT_DATA: bool = true; - fn elect( + fn elect( to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, - P: sp_std::ops::Mul, { // TODO: we really don't need to do this conversion all the time. With // https://github.com/paritytech/substrate/pull/6685 merged, we should make variants of @@ -39,6 +38,7 @@ impl ElectionProvider for OnChainSequentialPh // TODO: Okay even if not the above, then def. make the extension traits for converting // between validator Major and Nominator Major result types, and make the conversions be // lossless and painless to happen. + let mut stake_map: BTreeMap = BTreeMap::new(); voters.iter().for_each(|(v, s, _)| { stake_map.insert(v.clone(), *s); diff --git a/frame/election-providers/src/two_phase/macros.rs b/frame/election-providers/src/two_phase/macros.rs index c75fd67b28d2f..b34028155d22f 100644 --- a/frame/election-providers/src/two_phase/macros.rs +++ b/frame/election-providers/src/two_phase/macros.rs @@ -29,25 +29,25 @@ macro_rules! log { #[macro_export] macro_rules! voter_index_fn { - ($voters:ident, $acc:ty) => { - |who: &$acc| -> Option<$crate::two_phase::VoterIndex> { + ($voters:ident, $acc:ty, $t:ident) => { + |who: &$acc| -> Option<$crate::two_phase::CompactVoterIndexOf<$t>> { $voters .iter() .position(|(x, _, _)| x == who) - .and_then(|i| >::try_into(i).ok()) + .and_then(|i| >>::try_into(i).ok()) } }; } #[macro_export] macro_rules! target_index_fn { - ($targets:ident, $acc:ty) => { - |who: &$acc| -> Option<$crate::two_phase::TargetIndex> { - $targets - .iter() - .position(|x| x == who) - .and_then(|i| >::try_into(i).ok()) - } + ($targets:ident, $acc:ty, $t:ident) => { + |who: &$acc| -> Option<$crate::two_phase::CompactTargetIndexOf<$t>> { + $targets + .iter() + .position(|x| x == who) + .and_then(|i| >>::try_into(i).ok()) + } }; } diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 70b52e278d5c6..349b89d0172b2 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -1,9 +1,11 @@ use super::*; use frame_support::{parameter_types, traits::OnInitialize}; use sp_core::H256; +use sp_npos_elections::CompactSolution; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, + PerU16, }; use std::cell::RefCell; @@ -17,6 +19,11 @@ pub(crate) type TwoPhase = super::Module; pub(crate) type Balance = u64; pub(crate) type AccountId = u64; +sp_npos_elections::generate_solution_type!( + #[compact] + pub struct TestCompact::(16) +); + /// To from `now` to block `n`. pub fn roll_to(n: u64) { let now = System::block_number(); @@ -34,21 +41,22 @@ pub fn balances(who: &AccountId) -> (Balance, Balance) { /// Spit out a verifiable raw solution. /// /// This is a good example of what an offchain miner would do. -pub fn raw_solution() -> RawSolution { +pub fn raw_solution() -> RawSolution> { let voters = TwoPhase::snapshot_voters().unwrap(); let targets = TwoPhase::snapshot_targets().unwrap(); let desired = TwoPhase::desired_targets() as usize; // closures - let voter_index = crate::voter_index_fn!(voters, AccountId); - let target_index = crate::target_index_fn!(targets, AccountId); + let voter_index = crate::voter_index_fn!(voters, AccountId, Runtime); + let target_index = crate::target_index_fn!(targets, AccountId, Runtime); let stake_of = crate::stake_of_fn!(voters, AccountId); use sp_npos_elections::{seq_phragmen, to_without_backing, ElectionResult}; let ElectionResult { winners, assignments, - } = seq_phragmen::<_, OffchainAccuracy>(desired, targets.clone(), voters.clone(), None).unwrap(); + } = seq_phragmen::<_, CompactAccuracyOf>(desired, targets.clone(), voters.clone(), None) + .unwrap(); let winners = to_without_backing(winners); @@ -59,17 +67,9 @@ pub fn raw_solution() -> RawSolution { sp_npos_elections::evaluate_support(&support) }; let compact = - CompactAssignments::from_assignment(assignments, &voter_index, &target_index).unwrap(); - let winners = winners - .into_iter() - .map(|w| target_index(&w).unwrap()) - .collect::>(); + >::from_assignment(assignments, &voter_index, &target_index).unwrap(); - RawSolution { - winners, - compact, - score, - } + RawSolution { compact, score } } frame_support::impl_outer_origin! { @@ -191,7 +191,7 @@ impl crate::two_phase::Trait for Runtime { type SolutionImprovementThreshold = (); type SlashHandler = (); type RewardHandler = (); - type ElectionDataProvider = ExtBuilder; + type ElectionDataProvider = StakingMock; type WeightInfo = (); } @@ -207,7 +207,11 @@ impl Default for ExtBuilder { } } -impl crate::ElectionDataProvider for ExtBuilder { +pub struct StakingMock; + +impl crate::ElectionDataProvider for StakingMock { + type CompactSolution = TestCompact; + fn targets() -> Vec { Targets::get() } diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index efdf994706ee7..ec528ee9e6ebe 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -98,6 +98,11 @@ //! ## Correct Submission //! //! TODO +//! +//! ## Accuracy +//! +//! TODO +//! use crate::{ onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, FlatSupportMap, @@ -113,11 +118,11 @@ use frame_support::{ }; use frame_system::{ensure_none, ensure_signed}; use sp_npos_elections::{ - evaluate_support, generate_solution_type, Assignment, ElectionScore, ExtendedBalance, - VoteWeight, + assignment_ratio_to_staked_normalized, build_support_map, evaluate_support, Assignment, + CompactSolution, ElectionScore, ExtendedBalance, PerThing128, VoteWeight, }; -use sp_runtime::{traits::Zero, PerThing, PerU16, Perbill, RuntimeDebug}; -use sp_std::{mem::size_of, prelude::*}; +use sp_runtime::{traits::Zero, InnerOf, PerThing, Perbill, RuntimeDebug}; +use sp_std::prelude::*; #[cfg(test)] mod mock; @@ -127,6 +132,20 @@ pub(crate) mod macros; pub mod signed; pub mod unsigned; +/// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] +/// implementer. +pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< + ::AccountId, + ::BlockNumber, +>>::CompactSolution; + +/// The voter index. Derived from [`CompactOf`]. +pub type CompactVoterIndexOf = as CompactSolution>::Voter; +/// The target index. Derived from [`CompactOf`]. +pub type CompactTargetIndexOf = as CompactSolution>::Target; +/// The accuracy of the election. Derived from [`CompactOf`]. +pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; + type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -135,30 +154,6 @@ type PositiveImbalanceOf = type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; -/// Accuracy used for on-chain election. -pub type ChainAccuracy = Perbill; - -/// Accuracy used for off-chain election. This better be small. -pub type OffchainAccuracy = PerU16; - -/// Data type used to index voter in the compact type. -pub type VoterIndex = u32; - -/// Data type used to index target in the compact type. -pub type TargetIndex = u16; - -// Ensure the size of both TargetIndex and VoterIndex. They both need to be well below usize. -static_assertions::const_assert!(size_of::() <= size_of::()); -static_assertions::const_assert!(size_of::() <= size_of::()); -static_assertions::const_assert!(size_of::() <= size_of::()); -static_assertions::const_assert!(size_of::() <= size_of::()); - -// TODO: deal with 16 being defined here. -generate_solution_type!( - #[compact] - pub struct CompactAssignments::(16) -); - const LOG_TARGET: &'static str = "two-phase-submission"; /// Current phase of the pallet. @@ -222,11 +217,9 @@ impl Default for ElectionCompute { /// Such a solution should never become effective in anyway before being checked by the /// [`Module::feasibility_check`] #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] -pub struct RawSolution { - /// The winners indices. - winners: Vec, +pub struct RawSolution { /// Compact election edges. - compact: CompactAssignments, + compact: C, /// The _claimed_ score of the solution. score: ElectionScore, } @@ -235,23 +228,23 @@ pub struct RawSolution { /// /// This is just a wrapper around [`RawSolution`] and some additional info. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] -pub struct SignedSubmission { +pub struct SignedSubmission { /// Who submitted this solution. - who: AccountId, + who: A, /// The deposit reserved for storing this solution. - deposit: Balance, + deposit: B, /// The reward that should be given to this solution, if chosen the as the final one. - reward: Balance, + reward: B, /// The raw solution itself. - solution: RawSolution, + solution: RawSolution, } /// A checked and parsed solution, ready to be enacted. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] -pub struct ReadySolution { +pub struct ReadySolution { /// The final supports of the solution. This is target-major vector, storing each winners, total /// backing, and each individual backer. - supports: FlatSupportMap, + supports: FlatSupportMap, /// How this election was computed. compute: ElectionCompute, } @@ -341,12 +334,12 @@ pub trait Trait: frame_system::Trait { } decl_storage! { - trait Store for Module as TwoPhaseElectionProvider { + trait Store for Module as TwoPhaseElectionProvider where ExtendedBalance: From>> { /// Current phase. pub CurrentPhase get(fn current_phase): Phase = Phase::Off; /// Sorted (worse -> best) list of unchecked, signed solutions. - pub SignedSubmissions get(fn signed_submissions): Vec>>; + pub SignedSubmissions get(fn signed_submissions): Vec, CompactOf>>; /// Current best solution, signed or unsigned. pub QueuedSolution get(fn queued_solution): Option>; @@ -385,19 +378,25 @@ decl_event!( } ); -decl_error! { - pub enum PalletError for Module { - /// Submission was too early. - EarlySubmission, - /// The queue was full, and the solution was not better than any of the existing ones. - QueueFull, - /// The origin failed to pay the deposit. - CannotPayDeposit, - } -} +// decl_error! { +// pub enum PalletError for Module { +// /// Submission was too early. +// EarlySubmission, +// /// The queue was full, and the solution was not better than any of the existing ones. +// QueueFull, +// /// The origin failed to pay the deposit. +// CannotPayDeposit, +// } +// } decl_module! { - pub struct Module for enum Call where origin: T::Origin { + pub struct Module for enum Call + where + origin: T::Origin, + ExtendedBalance: From>> + { + // TODO: replace with PalletError once we have it working. + type Error = &'static str; fn deposit_event() = default; fn on_initialize(now: T::BlockNumber) -> Weight { @@ -439,21 +438,21 @@ decl_module! { /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution /// might be rewarded, slashed, or get all or a part of the deposit back. #[weight = 0] - fn submit(origin, solution: RawSolution) -> DispatchResultWithPostInfo { + fn submit(origin, solution: RawSolution>) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; // ensure solution is timely. - ensure!(Self::current_phase().is_signed(), PalletError::::EarlySubmission); + ensure!(Self::current_phase().is_signed(), "EarlySubmission"); // ensure solution claims is better. let mut signed_submissions = Self::signed_submissions(); let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution); - ensure!(maybe_index.is_some(), PalletError::::QueueFull); + ensure!(maybe_index.is_some(), "QueueFull"); let index = maybe_index.expect("Option checked to be `Some`; qed."); // collect deposit. Thereafter, the function cannot fail. let deposit = signed_submissions[index].deposit; - T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; + T::Currency::reserve(&who, deposit).map_err(|_| "CannotPayDeposit")?; // store the new signed submission. debug_assert!(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()); @@ -464,7 +463,7 @@ decl_module! { } #[weight = 0] - fn submit_unsigned(origin, solution: RawSolution) { + fn submit_unsigned(origin, solution: RawSolution>) { ensure_none(origin)?; Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); unimplemented!() @@ -472,7 +471,10 @@ decl_module! { } } -impl Module { +impl Module +where + ExtendedBalance: From>>, +{ /// Checks the feasibility of a solution. /// /// This checks the solution for the following: @@ -483,20 +485,13 @@ impl Module { /// 3. for each assignment, the check of `ElectionDataProvider` is also examined. /// 4. the claimed score is valid. fn feasibility_check( - solution: RawSolution, + solution: RawSolution>, compute: ElectionCompute, ) -> Result, FeasibilityError> { - let RawSolution { - winners, - compact, - score, - } = solution; + let RawSolution { compact, score } = solution; - // Ensure that the compact and winners have equal number of winners. - ensure!( - compact.unique_targets().len() == winners.len(), - FeasibilityError::WrongWinnerCount - ); + // winners are not directly encoded in the solution. + let winners = compact.unique_targets(); // Ensure that we have received enough winners. ensure!( @@ -510,11 +505,16 @@ impl Module { let snapshot_targets = Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - let voter_at = |i: VoterIndex| -> Option { - snapshot_voters.get(i as usize).map(|(x, _, _)| x).cloned() + use sp_runtime::traits::UniqueSaturatedInto; + let voter_at = |i: CompactVoterIndexOf| -> Option { + snapshot_voters + .get(i.unique_saturated_into()) + .map(|(x, _, _)| x) + .cloned() + }; + let target_at = |i: CompactTargetIndexOf| -> Option { + snapshot_targets.get(i.unique_saturated_into()).cloned() }; - let target_at = - |i: TargetIndex| -> Option { snapshot_targets.get(i as usize).cloned() }; // first, make sure that all the winners are sane. let winners = winners @@ -537,7 +537,7 @@ impl Module { |(_, _, t)| { if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) && T::ElectionDataProvider::feasibility_check_assignment::< - OffchainAccuracy, + CompactAccuracyOf, >(who, distribution) { Ok(()) @@ -552,20 +552,21 @@ impl Module { // ----- Start building support. First, we need some more closures. let stake_of = stake_of_fn!(snapshot_voters, T::AccountId); - use sp_npos_elections::{assignment_ratio_to_staked_normalized, build_support_map}; // This might fail if the normalization fails. Very unlikely. let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) .map_err::(Into::into)?; // This might fail if one of the voter edges is pointing to a non-winner. let supports = build_support_map(&winners, &staked_assignments) + .map(FlattenSupportMap::flatten) .map_err::(Into::into)?; // Finally, check that the claimed score was indeed correct. - // TODO: evaluate support could accept both types of support. - let known_score = evaluate_support(&supports); + // TODO: well, I am not sure if this is now better or not... + let known_score = + evaluate_support::(supports.iter().map(|&(ref x, ref y)| (x, y))); ensure!(known_score == score, FeasibilityError::InvalidScore); - let supports = supports.flatten(); + // let supports = supports.flatten(); Ok(ReadySolution { supports, compute }) } @@ -574,7 +575,7 @@ impl Module { let desired_targets = Self::desired_targets() as usize; let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - >::elect::( + >::elect::( desired_targets, targets, voters, @@ -583,19 +584,21 @@ impl Module { } } -impl crate::ElectionProvider for Module { +impl crate::ElectionProvider for Module +where + ExtendedBalance: From>>, +{ type Error = Error; const NEEDS_ELECT_DATA: bool = false; - fn elect( + fn elect( _to_elect: usize, _targets: Vec, _voters: Vec<(T::AccountId, VoteWeight, Vec)>, ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, - P: sp_std::ops::Mul, { Self::queued_solution() .map_or_else( diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index 452e3ac1d170e..ffe953ebe2be4 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -21,8 +21,12 @@ use crate::two_phase::*; use codec::Encode; use sp_arithmetic::traits::SaturatedConversion; use sp_npos_elections::is_score_better; +use sp_runtime::Perbill; -impl Module { +impl Module +where + ExtendedBalance: From>>, +{ /// Start the signed phase. /// /// Upon calling this, auxillary data for election is stored and signed solutions will be @@ -43,7 +47,7 @@ impl Module { /// /// Returns true if we have a good solution in the signed phase. pub fn finalize_signed_phase() -> bool { - let mut all_submission: Vec> = >::take(); + let mut all_submission: Vec> = >::take(); let mut found_solution = false; while let Some(best) = all_submission.pop() { @@ -94,8 +98,8 @@ impl Module { /// solution quality. pub fn insert_submission( who: &T::AccountId, - queue: &mut Vec>>, - solution: RawSolution, + queue: &mut Vec, CompactOf>>, + solution: RawSolution>, ) -> Option { // TODO: consider using VecDeQue or sth like that? @@ -106,7 +110,8 @@ impl Module { .enumerate() .rev() .find_map(|(i, s)| { - if is_score_better( + + if is_score_better::( solution.score, s.solution.score, T::SolutionImprovementThreshold::get(), @@ -146,13 +151,13 @@ impl Module { outcome } - pub fn deposit_for(solution: &RawSolution) -> BalanceOf { + pub fn deposit_for(solution: &RawSolution>) -> BalanceOf { let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); // TODO T::SignedDepositBase::get() + T::SignedDepositByte::get() * encoded_len } - pub fn reward_for(solution: &RawSolution) -> BalanceOf { + pub fn reward_for(solution: &RawSolution>) -> BalanceOf { T::SignedRewardBase::get() + T::SignedRewardFactor::get() * solution.score[0].saturated_into::>() } @@ -174,7 +179,7 @@ mod tests { assert_noop!( TwoPhase::submit(Origin::signed(10), solution), - PalletError::::EarlySubmission, + "EarlySubmission", ); }) } @@ -270,7 +275,6 @@ mod tests { assert_eq!(TwoPhase::current_phase(), Phase::Signed); let solution = RawSolution { - winners: vec![1u16], score: [5, 0, 0], ..Default::default() }; @@ -278,7 +282,6 @@ mod tests { // then a worse one. let solution = RawSolution { - winners: vec![2u16], score: [4, 0, 0], ..Default::default() }; @@ -286,7 +289,6 @@ mod tests { // then a better one. let solution = RawSolution { - winners: vec![3u16], score: [6, 0, 0], ..Default::default() }; @@ -295,9 +297,9 @@ mod tests { assert_eq!( TwoPhase::signed_submissions() .iter() - .map(|x| x.solution.winners[0]) + .map(|x| x.solution.score[0]) .collect::>(), - vec![2, 1, 3] + vec![4, 5, 6] ); }) } @@ -310,7 +312,6 @@ mod tests { for s in 0..MaxSignedSubmissions::get() { // score is always getting better let solution = RawSolution { - winners: vec![1u16], score: [(5 + s).into(), 0, 0], ..Default::default() }; @@ -319,14 +320,13 @@ mod tests { // weaker. let solution = RawSolution { - winners: vec![1u16], score: [4, 0, 0], ..Default::default() }; assert_noop!( TwoPhase::submit(Origin::signed(99), solution), - PalletError::::QueueFull, + "QueueFull", ); }) } @@ -339,7 +339,6 @@ mod tests { for s in 0..MaxSignedSubmissions::get() { // score is always getting better let solution = RawSolution { - winners: vec![1u16], score: [(5 + s).into(), 0, 0], ..Default::default() }; @@ -356,7 +355,6 @@ mod tests { // better. let solution = RawSolution { - winners: vec![1u16], score: [20, 0, 0], ..Default::default() }; @@ -382,7 +380,6 @@ mod tests { for i in 0..MaxSignedSubmissions::get() { let solution = RawSolution { - winners: vec![1u16], score: [(5 + i).into(), 0, 0], ..Default::default() }; @@ -398,13 +395,12 @@ mod tests { // 5 is not accepted. This will only cause processing with no benefit. let solution = RawSolution { - winners: vec![1u16], score: [5, 0, 0], ..Default::default() }; assert_noop!( TwoPhase::submit(Origin::signed(99), solution), - PalletError::::QueueFull + "QueueFull", ); }) } @@ -417,7 +413,6 @@ mod tests { roll_to(5); let solution = RawSolution { - winners: vec![1u16], score: [5, 0, 0], ..Default::default() }; @@ -431,7 +426,6 @@ mod tests { ); let solution = RawSolution { - winners: vec![1u16], score: [8, 0, 0], ..Default::default() }; @@ -445,7 +439,6 @@ mod tests { ); let solution = RawSolution { - winners: vec![1u16], score: [3, 0, 0], ..Default::default() }; @@ -459,7 +452,6 @@ mod tests { ); let solution = RawSolution { - winners: vec![1u16], score: [6, 0, 0], ..Default::default() }; @@ -473,7 +465,6 @@ mod tests { ); let solution = RawSolution { - winners: vec![1u16], score: [6, 0, 0], ..Default::default() }; @@ -487,7 +478,6 @@ mod tests { ); let solution = RawSolution { - winners: vec![1u16], score: [10, 0, 0], ..Default::default() }; diff --git a/primitives/npos-elections/compact/src/assignment.rs b/primitives/npos-elections/compact/src/assignment.rs index 8b61076521d7c..7d1d8f1d880fd 100644 --- a/primitives/npos-elections/compact/src/assignment.rs +++ b/primitives/npos-elections/compact/src/assignment.rs @@ -21,7 +21,7 @@ use crate::field_name_for; use proc_macro2::TokenStream as TokenStream2; use quote::quote; -fn from_impl(count: usize) -> TokenStream2 { +pub(crate) fn from_impl(count: usize) -> TokenStream2 { let from_impl_single = { let name = field_name_for(1); quote!(1 => compact.#name.push( @@ -73,7 +73,7 @@ fn from_impl(count: usize) -> TokenStream2 { ) } -fn into_impl(count: usize, per_thing: syn::Type) -> TokenStream2 { +pub(crate) fn into_impl(count: usize, per_thing: syn::Type) -> TokenStream2 { let into_impl_single = { let name = field_name_for(1); quote!( @@ -153,53 +153,3 @@ fn into_impl(count: usize, per_thing: syn::Type) -> TokenStream2 { #into_impl_rest ) } - -pub(crate) fn assignment( - ident: syn::Ident, - voter_type: syn::Type, - target_type: syn::Type, - weight_type: syn::Type, - count: usize, -) -> TokenStream2 { - let from_impl = from_impl(count); - let into_impl = into_impl(count, weight_type.clone()); - - quote!( - use _npos::__OrInvalidIndex; - impl #ident { - pub fn from_assignment( - assignments: Vec<_npos::Assignment>, - index_of_voter: FV, - index_of_target: FT, - ) -> Result - where - A: _npos::IdentifierT, - for<'r> FV: Fn(&'r A) -> Option<#voter_type>, - for<'r> FT: Fn(&'r A) -> Option<#target_type>, - { - let mut compact: #ident = Default::default(); - - for _npos::Assignment { who, distribution } in assignments { - match distribution.len() { - 0 => continue, - #from_impl - _ => { - return Err(_npos::Error::CompactTargetOverflow); - } - } - }; - Ok(compact) - } - - pub fn into_assignment( - self, - voter_at: impl Fn(#voter_type) -> Option, - target_at: impl Fn(#target_type) -> Option, - ) -> Result>, _npos::Error> { - let mut assignments: Vec<_npos::Assignment> = Default::default(); - #into_impl - Ok(assignments) - } - } - ) -} diff --git a/primitives/npos-elections/compact/src/lib.rs b/primitives/npos-elections/compact/src/lib.rs index b35c407c40cd5..86ddaf4af70bc 100644 --- a/primitives/npos-elections/compact/src/lib.rs +++ b/primitives/npos-elections/compact/src/lib.rs @@ -95,19 +95,11 @@ pub fn generate_solution_type(item: TokenStream) -> TokenStream { compact_encoding, ).unwrap_or_else(|e| e.to_compile_error()); - let assignment_impls = assignment::assignment( - ident.clone(), - voter_type.clone(), - target_type.clone(), - weight_type.clone(), - count, - ); - quote!( #imports #solution_struct - #assignment_impls - ).into() + ) + .into() } fn struct_def( @@ -172,40 +164,36 @@ fn struct_def( quote!(#[derive(Default, PartialEq, Eq, Clone, Debug, _npos::codec::Encode, _npos::codec::Decode)]) }; + let from_impl = assignment::from_impl(count); + let into_impl = assignment::into_impl(count, weight_type.clone()); + Ok(quote! ( /// A struct to encode a election assignment in a compact way. #derives_and_maybe_compact_encoding #vis struct #ident { #singles #doubles #rest } - impl _npos::VotingLimit for #ident { + use _npos::__OrInvalidIndex; + impl _npos::CompactSolution for #ident { const LIMIT: usize = #count; - } + type Voter = #voter_type; + type Target = #target_type; + type VoteWeight = #weight_type; - impl #ident { - /// Get the length of all the assignments that this type is encoding. This is basically - /// the same as the number of assignments, or the number of voters in total. - pub fn len(&self) -> usize { + fn len(&self) -> usize { let mut all_len = 0usize; #len_impl all_len } - /// Get the total count of edges. - pub fn edge_count(&self) -> usize { + fn edge_count(&self) -> usize { let mut all_edges = 0usize; #edge_count_impl all_edges } - /// 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. - /// - /// The resulting indices are sorted. - pub fn unique_targets(&self) -> Vec<#target_type> { - let mut all_targets: Vec<#target_type> = Vec::with_capacity(self.average_edge_count()); - let mut maybe_insert_target = |t: #target_type| { + fn unique_targets(&self) -> Vec { + let mut all_targets: Vec = Vec::with_capacity(self.average_edge_count()); + let mut maybe_insert_target = |t: Self::Target| { match all_targets.binary_search(&t) { Ok(_) => (), Err(pos) => all_targets.insert(pos, t) @@ -217,22 +205,44 @@ fn struct_def( all_targets } - /// Get the average edge count. - pub fn average_edge_count(&self) -> usize { - self.edge_count().checked_div(self.len()).unwrap_or(0) - } - - /// 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 from - /// `self.len()`. - pub fn remove_voter(&mut self, to_remove: #voter_type) -> bool { + fn remove_voter(&mut self, to_remove: Self::Voter) -> bool { #remove_voter_impl return false } + + fn from_assignment( + assignments: Vec<_npos::Assignment>, + index_of_voter: FV, + index_of_target: FT, + ) -> Result + where + A: _npos::IdentifierT, + for<'r> FV: Fn(&'r A) -> Option, + for<'r> FT: Fn(&'r A) -> Option, + { + let mut compact: #ident = Default::default(); + + for _npos::Assignment { who, distribution } in assignments { + match distribution.len() { + 0 => continue, + #from_impl + _ => { + return Err(_npos::Error::CompactTargetOverflow); + } + } + }; + Ok(compact) + } + + fn into_assignment( + self, + voter_at: impl Fn(Self::Voter) -> Option, + target_at: impl Fn(Self::Target) -> Option, + ) -> Result>, _npos::Error> { + let mut assignments: Vec<_npos::Assignment> = Default::default(); + #into_impl + Ok(assignments) + } } )) } @@ -347,7 +357,6 @@ fn imports() -> Result { } } } - struct SolutionDef { vis: syn::Visibility, ident: syn::Ident, diff --git a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs index 0aada6a5624dd..f22eadb66b9d7 100644 --- a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs @@ -66,9 +66,13 @@ fn main() { }; let unbalanced_score = { - let staked = assignment_ratio_to_staked_normalized(unbalanced.assignments.clone(), &stake_of).unwrap(); + let staked = assignment_ratio_to_staked_normalized( + unbalanced.assignments.clone(), + &stake_of, + ) + .unwrap(); let winners = to_without_backing(unbalanced.winners.clone()); - let support = build_support_map(winners.as_ref(), staked.as_ref()).unwrap(); + let support = build_support_map(&winners, &staked).unwrap(); let score = evaluate_support(&support); if score[0] == 0 { diff --git a/primitives/npos-elections/src/helpers.rs b/primitives/npos-elections/src/helpers.rs index cd8c199205cab..cc6392d1d3f2d 100644 --- a/primitives/npos-elections/src/helpers.rs +++ b/primitives/npos-elections/src/helpers.rs @@ -18,21 +18,21 @@ //! Helper methods for npos-elections. use crate::{ - Assignment, ExtendedBalance, VoteWeight, IdentifierT, StakedAssignment, WithApprovalOf, Error, + Assignment, Error, ExtendedBalance, IdentifierT, PerThing128, StakedAssignment, VoteWeight, + WithApprovalOf, }; -use sp_arithmetic::{PerThing, InnerOf}; +use sp_arithmetic::{InnerOf, PerThing}; use sp_std::prelude::*; /// Converts a vector of ratio assignments into ones with absolute budget value. /// /// Note that this will NOT attempt at normalizing the result. -pub fn assignment_ratio_to_staked( +pub fn assignment_ratio_to_staked( ratio: Vec>, stake_of: FS, ) -> Vec> where for<'r> FS: Fn(&'r A) -> VoteWeight, - P: sp_std::ops::Mul, ExtendedBalance: From>, { ratio @@ -45,19 +45,22 @@ where } /// Same as [`assignment_ratio_to_staked`] and try and do normalization. -pub fn assignment_ratio_to_staked_normalized( +pub fn assignment_ratio_to_staked_normalized( ratio: Vec>, stake_of: FS, ) -> Result>, Error> where for<'r> FS: Fn(&'r A) -> VoteWeight, - P: sp_std::ops::Mul, ExtendedBalance: From>, { let mut staked = assignment_ratio_to_staked(ratio, &stake_of); - staked.iter_mut().map(|a| - a.try_normalize(stake_of(&a.who).into()).map_err(|err| Error::ArithmeticError(err)) - ).collect::>()?; + staked + .iter_mut() + .map(|a| { + a.try_normalize(stake_of(&a.who).into()) + .map_err(|err| Error::ArithmeticError(err)) + }) + .collect::>()?; Ok(staked) } @@ -74,7 +77,7 @@ where } /// Same as [`assignment_staked_to_ratio`] and try and do normalization. -pub fn assignment_staked_to_ratio_normalized( +pub fn assignment_staked_to_ratio_normalized( staked: Vec>, ) -> Result>, Error> where diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 1df1026edd9cb..84c36ca88c6f9 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -74,18 +74,19 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_std::{ - prelude::*, collections::btree_map::BTreeMap, fmt::Debug, cmp::Ordering, rc::Rc, cell::RefCell, -}; use sp_arithmetic::{ - PerThing, Rational128, ThresholdOrd, InnerOf, Normalizable, - traits::{Zero, Bounded}, + traits::{Bounded, Zero}, + InnerOf, Normalizable, PerThing, Rational128, ThresholdOrd, +}; +use sp_std::{ + cell::RefCell, cmp::Ordering, collections::btree_map::BTreeMap, fmt::Debug, ops::Mul, + prelude::*, rc::Rc, }; #[cfg(feature = "std")] -use serde::{Serialize, Deserialize}; +use codec::{Decode, Encode}; #[cfg(feature = "std")] -use codec::{Encode, Decode}; +use serde::{Deserialize, Serialize}; #[cfg(test)] mod mock; @@ -128,22 +129,23 @@ impl __OrInvalidIndex for Option { /// A common interface for all compact solutions. /// /// See [`compact`] for more info. -pub trait CompactSolution: Sized { +pub trait CompactSolution: Sized { const LIMIT: usize; - type Voter; - type Target; - type VoteWeight: PerThing; + type Voter: sp_arithmetic::traits::UniqueSaturatedInto; + type Target: sp_arithmetic::traits::UniqueSaturatedInto; + type VoteWeight: PerThing128; - fn from_assignment( + fn from_assignment( assignments: Vec>, voter_index: FV, target_index: FT, ) -> Result where + A: IdentifierT, for<'r> FV: Fn(&'r A) -> Option, for<'r> FT: Fn(&'r A) -> Option; - fn into_assignment( + fn into_assignment( self, voter_at: impl Fn(Self::Voter) -> Option, target_at: impl Fn(Self::Target) -> Option, @@ -184,17 +186,15 @@ pub trait CompactSolution: Sized { // re-export the compact solution type. pub use sp_npos_elections_compact::generate_solution_type; -/// A trait to limit the number of votes per voter. The generated compact type will implement this. -pub trait VotingLimit { - const LIMIT: usize; -} - /// an aggregator trait for a generic type of a voter/target identifier. This usually maps to /// substrate's account id. pub trait IdentifierT: Clone + Eq + Default + Ord + Debug + codec::Codec {} - impl IdentifierT for T {} +/// Aggregator trait for a PerThing that can be multiplied by u128 (ExtendedBalance). +pub trait PerThing128: PerThing + Mul {} +impl> PerThing128 for T {} + /// The errors that might occur in the this crate and compact. #[derive(Debug, Eq, PartialEq)] pub enum Error { @@ -389,10 +389,7 @@ pub struct Assignment { pub distribution: Vec<(AccountId, P)>, } -impl Assignment -where - ExtendedBalance: From>, -{ +impl Assignment { /// Convert from a ratio assignment into one with absolute values aka. [`StakedAssignment`]. /// /// It needs `stake` which is the total budget of the voter. If `fill` is set to true, it @@ -402,11 +399,9 @@ where /// /// If an edge ratio is [`Bounded::min_value()`], it is dropped. This edge can never mean /// anything useful. - pub fn into_staked(self, stake: ExtendedBalance) -> StakedAssignment - where - P: sp_std::ops::Mul, - { - let distribution = self.distribution + pub fn into_staked(self, stake: ExtendedBalance) -> StakedAssignment { + let distribution = self + .distribution .into_iter() .filter_map(|(target, p)| { // if this ratio is zero, then skip it. @@ -614,15 +609,19 @@ where /// - Sum of all supports squared. This value must be **minimized**. /// /// `O(E)` where `E` is the total number of edges. -pub fn evaluate_support( - support: &SupportMap, +pub fn evaluate_support< + 'a, + AccountId: 'a, + I: IntoIterator)>, +>( + support: I, ) -> ElectionScore { let mut min_support = ExtendedBalance::max_value(); let mut sum: ExtendedBalance = Zero::zero(); // NOTE: The third element might saturate but fine for now since this will run on-chain and need // to be fast. let mut sum_squared: ExtendedBalance = Zero::zero(); - for (_, support) in support.iter() { + for (_, ref support) in support.into_iter() { sum = sum.saturating_add(support.total); let squared = support.total.saturating_mul(support.total); sum_squared = sum_squared.saturating_add(squared); @@ -641,7 +640,8 @@ pub fn evaluate_support( /// /// Note that the third component should be minimized. pub fn is_score_better(this: ElectionScore, that: ElectionScore, epsilon: P) -> bool - where ExtendedBalance: From> +where + ExtendedBalance: From>, { match this .iter() diff --git a/primitives/npos-elections/src/mock.rs b/primitives/npos-elections/src/mock.rs index 32c9d1223862a..33278da8f028e 100644 --- a/primitives/npos-elections/src/mock.rs +++ b/primitives/npos-elections/src/mock.rs @@ -320,7 +320,6 @@ pub(crate) fn run_and_compare( to_elect: usize, ) where ExtendedBalance: From>, - Output: sp_std::ops::Mul, { // run fixed point code. let ElectionResult { winners, assignments } = seq_phragmen::<_, Output>( diff --git a/primitives/npos-elections/src/phragmen.rs b/primitives/npos-elections/src/phragmen.rs index efe462d7b5e6b..404fb70d9a40c 100644 --- a/primitives/npos-elections/src/phragmen.rs +++ b/primitives/npos-elections/src/phragmen.rs @@ -21,15 +21,15 @@ //! to the Maximin problem. use crate::{ - IdentifierT, VoteWeight, Voter, CandidatePtr, ExtendedBalance, setup_inputs, ElectionResult, + balancing, setup_inputs, CandidatePtr, ElectionResult, ExtendedBalance, IdentifierT, + PerThing128, VoteWeight, Voter, }; -use sp_std::prelude::*; use sp_arithmetic::{ - PerThing, InnerOf, Rational128, helpers_128bit::multiply_by_rational, - traits::{Zero, Bounded}, + traits::{Bounded, Zero}, + InnerOf, Rational128, }; -use crate::balancing; +use sp_std::prelude::*; /// The denominator used for loads. Since votes are collected as u64, the smallest ratio that we /// might collect is `1/approval_stake` where approval stake is the sum of votes. Hence, some number @@ -63,7 +63,7 @@ const DEN: ExtendedBalance = ExtendedBalance::max_value(); /// `expect` this to return `Ok`. /// /// This can only fail if the normalization fails. -pub fn seq_phragmen( +pub fn seq_phragmen( rounds: usize, initial_candidates: Vec, initial_voters: Vec<(AccountId, VoteWeight, Vec)>, diff --git a/primitives/npos-elections/src/phragmms.rs b/primitives/npos-elections/src/phragmms.rs index 9b59e22c249b6..f4c4109020397 100644 --- a/primitives/npos-elections/src/phragmms.rs +++ b/primitives/npos-elections/src/phragmms.rs @@ -22,10 +22,10 @@ //! MMS algorithm. use crate::{ - IdentifierT, ElectionResult, ExtendedBalance, setup_inputs, VoteWeight, Voter, CandidatePtr, - balance, + balance, setup_inputs, CandidatePtr, ElectionResult, ExtendedBalance, IdentifierT, PerThing128, + VoteWeight, Voter, }; -use sp_arithmetic::{PerThing, InnerOf, Rational128, traits::Bounded}; +use sp_arithmetic::{traits::Bounded, InnerOf, PerThing, Rational128}; use sp_std::{prelude::*, rc::Rc}; /// Execute the phragmms method. @@ -41,13 +41,14 @@ use sp_std::{prelude::*, rc::Rc}; /// assignments, `assignment.distribution.map(|p| p.deconstruct()).sum()` fails to fit inside /// `UpperOf

`. A user of this crate may statically assert that this can never happen and safely /// `expect` this to return `Ok`. -pub fn phragmms( +pub fn phragmms( to_elect: usize, initial_candidates: Vec, initial_voters: Vec<(AccountId, VoteWeight, Vec)>, balancing_config: Option<(usize, ExtendedBalance)>, ) -> Result, &'static str> - where ExtendedBalance: From> +where + ExtendedBalance: From>, { let (candidates, mut voters) = setup_inputs(initial_candidates, initial_voters); diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index dc7a1a5fdfb97..af42b11de41a3 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -1072,15 +1072,12 @@ mod score { } mod solution_type { - use codec::{Decode, Encode}; use super::AccountId; + use codec::{Decode, Encode}; // these need to come from the same dev-dependency `sp-npos-elections`, not from the crate. - use crate::{ - generate_solution_type, Assignment, - Error as PhragmenError, - }; - use sp_std::{convert::TryInto, fmt::Debug}; + use crate::{generate_solution_type, Assignment, CompactSolution, Error as PhragmenError}; use sp_arithmetic::Percent; + use sp_std::{convert::TryInto, fmt::Debug}; type TestAccuracy = Percent; From 0cb35eb3deffb32e05469f325dd06accdc71d7b9 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 9 Oct 2020 17:44:45 +0200 Subject: [PATCH 07/62] Much simplifications and cleanups. --- frame/election-providers/src/lib.rs | 2 +- frame/election-providers/src/onchain.rs | 9 +- frame/election-providers/src/two_phase/mod.rs | 19 +++- .../src/two_phase/signed.rs | 92 +++++++++---------- 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs index 702a4da6b74b9..65446e234ad8e 100644 --- a/frame/election-providers/src/lib.rs +++ b/frame/election-providers/src/lib.rs @@ -139,7 +139,7 @@ pub trait ElectionProvider { /// /// The implementation should, if possible, use the accuracy `P` to compute the election result. fn elect( - to_elect: usize, // TODO: consider making this u32 + to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, ) -> Result, Self::Error> diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs index 6e82395246a72..29e366f348698 100644 --- a/frame/election-providers/src/onchain.rs +++ b/frame/election-providers/src/onchain.rs @@ -31,14 +31,6 @@ impl ElectionProvider for OnChainSequentialPh where ExtendedBalance: From<

::Inner>, { - // TODO: we really don't need to do this conversion all the time. With - // https://github.com/paritytech/substrate/pull/6685 merged, we should make variants of - // seq_phragmen and others that return a different return type. In fact, I think I should - // rebase this branch there and just build there as well. - // TODO: Okay even if not the above, then def. make the extension traits for converting - // between validator Major and Nominator Major result types, and make the conversions be - // lossless and painless to happen. - let mut stake_map: BTreeMap = BTreeMap::new(); voters.iter().for_each(|(v, s, _)| { stake_map.insert(v.clone(), *s); @@ -49,6 +41,7 @@ impl ElectionProvider for OnChainSequentialPh sp_npos_elections::seq_phragmen::<_, P>(to_elect, targets, voters, None) .and_then(|e| { + // these could use potential simplifications. let ElectionResult { winners, assignments, diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index ec528ee9e6ebe..4e2c556bbf25c 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -294,8 +294,23 @@ impl From for FeasibilityError { } /// The weights for this pallet. -pub trait WeightInfo {} -impl WeightInfo for () {} +pub trait WeightInfo { + fn feasibility_check() -> Weight; + fn submit() -> Weight; + fn submit_unsigned() -> Weight; +} + +impl WeightInfo for () { + fn feasibility_check() -> Weight { + Default::default() + } + fn submit() -> Weight { + Default::default() + } + fn submit_unsigned() -> Weight { + Default::default() + } +} pub trait Trait: frame_system::Trait { /// Event type. diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index ffe953ebe2be4..4d1ae9b0db41b 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -43,9 +43,13 @@ where DesiredTargets::put(desired_targets); } - /// Finish the singed phase. + /// Finish the singed phase. Process the signed submissions from best to worse until a valid one + /// is found, rewarding the best oen and slashing the invalid ones along the way. /// /// Returns true if we have a good solution in the signed phase. + /// + /// This drains the [`SignedSubmissions`], potentially storing the best valid one in + /// [`QueuedSolution`]. pub fn finalize_signed_phase() -> bool { let mut all_submission: Vec> = >::take(); let mut found_solution = false; @@ -85,7 +89,6 @@ where // Any unprocessed solution is not pointless to even ponder upon. Feasible or malicious, // they didn't end up being used. Unreserve the bonds. all_submission.into_iter().for_each(|not_processed| { - dbg!(¬_processed); let SignedSubmission { who, deposit, .. } = not_processed; let _remaining = T::Currency::unreserve(&who, deposit); debug_assert!(_remaining.is_zero()); @@ -96,13 +99,13 @@ where /// Find a proper position in the queue for the signed queue, whilst maintaining the order of /// solution quality. + /// + /// The length of the queue will always be kept less than or equal to `T::MaxSignedSubmissions`. pub fn insert_submission( who: &T::AccountId, queue: &mut Vec, CompactOf>>, solution: RawSolution>, ) -> Option { - // TODO: consider using VecDeQue or sth like that? - // from the last score, compare and see if the current one is better. If none, then the // awarded index is 0. let outcome = queue @@ -110,7 +113,6 @@ where .enumerate() .rev() .find_map(|(i, s)| { - if is_score_better::( solution.score, s.solution.score, @@ -136,7 +138,9 @@ where reward, solution, }; - // TODO: write proof that this cannot panic + // Proof: `at` must always less than or equal queue.len() for this not to panic. + // It is either 0 (in which case `0 <= queue.len()`) or one of the queue indices + // + 1. The biggest queue index is `queue.len() - 1`, thus `at <= queue.len()`. queue.insert(at, submission); if queue.len() as u32 > T::MaxSignedSubmissions::get() { queue.remove(0); @@ -151,12 +155,25 @@ where outcome } + /// Collect sufficient deposit to store this solution this chain. + /// + /// The deposit is composed of 3 main elements: + /// + /// 1. base deposit, fixed for all submissions. + /// 2. a per-byte deposit, for renting the state usage. + /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize pub fn deposit_for(solution: &RawSolution>) -> BalanceOf { let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); - // TODO - T::SignedDepositBase::get() + T::SignedDepositByte::get() * encoded_len + let feasibility_weight = T::WeightInfo::feasibility_check(); + + let len_deposit = T::SignedDepositByte::get() * encoded_len; + let weight_deposit = T::SignedDepositWeight::get() * feasibility_weight.saturated_into(); + + T::SignedDepositBase::get() + len_deposit + weight_deposit } + /// The reward for this solution, if successfully chosen as the best one at the end of the + /// signed phase. pub fn reward_for(solution: &RawSolution>) -> BalanceOf { T::SignedRewardBase::get() + T::SignedRewardFactor::get() * solution.score[0].saturated_into::>() @@ -410,6 +427,10 @@ mod tests { ExtBuilder::default() .max_signed_submission(3) .build_and_execute(|| { + let scores = || TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(); roll_to(5); let solution = RawSolution { @@ -417,78 +438,49 @@ mod tests { ..Default::default() }; assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); - assert_eq!( - TwoPhase::signed_submissions() - .into_iter() - .map(|s| s.solution.score[0]) - .collect::>(), - vec![5] - ); + assert_eq!(scores(), vec![5]); let solution = RawSolution { score: [8, 0, 0], ..Default::default() }; assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); - assert_eq!( - TwoPhase::signed_submissions() - .into_iter() - .map(|s| s.solution.score[0]) - .collect::>(), - vec![5, 8] - ); + assert_eq!(scores(), vec![5, 8]); let solution = RawSolution { score: [3, 0, 0], ..Default::default() }; assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); - assert_eq!( - TwoPhase::signed_submissions() - .into_iter() - .map(|s| s.solution.score[0]) - .collect::>(), - vec![3, 5, 8] - ); + assert_eq!(scores(), vec![3, 5, 8]); let solution = RawSolution { score: [6, 0, 0], ..Default::default() }; assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); - assert_eq!( - TwoPhase::signed_submissions() - .into_iter() - .map(|s| s.solution.score[0]) - .collect::>(), - vec![5, 6, 8] - ); + assert_eq!(scores(), vec![5, 6, 8]); let solution = RawSolution { score: [6, 0, 0], ..Default::default() }; assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); - assert_eq!( - TwoPhase::signed_submissions() - .into_iter() - .map(|s| s.solution.score[0]) - .collect::>(), - vec![6, 6, 8] - ); + assert_eq!(scores(), vec![6, 6, 8]); let solution = RawSolution { score: [10, 0, 0], ..Default::default() }; assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); - assert_eq!( - TwoPhase::signed_submissions() - .into_iter() - .map(|s| s.solution.score[0]) - .collect::>(), - vec![6, 8, 10] - ); + assert_eq!(scores(), vec![6, 8, 10]); + + let solution = RawSolution { + score: [12, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!(scores(), vec![8, 10, 12]); }) } From c1ff3ecf61b6c9500cf0e98ee66a0545e0da6b6c Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 9 Oct 2020 18:03:40 +0200 Subject: [PATCH 08/62] A skeleton for the unsigned version. --- frame/election-providers/expanded.rs | 4615 +++++------------ frame/election-providers/src/two_phase/mod.rs | 65 +- .../src/two_phase/unsigned.rs | 31 + 3 files changed, 1248 insertions(+), 3463 deletions(-) diff --git a/frame/election-providers/expanded.rs b/frame/election-providers/expanded.rs index 887cbf3b5f288..161ab56cc7683 100644 --- a/frame/election-providers/expanded.rs +++ b/frame/election-providers/expanded.rs @@ -1,26 +1,95 @@ #![feature(prelude_import)] +//! Reusable Election Providers. +//! +//! The core functionality of this crate is around [`ElectionProvider`]. An election provider is a +//! struct, module, or anything else that implements [`ElectionProvider`]. Such types can then be +//! passed around to other crates and pallets that need election functionality. +//! +//! Two main election providers are implemented in this crate. +//! +//! 1. [`onchain`]: A `struct` that perform the election onchain (i.e. in the fly). This type is +//! likely to be expensive for most chains and damage the block time. Only use when you are sure +//! that the inputs are bounded and small enough. +//! 2. [`two_phase`]: An individual `pallet` that performs the election in two phases, signed and +//! unsigned. Needless to say, the pallet needs to be included in the final runtime. #[prelude_import] use std::prelude::v1::*; #[macro_use] extern crate std; -use sp_std::prelude::*; +use sp_std::{fmt::Debug, prelude::*}; +/// The onchain module. pub mod onchain { - use crate::{ElectionProvider, Error}; + use crate::{ElectionProvider, FlatSupportMap, FlattenSupportMap}; use sp_arithmetic::PerThing; use sp_npos_elections::{ - ElectionResult, ExtendedBalance, FlatSupportMap, FlattenSupportMap, IdentifierT, VoteWeight, + ElectionResult, ExtendedBalance, IdentifierT, PerThing128, VoteWeight, }; + use sp_runtime::RuntimeDebug; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; + /// Errors of the on-chain election. + pub enum Error { + /// An internal error in the NPoS elections crate. + NposElections(sp_npos_elections::Error), + } + impl core::fmt::Debug for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::NposElections(ref a0) => { + fmt.debug_tuple("Error::NposElections").field(a0).finish() + } + _ => Ok(()), + } + } + } + impl ::core::marker::StructuralEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } + impl ::core::marker::StructuralPartialEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + match (&*self, &*other) { + (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + } + } + #[inline] + fn ne(&self, other: &Error) -> bool { + match (&*self, &*other) { + (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + } + } + } + impl From for Error { + fn from(e: sp_npos_elections::Error) -> Self { + Error::NposElections(e) + } + } pub struct OnChainSequentialPhragmen; impl ElectionProvider for OnChainSequentialPhragmen { - fn elect( + type Error = Error; + const NEEDS_ELECT_DATA: bool = true; + fn elect( to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, - P: sp_std::ops::Mul, { let mut stake_map: BTreeMap = BTreeMap::new(); voters.iter().for_each(|(v, s, _)| { @@ -49,8 +118,100 @@ pub mod onchain { } } } +/// The two-phase module. pub mod two_phase { - use crate::{onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider}; + //! # Two phase election provider pallet. + //! + //! As the name suggests, this election provider has two distinct phases (see [`Phase`]), signed and + //! unsigned. + //! + //! ## Phases + //! + //! The timeline of pallet is as follows. At each block, + //! [`ElectionDataProvider::next_election_prediction`] is used to estimate the time remaining to the + //! next call to `elect`. Based on this, a phase is chosen. The timeline is as follows. + //! + //! ```ignore + //! elect() + //! + <--T::SignedPhase--> + <--T::UnsignedPhase--> + + //! +-------------------------------------------------------------------+ + //! Phase::Off + Phase::Signed + Phase::Unsigned + + //! + //! Note that the unsigned phase starts `T::UnsignedPhase` blocks before the + //! `next_election_prediction`, but only ends when a call to `ElectionProvider::elect` happens. + //! + //! ``` + //! ### Signed Phase + //! + //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A + //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution + //! on-chain for a number of blocks. A maximum of [`Trait::MaxSignedSubmissions`] solutions are + //! stored. The queue is always sorted based on score (worse -> best). + //! + //! Upon arrival of a new solution: + //! + //! 1. If the queue is not full, it is stored. + //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the + //! worse solution is discarded (TODO: what to do with the bond?) and the new solution is stored + //! in the correct index. + //! 3. If the queue is full and the solution is not an improvement compared to any of the queued + //! ones, it is instantly rejected and no additional bond is reserved. + //! + //! A signed solution cannot be reversed, taken back, updated, or retracted. In other words, the + //! origin can not bail out in any way. + //! + //! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed + //! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure + //! the score claimed by this score was correct, among other checks. At each step, if the current + //! best solution is passes the feasibility check, it is considered to be the best one. The sender + //! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without + //! being checked. + //! + //! The following example covers all of the cases at the end of the signed phase: + //! + //! ```ignore + //! Queue + //! +-------------------------------+ + //! |Solution(score=20, valid=false)| +--> Slashed + //! +-------------------------------+ + //! |Solution(score=15, valid=true )| +--> Rewarded + //! +-------------------------------+ + //! |Solution(score=10, valid=true )| +--> Discarded + //! +-------------------------------+ + //! |Solution(score=05, valid=false)| +--> Discarded + //! +-------------------------------+ + //! | None | + //! +-------------------------------+ + //! ``` + //! + //! Note that both of the bottom solutions end up being discarded and get their deposit back, + //! despite one of them being invalid. + //! + //! ## Unsigned Phase + //! + //! If signed phase ends with a good solution, then the unsigned phase will be `active` + //! ([`Phase::Unsigned(true)`]), else the unsigned phase will be `passive`. + //! + //! TODO + //! + //! ### Fallback + //! + //! If we reach the end of both phases (i.e. call to `ElectionProvider::elect` happens) and no good + //! solution is queued, then we fallback to an on-chain election. The on-chain election is slow, and + //! contains to balancing or reduction post-processing. + //! + //! ## Correct Submission + //! + //! TODO + //! + //! ## Accuracy + //! + //! TODO + //! + use crate::{ + onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, FlatSupportMap, + FlattenSupportMap, + }; use codec::{Decode, Encode, HasCompact}; use frame_support::{ decl_error, decl_event, decl_module, decl_storage, @@ -61,17 +222,26 @@ pub mod two_phase { }; use frame_system::{ensure_none, ensure_signed}; use sp_npos_elections::{ - evaluate_support, generate_solution_type, Assignment, ElectionScore, ExtendedBalance, - FlatSupportMap, FlattenSupportMap, VoteWeight, + assignment_ratio_to_staked_normalized, build_support_map, evaluate_support, Assignment, + CompactSolution, ElectionScore, ExtendedBalance, PerThing128, VoteWeight, }; - use sp_runtime::{traits::Zero, PerThing, PerU16, Perbill, RuntimeDebug}; - use sp_std::{mem::size_of, prelude::*}; + use sp_runtime::{traits::Zero, InnerOf, PerThing, Perbill, RuntimeDebug}; + use sp_std::prelude::*; + #[macro_use] + pub(crate) mod macros { + //! Some helper macros for this crate. + } pub mod signed { + //! The signed phase implementation. use crate::two_phase::*; use codec::Encode; use sp_arithmetic::traits::SaturatedConversion; use sp_npos_elections::is_score_better; - impl Module { + use sp_runtime::Perbill; + impl Module + where + ExtendedBalance: From>>, + { /// Start the signed phase. /// /// Upon calling this, auxillary data for election is stored and signed solutions will be @@ -86,11 +256,15 @@ pub mod two_phase { >::put(voters); DesiredTargets::put(desired_targets); } - /// Finish the singed phase. + /// Finish the singed phase. Process the signed submissions from best to worse until a valid one + /// is found, rewarding the best oen and slashing the invalid ones along the way. /// /// Returns true if we have a good solution in the signed phase. + /// + /// This drains the [`SignedSubmissions`], potentially storing the best valid one in + /// [`QueuedSolution`]. pub fn finalize_signed_phase() -> bool { - let mut all_submission: Vec> = + let mut all_submission: Vec> = >::take(); let mut found_solution = false; while let Some(best) = all_submission.pop() { @@ -135,83 +309,6 @@ pub mod two_phase { } } all_submission.into_iter().for_each(|not_processed| { - match ¬_processed { - tmp => { - { - ::std::io::_eprint(::core::fmt::Arguments::new_v1_formatted( - &["[", ":", "] ", " = ", "\n"], - &match ( - &"frame/election-providers/src/two_phase/signed.rs", - &65u32, - &"¬_processed", - &&tmp, - ) { - (arg0, arg1, arg2, arg3) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg2, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg3, - ::core::fmt::Debug::fmt, - ), - ], - }, - &[ - ::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 1usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 2usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 3usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ], - )); - }; - tmp - } - }; let SignedSubmission { who, deposit, .. } = not_processed; let _remaining = T::Currency::unreserve(&who, deposit); if true { @@ -226,17 +323,19 @@ pub mod two_phase { } /// Find a proper position in the queue for the signed queue, whilst maintaining the order of /// solution quality. + /// + /// The length of the queue will always be kept less than or equal to `T::MaxSignedSubmissions`. pub fn insert_submission( who: &T::AccountId, - queue: &mut Vec>>, - solution: RawSolution, + queue: &mut Vec, CompactOf>>, + solution: RawSolution>, ) -> Option { let outcome = queue .iter() .enumerate() .rev() .find_map(|(i, s)| { - if is_score_better( + if is_score_better::( solution.score, s.solution.score, T::SolutionImprovementThreshold::get(), @@ -258,2809 +357,86 @@ pub mod two_phase { deposit, reward, solution, - }; - queue.insert(at, submission); - if queue.len() as u32 > T::MaxSignedSubmissions::get() { - queue.remove(0); - Some(at - 1) - } else { - Some(at) - } - } - }); - if true { - if !(queue.len() as u32 <= T::MaxSignedSubmissions::get()) { - { - :: std :: rt :: begin_panic ( "assertion failed: queue.len() as u32 <= T::MaxSignedSubmissions::get()" ) - } - }; - }; - outcome - } - pub fn deposit_for(solution: &RawSolution) -> BalanceOf { - let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); - T::SignedDepositBase::get() + T::SignedDepositByte::get() * encoded_len - } - pub fn reward_for(solution: &RawSolution) -> BalanceOf { - T::SignedRewardBase::get() - + T::SignedRewardFactor::get() - * solution.score[0].saturated_into::>() - } - } - } - pub mod unsigned {} - type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - type PositiveImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::PositiveImbalance; - type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::NegativeImbalance; - /// Accuracy used for on-chain election. - pub type ChainAccuracy = Perbill; - /// Accuracy used for off-chain election. This better be small. - pub type OffchainAccuracy = PerU16; - /// Data type used to index nominators in the compact type. - pub type VoterIndex = u32; - /// Data type used to index validators in the compact type. - pub type TargetIndex = u16; - #[allow(unknown_lints, eq_op)] - const _: [(); 0 - !{ - const ASSERT: bool = size_of::() <= size_of::(); - ASSERT - } as usize] = []; - #[allow(unknown_lints, eq_op)] - const _: [(); 0 - !{ - const ASSERT: bool = size_of::() <= size_of::(); - ASSERT - } as usize] = []; - #[allow(unknown_lints, eq_op)] - const _: [(); 0 - !{ - const ASSERT: bool = size_of::() <= size_of::(); - ASSERT - } as usize] = []; - #[allow(unknown_lints, eq_op)] - const _: [(); 0 - !{ - const ASSERT: bool = size_of::() <= size_of::(); - ASSERT - } as usize] = []; - extern crate sp_npos_elections as _npos; - /// A struct to encode a election assignment in a compact way. - impl _npos::codec::Encode for CompactAssignments { - fn encode(&self) -> Vec { - let mut r = ::alloc::vec::Vec::new(); - let votes1 = self - .votes1 - .iter() - .map(|(v, t)| { - ( - _npos::codec::Compact(v.clone()), - _npos::codec::Compact(t.clone()), - ) - }) - .collect::>(); - votes1.encode_to(&mut r); - let votes2 = self - .votes2 - .iter() - .map(|(v, (t1, w), t2)| { - ( - _npos::codec::Compact(v.clone()), - ( - _npos::codec::Compact(t1.clone()), - _npos::codec::Compact(w.clone()), - ), - _npos::codec::Compact(t2.clone()), - ) - }) - .collect::>(); - votes2.encode_to(&mut r); - let votes3 = self - .votes3 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes3.encode_to(&mut r); - let votes4 = self - .votes4 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes4.encode_to(&mut r); - let votes5 = self - .votes5 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes5.encode_to(&mut r); - let votes6 = self - .votes6 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes6.encode_to(&mut r); - let votes7 = self - .votes7 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes7.encode_to(&mut r); - let votes8 = self - .votes8 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes8.encode_to(&mut r); - let votes9 = self - .votes9 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes9.encode_to(&mut r); - let votes10 = self - .votes10 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes10.encode_to(&mut r); - let votes11 = self - .votes11 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes11.encode_to(&mut r); - let votes12 = self - .votes12 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes12.encode_to(&mut r); - let votes13 = self - .votes13 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes13.encode_to(&mut r); - let votes14 = self - .votes14 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[12usize].0.clone()), - _npos::codec::Compact(inner[12usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes14.encode_to(&mut r); - let votes15 = self - .votes15 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[12usize].0.clone()), - _npos::codec::Compact(inner[12usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[13usize].0.clone()), - _npos::codec::Compact(inner[13usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes15.encode_to(&mut r); - let votes16 = self - .votes16 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[12usize].0.clone()), - _npos::codec::Compact(inner[12usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[13usize].0.clone()), - _npos::codec::Compact(inner[13usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[14usize].0.clone()), - _npos::codec::Compact(inner[14usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes16.encode_to(&mut r); - r - } - } - impl _npos::codec::Decode for CompactAssignments { - fn decode(value: &mut I) -> Result { - let votes1 = , - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes1 = votes1 - .into_iter() - .map(|(v, t)| (v.0, t.0)) - .collect::>(); - let votes2 = , - ( - _npos::codec::Compact, - _npos::codec::Compact, - ), - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes2 = votes2 - .into_iter() - .map(|(v, (t1, w), t2)| (v.0, (t1.0, w.0), t2.0)) - .collect::>(); - let votes3 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 3usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes3 = votes3 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes4 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 4usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes4 = votes4 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes5 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 5usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes5 = votes5 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes6 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 6usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes6 = votes6 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes7 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 7usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes7 = votes7 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes8 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 8usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes8 = votes8 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes9 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 9usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes9 = votes9 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes10 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 10usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes10 = votes10 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes11 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 11usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes11 = votes11 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes12 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 12usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes12 = votes12 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes13 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 13usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes13 = votes13 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes14 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 14usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes14 = votes14 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ((inner[12usize].0).0, (inner[12usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes15 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 15usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes15 = votes15 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ((inner[12usize].0).0, (inner[12usize].1).0), - ((inner[13usize].0).0, (inner[13usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes16 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 16usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes16 = votes16 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ((inner[12usize].0).0, (inner[12usize].1).0), - ((inner[13usize].0).0, (inner[13usize].1).0), - ((inner[14usize].0).0, (inner[14usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - Ok(CompactAssignments { - votes1, - votes2, - votes3, - votes4, - votes5, - votes6, - votes7, - votes8, - votes9, - votes10, - votes11, - votes12, - votes13, - votes14, - votes15, - votes16, - }) - } - } - pub struct CompactAssignments { - votes1: Vec<(VoterIndex, TargetIndex)>, - votes2: Vec<(VoterIndex, (TargetIndex, OffchainAccuracy), TargetIndex)>, - votes3: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 2usize], - TargetIndex, - )>, - votes4: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 3usize], - TargetIndex, - )>, - votes5: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 4usize], - TargetIndex, - )>, - votes6: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 5usize], - TargetIndex, - )>, - votes7: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 6usize], - TargetIndex, - )>, - votes8: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 7usize], - TargetIndex, - )>, - votes9: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 8usize], - TargetIndex, - )>, - votes10: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 9usize], - TargetIndex, - )>, - votes11: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 10usize], - TargetIndex, - )>, - votes12: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 11usize], - TargetIndex, - )>, - votes13: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 12usize], - TargetIndex, - )>, - votes14: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 13usize], - TargetIndex, - )>, - votes15: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 14usize], - TargetIndex, - )>, - votes16: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 15usize], - TargetIndex, - )>, - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for CompactAssignments { - #[inline] - fn default() -> CompactAssignments { - CompactAssignments { - votes1: ::core::default::Default::default(), - votes2: ::core::default::Default::default(), - votes3: ::core::default::Default::default(), - votes4: ::core::default::Default::default(), - votes5: ::core::default::Default::default(), - votes6: ::core::default::Default::default(), - votes7: ::core::default::Default::default(), - votes8: ::core::default::Default::default(), - votes9: ::core::default::Default::default(), - votes10: ::core::default::Default::default(), - votes11: ::core::default::Default::default(), - votes12: ::core::default::Default::default(), - votes13: ::core::default::Default::default(), - votes14: ::core::default::Default::default(), - votes15: ::core::default::Default::default(), - votes16: ::core::default::Default::default(), - } - } - } - impl ::core::marker::StructuralPartialEq for CompactAssignments {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for CompactAssignments { - #[inline] - fn eq(&self, other: &CompactAssignments) -> bool { - match *other { - CompactAssignments { - votes1: ref __self_1_0, - votes2: ref __self_1_1, - votes3: ref __self_1_2, - votes4: ref __self_1_3, - votes5: ref __self_1_4, - votes6: ref __self_1_5, - votes7: ref __self_1_6, - votes8: ref __self_1_7, - votes9: ref __self_1_8, - votes10: ref __self_1_9, - votes11: ref __self_1_10, - votes12: ref __self_1_11, - votes13: ref __self_1_12, - votes14: ref __self_1_13, - votes15: ref __self_1_14, - votes16: ref __self_1_15, - } => match *self { - CompactAssignments { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - && (*__self_0_3) == (*__self_1_3) - && (*__self_0_4) == (*__self_1_4) - && (*__self_0_5) == (*__self_1_5) - && (*__self_0_6) == (*__self_1_6) - && (*__self_0_7) == (*__self_1_7) - && (*__self_0_8) == (*__self_1_8) - && (*__self_0_9) == (*__self_1_9) - && (*__self_0_10) == (*__self_1_10) - && (*__self_0_11) == (*__self_1_11) - && (*__self_0_12) == (*__self_1_12) - && (*__self_0_13) == (*__self_1_13) - && (*__self_0_14) == (*__self_1_14) - && (*__self_0_15) == (*__self_1_15) - } - }, - } - } - #[inline] - fn ne(&self, other: &CompactAssignments) -> bool { - match *other { - CompactAssignments { - votes1: ref __self_1_0, - votes2: ref __self_1_1, - votes3: ref __self_1_2, - votes4: ref __self_1_3, - votes5: ref __self_1_4, - votes6: ref __self_1_5, - votes7: ref __self_1_6, - votes8: ref __self_1_7, - votes9: ref __self_1_8, - votes10: ref __self_1_9, - votes11: ref __self_1_10, - votes12: ref __self_1_11, - votes13: ref __self_1_12, - votes14: ref __self_1_13, - votes15: ref __self_1_14, - votes16: ref __self_1_15, - } => match *self { - CompactAssignments { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) - || (*__self_0_2) != (*__self_1_2) - || (*__self_0_3) != (*__self_1_3) - || (*__self_0_4) != (*__self_1_4) - || (*__self_0_5) != (*__self_1_5) - || (*__self_0_6) != (*__self_1_6) - || (*__self_0_7) != (*__self_1_7) - || (*__self_0_8) != (*__self_1_8) - || (*__self_0_9) != (*__self_1_9) - || (*__self_0_10) != (*__self_1_10) - || (*__self_0_11) != (*__self_1_11) - || (*__self_0_12) != (*__self_1_12) - || (*__self_0_13) != (*__self_1_13) - || (*__self_0_14) != (*__self_1_14) - || (*__self_0_15) != (*__self_1_15) - } - }, - } - } - } - impl ::core::marker::StructuralEq for CompactAssignments {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for CompactAssignments { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq< - Vec<(VoterIndex, (TargetIndex, OffchainAccuracy), TargetIndex)>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 2usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 3usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 4usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 5usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 6usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 7usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 8usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 9usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 10usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 11usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 12usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 13usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 14usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 15usize], - TargetIndex, - )>, - >; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for CompactAssignments { - #[inline] - fn clone(&self) -> CompactAssignments { - match *self { - CompactAssignments { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => CompactAssignments { - votes1: ::core::clone::Clone::clone(&(*__self_0_0)), - votes2: ::core::clone::Clone::clone(&(*__self_0_1)), - votes3: ::core::clone::Clone::clone(&(*__self_0_2)), - votes4: ::core::clone::Clone::clone(&(*__self_0_3)), - votes5: ::core::clone::Clone::clone(&(*__self_0_4)), - votes6: ::core::clone::Clone::clone(&(*__self_0_5)), - votes7: ::core::clone::Clone::clone(&(*__self_0_6)), - votes8: ::core::clone::Clone::clone(&(*__self_0_7)), - votes9: ::core::clone::Clone::clone(&(*__self_0_8)), - votes10: ::core::clone::Clone::clone(&(*__self_0_9)), - votes11: ::core::clone::Clone::clone(&(*__self_0_10)), - votes12: ::core::clone::Clone::clone(&(*__self_0_11)), - votes13: ::core::clone::Clone::clone(&(*__self_0_12)), - votes14: ::core::clone::Clone::clone(&(*__self_0_13)), - votes15: ::core::clone::Clone::clone(&(*__self_0_14)), - votes16: ::core::clone::Clone::clone(&(*__self_0_15)), - }, - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::fmt::Debug for CompactAssignments { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match *self { - CompactAssignments { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => { - let mut debug_trait_builder = f.debug_struct("CompactAssignments"); - let _ = debug_trait_builder.field("votes1", &&(*__self_0_0)); - let _ = debug_trait_builder.field("votes2", &&(*__self_0_1)); - let _ = debug_trait_builder.field("votes3", &&(*__self_0_2)); - let _ = debug_trait_builder.field("votes4", &&(*__self_0_3)); - let _ = debug_trait_builder.field("votes5", &&(*__self_0_4)); - let _ = debug_trait_builder.field("votes6", &&(*__self_0_5)); - let _ = debug_trait_builder.field("votes7", &&(*__self_0_6)); - let _ = debug_trait_builder.field("votes8", &&(*__self_0_7)); - let _ = debug_trait_builder.field("votes9", &&(*__self_0_8)); - let _ = debug_trait_builder.field("votes10", &&(*__self_0_9)); - let _ = debug_trait_builder.field("votes11", &&(*__self_0_10)); - let _ = debug_trait_builder.field("votes12", &&(*__self_0_11)); - let _ = debug_trait_builder.field("votes13", &&(*__self_0_12)); - let _ = debug_trait_builder.field("votes14", &&(*__self_0_13)); - let _ = debug_trait_builder.field("votes15", &&(*__self_0_14)); - let _ = debug_trait_builder.field("votes16", &&(*__self_0_15)); - debug_trait_builder.finish() - } - } - } - } - impl _npos::VotingLimit for CompactAssignments { - const LIMIT: usize = 16usize; - } - impl CompactAssignments { - /// Get the length of all the assignments that this type is encoding. This is basically - /// the same as the number of assignments, or the number of voters in total. - pub fn len(&self) -> usize { - let mut all_len = 0usize; - all_len = all_len.saturating_add(self.votes1.len()); - all_len = all_len.saturating_add(self.votes2.len()); - all_len = all_len.saturating_add(self.votes3.len()); - all_len = all_len.saturating_add(self.votes4.len()); - all_len = all_len.saturating_add(self.votes5.len()); - all_len = all_len.saturating_add(self.votes6.len()); - all_len = all_len.saturating_add(self.votes7.len()); - all_len = all_len.saturating_add(self.votes8.len()); - all_len = all_len.saturating_add(self.votes9.len()); - all_len = all_len.saturating_add(self.votes10.len()); - all_len = all_len.saturating_add(self.votes11.len()); - all_len = all_len.saturating_add(self.votes12.len()); - all_len = all_len.saturating_add(self.votes13.len()); - all_len = all_len.saturating_add(self.votes14.len()); - all_len = all_len.saturating_add(self.votes15.len()); - all_len = all_len.saturating_add(self.votes16.len()); - all_len - } - /// Get the total count of edges. - pub fn edge_count(&self) -> usize { - let mut all_edges = 0usize; - all_edges = all_edges.saturating_add(self.votes1.len().saturating_mul(1usize as usize)); - all_edges = all_edges.saturating_add(self.votes2.len().saturating_mul(2usize as usize)); - all_edges = all_edges.saturating_add(self.votes3.len().saturating_mul(3usize as usize)); - all_edges = all_edges.saturating_add(self.votes4.len().saturating_mul(4usize as usize)); - all_edges = all_edges.saturating_add(self.votes5.len().saturating_mul(5usize as usize)); - all_edges = all_edges.saturating_add(self.votes6.len().saturating_mul(6usize as usize)); - all_edges = all_edges.saturating_add(self.votes7.len().saturating_mul(7usize as usize)); - all_edges = all_edges.saturating_add(self.votes8.len().saturating_mul(8usize as usize)); - all_edges = all_edges.saturating_add(self.votes9.len().saturating_mul(9usize as usize)); - all_edges = - all_edges.saturating_add(self.votes10.len().saturating_mul(10usize as usize)); - all_edges = - all_edges.saturating_add(self.votes11.len().saturating_mul(11usize as usize)); - all_edges = - all_edges.saturating_add(self.votes12.len().saturating_mul(12usize as usize)); - all_edges = - all_edges.saturating_add(self.votes13.len().saturating_mul(13usize as usize)); - all_edges = - all_edges.saturating_add(self.votes14.len().saturating_mul(14usize as usize)); - all_edges = - all_edges.saturating_add(self.votes15.len().saturating_mul(15usize as usize)); - all_edges = - all_edges.saturating_add(self.votes16.len().saturating_mul(16usize as usize)); - all_edges - } - /// 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. - /// - /// The resulting indices are sorted. - pub fn unique_targets(&self) -> Vec { - let mut all_targets: Vec = Vec::with_capacity(self.average_edge_count()); - let mut maybe_insert_target = |t: TargetIndex| match all_targets.binary_search(&t) { - Ok(_) => (), - Err(pos) => all_targets.insert(pos, t), - }; - self.votes1.iter().for_each(|(_, t)| { - maybe_insert_target(*t); - }); - self.votes2.iter().for_each(|(_, (t1, _), t2)| { - maybe_insert_target(*t1); - maybe_insert_target(*t2); - }); - self.votes3.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes4.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes5.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes6.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes7.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes8.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes9.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes10.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes11.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes12.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes13.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes14.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes15.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes16.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - all_targets - } - /// Get the average edge count. - pub fn average_edge_count(&self) -> usize { - self.edge_count().checked_div(self.len()).unwrap_or(0) - } - /// 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 from - /// `self.len()`. - pub fn remove_voter(&mut self, to_remove: VoterIndex) -> bool { - if let Some(idx) = self.votes1.iter().position(|(x, _)| *x == to_remove) { - self.votes1.remove(idx); - return true; - } - if let Some(idx) = self.votes2.iter().position(|(x, _, _)| *x == to_remove) { - self.votes2.remove(idx); - return true; - } - if let Some(idx) = self.votes3.iter().position(|(x, _, _)| *x == to_remove) { - self.votes3.remove(idx); - return true; - } - if let Some(idx) = self.votes4.iter().position(|(x, _, _)| *x == to_remove) { - self.votes4.remove(idx); - return true; - } - if let Some(idx) = self.votes5.iter().position(|(x, _, _)| *x == to_remove) { - self.votes5.remove(idx); - return true; - } - if let Some(idx) = self.votes6.iter().position(|(x, _, _)| *x == to_remove) { - self.votes6.remove(idx); - return true; - } - if let Some(idx) = self.votes7.iter().position(|(x, _, _)| *x == to_remove) { - self.votes7.remove(idx); - return true; - } - if let Some(idx) = self.votes8.iter().position(|(x, _, _)| *x == to_remove) { - self.votes8.remove(idx); - return true; - } - if let Some(idx) = self.votes9.iter().position(|(x, _, _)| *x == to_remove) { - self.votes9.remove(idx); - return true; - } - if let Some(idx) = self.votes10.iter().position(|(x, _, _)| *x == to_remove) { - self.votes10.remove(idx); - return true; - } - if let Some(idx) = self.votes11.iter().position(|(x, _, _)| *x == to_remove) { - self.votes11.remove(idx); - return true; - } - if let Some(idx) = self.votes12.iter().position(|(x, _, _)| *x == to_remove) { - self.votes12.remove(idx); - return true; - } - if let Some(idx) = self.votes13.iter().position(|(x, _, _)| *x == to_remove) { - self.votes13.remove(idx); - return true; - } - if let Some(idx) = self.votes14.iter().position(|(x, _, _)| *x == to_remove) { - self.votes14.remove(idx); - return true; - } - if let Some(idx) = self.votes15.iter().position(|(x, _, _)| *x == to_remove) { - self.votes15.remove(idx); - return true; - } - if let Some(idx) = self.votes16.iter().position(|(x, _, _)| *x == to_remove) { - self.votes16.remove(idx); - return true; - } - return false; - } - } - use _npos::__OrInvalidIndex; - impl CompactAssignments { - pub fn from_assignment( - assignments: Vec<_npos::Assignment>, - index_of_voter: FV, - index_of_target: FT, - ) -> Result - where - A: _npos::IdentifierT, - for<'r> FV: Fn(&'r A) -> Option, - for<'r> FT: Fn(&'r A) -> Option, - { - let mut compact: CompactAssignments = Default::default(); - for _npos::Assignment { who, distribution } in assignments { - match distribution.len() { - 0 => continue, - 1 => compact.votes1.push(( - index_of_voter(&who).or_invalid_index()?, - index_of_target(&distribution[0].0).or_invalid_index()?, - )), - 2 => compact.votes2.push(( - index_of_voter(&who).or_invalid_index()?, - ( - index_of_target(&distribution[0].0).or_invalid_index()?, - distribution[0].1, - ), - index_of_target(&distribution[1].0).or_invalid_index()?, - )), - 3usize => compact.votes3.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ], - index_of_target(&distribution[2usize].0).or_invalid_index()?, - )), - 4usize => compact.votes4.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ], - index_of_target(&distribution[3usize].0).or_invalid_index()?, - )), - 5usize => compact.votes5.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ], - index_of_target(&distribution[4usize].0).or_invalid_index()?, - )), - 6usize => compact.votes6.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ], - index_of_target(&distribution[5usize].0).or_invalid_index()?, - )), - 7usize => compact.votes7.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ], - index_of_target(&distribution[6usize].0).or_invalid_index()?, - )), - 8usize => compact.votes8.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ], - index_of_target(&distribution[7usize].0).or_invalid_index()?, - )), - 9usize => compact.votes9.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ], - index_of_target(&distribution[8usize].0).or_invalid_index()?, - )), - 10usize => compact.votes10.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ], - index_of_target(&distribution[9usize].0).or_invalid_index()?, - )), - 11usize => compact.votes11.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ], - index_of_target(&distribution[10usize].0).or_invalid_index()?, - )), - 12usize => compact.votes12.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ], - index_of_target(&distribution[11usize].0).or_invalid_index()?, - )), - 13usize => compact.votes13.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), - ], - index_of_target(&distribution[12usize].0).or_invalid_index()?, - )), - 14usize => compact.votes14.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), - ( - index_of_target(&distribution[12usize].0).or_invalid_index()?, - distribution[12usize].1, - ), - ], - index_of_target(&distribution[13usize].0).or_invalid_index()?, - )), - 15usize => compact.votes15.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), - ( - index_of_target(&distribution[12usize].0).or_invalid_index()?, - distribution[12usize].1, - ), - ( - index_of_target(&distribution[13usize].0).or_invalid_index()?, - distribution[13usize].1, - ), - ], - index_of_target(&distribution[14usize].0).or_invalid_index()?, - )), - 16usize => compact.votes16.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), - ( - index_of_target(&distribution[12usize].0).or_invalid_index()?, - distribution[12usize].1, - ), - ( - index_of_target(&distribution[13usize].0).or_invalid_index()?, - distribution[13usize].1, - ), - ( - index_of_target(&distribution[14usize].0).or_invalid_index()?, - distribution[14usize].1, - ), - ], - index_of_target(&distribution[15usize].0).or_invalid_index()?, - )), - _ => { - return Err(_npos::Error::CompactTargetOverflow); - } - } - } - Ok(compact) - } - pub fn into_assignment( - self, - voter_at: impl Fn(VoterIndex) -> Option, - target_at: impl Fn(TargetIndex) -> Option, - ) -> Result>, _npos::Error> { - let mut assignments: Vec<_npos::Assignment> = Default::default(); - for (voter_index, target_index) in self.votes1 { - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: <[_]>::into_vec(box [( - target_at(target_index).or_invalid_index()?, - OffchainAccuracy::one(), - )]), - }) - } - for (voter_index, (t1_idx, p1), t2_idx) in self.votes2 { - if p1 >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p2 = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - p1, - ); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: <[_]>::into_vec(box [ - (target_at(t1_idx).or_invalid_index()?, p1), - (target_at(t2_idx).or_invalid_index()?, p2), - ]), - }); - } - for (voter_index, inners, t_last_idx) in self.votes3 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes4 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes5 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes6 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes7 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes8 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes9 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes10 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes11 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes12 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes13 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes14 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes15 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); + }; + queue.insert(at, submission); + if queue.len() as u32 > T::MaxSignedSubmissions::get() { + queue.remove(0); + Some(at - 1) + } else { + Some(at) + } + } + }); + if true { + if !(queue.len() as u32 <= T::MaxSignedSubmissions::get()) { + { + :: std :: rt :: begin_panic ( "assertion failed: queue.len() as u32 <= T::MaxSignedSubmissions::get()" ) + } + }; + }; + outcome } - for (voter_index, inners, t_last_idx) in self.votes16 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); + /// Collect sufficient deposit to store this solution this chain. + /// + /// The deposit is composed of 3 main elements: + /// + /// 1. base deposit, fixed for all submissions. + /// 2. a per-byte deposit, for renting the state usage. + /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize + pub fn deposit_for(solution: &RawSolution>) -> BalanceOf { + let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); + let feasibility_weight = T::WeightInfo::feasibility_check(); + let len_deposit = T::SignedDepositByte::get() * encoded_len; + let weight_deposit = + T::SignedDepositWeight::get() * feasibility_weight.saturated_into(); + T::SignedDepositBase::get() + len_deposit + weight_deposit + } + /// The reward for this solution, if successfully chosen as the best one at the end of the + /// signed phase. + pub fn reward_for(solution: &RawSolution>) -> BalanceOf { + T::SignedRewardBase::get() + + T::SignedRewardFactor::get() + * solution.score[0].saturated_into::>() } - Ok(assignments) } } + pub mod unsigned { + //! The unsigned phase implementation. + use crate::two_phase::*; + use codec::Encode; + use sp_arithmetic::traits::SaturatedConversion; + use sp_npos_elections::is_score_better; + use sp_runtime::Perbill; + impl Module where ExtendedBalance: From>> {} + } + /// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] + /// implementer. + pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< + ::AccountId, + ::BlockNumber, + >>::CompactSolution; + /// The voter index. Derived from [`CompactOf`]. + pub type CompactVoterIndexOf = as CompactSolution>::Voter; + /// The target index. Derived from [`CompactOf`]. + pub type CompactTargetIndexOf = as CompactSolution>::Target; + /// The accuracy of the election. Derived from [`CompactOf`]. + pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; + type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + type PositiveImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::PositiveImbalance; + type NegativeImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::NegativeImbalance; const LOG_TARGET: &'static str = "two-phase-submission"; + /// Current phase of the pallet. pub enum Phase { + /// Nothing, the election is not happening. Off, + /// Signed phase is open. Signed, + /// Unsigned phase is open. Unsigned(bool), } impl ::core::marker::StructuralPartialEq for Phase {} @@ -3190,24 +566,28 @@ pub mod two_phase { } } impl Phase { + /// Weather the phase is signed or not. pub fn is_signed(&self) -> bool { match self { Phase::Signed => true, _ => false, } } + /// Weather the phase is unsigned or not. pub fn is_unsigned(&self) -> bool { match self { Phase::Unsigned(_) => true, _ => false, } } + /// Weather the phase is unsigned and open or not. pub fn is_unsigned_open(&self) -> bool { match self { Phase::Unsigned(true) => true, _ => false, } } + /// Weather the phase is off or not. pub fn is_off(&self) -> bool { match self { Phase::Off => true, @@ -3215,9 +595,13 @@ pub mod two_phase { } } } + /// The type of `Computation` that provided this election data. pub enum ElectionCompute { + /// Election was computed on-chain. OnChain, + /// Election was computed with a signed submission. Signed, + /// Election was computed with an unsigned submission. Unsigned, } impl ::core::marker::StructuralPartialEq for ElectionCompute {} @@ -3316,84 +700,74 @@ pub mod two_phase { ElectionCompute::OnChain } } - pub struct RawSolution { - winners: Vec, - compact: CompactAssignments, + /// A raw, unchecked solution. + /// + /// Such a solution should never become effective in anyway before being checked by the + /// [`Module::feasibility_check`] + pub struct RawSolution { + /// Compact election edges. + compact: C, + /// The _claimed_ score of the solution. score: ElectionScore, } - impl ::core::marker::StructuralPartialEq for RawSolution {} + impl ::core::marker::StructuralPartialEq for RawSolution {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for RawSolution { + impl ::core::cmp::PartialEq for RawSolution { #[inline] - fn eq(&self, other: &RawSolution) -> bool { + fn eq(&self, other: &RawSolution) -> bool { match *other { RawSolution { - winners: ref __self_1_0, - compact: ref __self_1_1, - score: ref __self_1_2, + compact: ref __self_1_0, + score: ref __self_1_1, } => match *self { RawSolution { - winners: ref __self_0_0, - compact: ref __self_0_1, - score: ref __self_0_2, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - } + compact: ref __self_0_0, + score: ref __self_0_1, + } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), }, } } #[inline] - fn ne(&self, other: &RawSolution) -> bool { + fn ne(&self, other: &RawSolution) -> bool { match *other { RawSolution { - winners: ref __self_1_0, - compact: ref __self_1_1, - score: ref __self_1_2, + compact: ref __self_1_0, + score: ref __self_1_1, } => match *self { RawSolution { - winners: ref __self_0_0, - compact: ref __self_0_1, - score: ref __self_0_2, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) - || (*__self_0_2) != (*__self_1_2) - } + compact: ref __self_0_0, + score: ref __self_0_1, + } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), }, } } } - impl ::core::marker::StructuralEq for RawSolution {} + impl ::core::marker::StructuralEq for RawSolution {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq for RawSolution { + impl ::core::cmp::Eq for RawSolution { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; } } } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::clone::Clone for RawSolution { + impl ::core::clone::Clone for RawSolution { #[inline] - fn clone(&self) -> RawSolution { + fn clone(&self) -> RawSolution { match *self { RawSolution { - winners: ref __self_0_0, - compact: ref __self_0_1, - score: ref __self_0_2, + compact: ref __self_0_0, + score: ref __self_0_1, } => RawSolution { - winners: ::core::clone::Clone::clone(&(*__self_0_0)), - compact: ::core::clone::Clone::clone(&(*__self_0_1)), - score: ::core::clone::Clone::clone(&(*__self_0_2)), + compact: ::core::clone::Clone::clone(&(*__self_0_0)), + score: ::core::clone::Clone::clone(&(*__self_0_1)), }, } } @@ -3402,31 +776,36 @@ pub mod two_phase { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for RawSolution { + impl _parity_scale_codec::Encode for RawSolution + where + C: _parity_scale_codec::Encode, + C: _parity_scale_codec::Encode, + { fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.winners); dest.push(&self.compact); dest.push(&self.score); } } - impl _parity_scale_codec::EncodeLike for RawSolution {} + impl _parity_scale_codec::EncodeLike for RawSolution + where + C: _parity_scale_codec::Encode, + C: _parity_scale_codec::Encode, + { + } }; const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for RawSolution { + impl _parity_scale_codec::Decode for RawSolution + where + C: _parity_scale_codec::Decode, + C: _parity_scale_codec::Decode, + { fn decode( input: &mut DecIn, ) -> core::result::Result { Ok(RawSolution { - winners: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field RawSolution.winners".into()), - Ok(a) => a, - } - }, compact: { let res = _parity_scale_codec::Decode::decode(input); match res { @@ -3445,10 +824,12 @@ pub mod two_phase { } } }; - impl core::fmt::Debug for RawSolution { + impl core::fmt::Debug for RawSolution + where + C: core::fmt::Debug, + { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { fmt.debug_struct("RawSolution") - .field("winners", &self.winners) .field("compact", &self.compact) .field("score", &self.score) .finish() @@ -3456,33 +837,39 @@ pub mod two_phase { } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::default::Default for RawSolution { + impl ::core::default::Default for RawSolution { #[inline] - fn default() -> RawSolution { + fn default() -> RawSolution { RawSolution { - winners: ::core::default::Default::default(), compact: ::core::default::Default::default(), score: ::core::default::Default::default(), } } } - pub struct SignedSubmission { - who: AccountId, - deposit: Balance, - reward: Balance, - solution: RawSolution, - } - impl ::core::marker::StructuralPartialEq - for SignedSubmission - { - } + /// A raw, unchecked signed submission. + /// + /// This is just a wrapper around [`RawSolution`] and some additional info. + pub struct SignedSubmission { + /// Who submitted this solution. + who: A, + /// The deposit reserved for storing this solution. + deposit: B, + /// The reward that should be given to this solution, if chosen the as the final one. + reward: B, + /// The raw solution itself. + solution: RawSolution, + } + impl ::core::marker::StructuralPartialEq for SignedSubmission {} #[automatically_derived] #[allow(unused_qualifications)] - impl - ::core::cmp::PartialEq for SignedSubmission + impl< + A: ::core::cmp::PartialEq, + B: ::core::cmp::PartialEq + HasCompact, + C: ::core::cmp::PartialEq, + > ::core::cmp::PartialEq for SignedSubmission { #[inline] - fn eq(&self, other: &SignedSubmission) -> bool { + fn eq(&self, other: &SignedSubmission) -> bool { match *other { SignedSubmission { who: ref __self_1_0, @@ -3505,7 +892,7 @@ pub mod two_phase { } } #[inline] - fn ne(&self, other: &SignedSubmission) -> bool { + fn ne(&self, other: &SignedSubmission) -> bool { match *other { SignedSubmission { who: ref __self_1_0, @@ -3528,33 +915,33 @@ pub mod two_phase { } } } - impl ::core::marker::StructuralEq - for SignedSubmission - { - } + impl ::core::marker::StructuralEq for SignedSubmission {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq - for SignedSubmission + impl ::core::cmp::Eq + for SignedSubmission { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq>; } } } #[automatically_derived] #[allow(unused_qualifications)] - impl - ::core::clone::Clone for SignedSubmission + impl< + A: ::core::clone::Clone, + B: ::core::clone::Clone + HasCompact, + C: ::core::clone::Clone, + > ::core::clone::Clone for SignedSubmission { #[inline] - fn clone(&self) -> SignedSubmission { + fn clone(&self) -> SignedSubmission { match *self { SignedSubmission { who: ref __self_0_0, @@ -3574,15 +961,16 @@ pub mod two_phase { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode - for SignedSubmission + impl _parity_scale_codec::Encode for SignedSubmission where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, + A: _parity_scale_codec::Encode, + A: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, { fn encode_to(&self, dest: &mut EncOut) { dest.push(&self.who); @@ -3591,15 +979,16 @@ pub mod two_phase { dest.push(&self.solution); } } - impl _parity_scale_codec::EncodeLike - for SignedSubmission + impl _parity_scale_codec::EncodeLike for SignedSubmission where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, + A: _parity_scale_codec::Encode, + A: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, { } }; @@ -3607,15 +996,16 @@ pub mod two_phase { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode - for SignedSubmission + impl _parity_scale_codec::Decode for SignedSubmission where - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - Balance: _parity_scale_codec::Decode, - Balance: _parity_scale_codec::Decode, - Balance: _parity_scale_codec::Decode, - Balance: _parity_scale_codec::Decode, + A: _parity_scale_codec::Decode, + A: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + RawSolution: _parity_scale_codec::Decode, + RawSolution: _parity_scale_codec::Decode, { fn decode( input: &mut DecIn, @@ -3661,10 +1051,11 @@ pub mod two_phase { } } }; - impl core::fmt::Debug for SignedSubmission + impl core::fmt::Debug for SignedSubmission where - AccountId: core::fmt::Debug, - Balance: core::fmt::Debug, + A: core::fmt::Debug, + B: core::fmt::Debug, + C: core::fmt::Debug, { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { fmt.debug_struct("SignedSubmission") @@ -3675,85 +1066,72 @@ pub mod two_phase { .finish() } } - /// A parsed solution, ready to be enacted. - pub struct ReadySolution { - winners: Vec, - supports: FlatSupportMap, + /// A checked and parsed solution, ready to be enacted. + pub struct ReadySolution { + /// The final supports of the solution. This is target-major vector, storing each winners, total + /// backing, and each individual backer. + supports: FlatSupportMap, + /// How this election was computed. compute: ElectionCompute, } - impl ::core::marker::StructuralPartialEq for ReadySolution {} + impl ::core::marker::StructuralPartialEq for ReadySolution {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for ReadySolution { + impl ::core::cmp::PartialEq for ReadySolution { #[inline] - fn eq(&self, other: &ReadySolution) -> bool { + fn eq(&self, other: &ReadySolution) -> bool { match *other { ReadySolution { - winners: ref __self_1_0, - supports: ref __self_1_1, - compute: ref __self_1_2, + supports: ref __self_1_0, + compute: ref __self_1_1, } => match *self { ReadySolution { - winners: ref __self_0_0, - supports: ref __self_0_1, - compute: ref __self_0_2, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - } + supports: ref __self_0_0, + compute: ref __self_0_1, + } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), }, } } #[inline] - fn ne(&self, other: &ReadySolution) -> bool { + fn ne(&self, other: &ReadySolution) -> bool { match *other { ReadySolution { - winners: ref __self_1_0, - supports: ref __self_1_1, - compute: ref __self_1_2, + supports: ref __self_1_0, + compute: ref __self_1_1, } => match *self { ReadySolution { - winners: ref __self_0_0, - supports: ref __self_0_1, - compute: ref __self_0_2, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) - || (*__self_0_2) != (*__self_1_2) - } + supports: ref __self_0_0, + compute: ref __self_0_1, + } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), }, } } } - impl ::core::marker::StructuralEq for ReadySolution {} + impl ::core::marker::StructuralEq for ReadySolution {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq for ReadySolution { + impl ::core::cmp::Eq for ReadySolution { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; let _: ::core::cmp::AssertParamIsEq; } } } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::clone::Clone for ReadySolution { + impl ::core::clone::Clone for ReadySolution { #[inline] - fn clone(&self) -> ReadySolution { + fn clone(&self) -> ReadySolution { match *self { ReadySolution { - winners: ref __self_0_0, - supports: ref __self_0_1, - compute: ref __self_0_2, + supports: ref __self_0_0, + compute: ref __self_0_1, } => ReadySolution { - winners: ::core::clone::Clone::clone(&(*__self_0_0)), - supports: ::core::clone::Clone::clone(&(*__self_0_1)), - compute: ::core::clone::Clone::clone(&(*__self_0_2)), + supports: ::core::clone::Clone::clone(&(*__self_0_0)), + compute: ::core::clone::Clone::clone(&(*__self_0_1)), }, } } @@ -3762,25 +1140,20 @@ pub mod two_phase { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for ReadySolution + impl _parity_scale_codec::Encode for ReadySolution where - Vec: _parity_scale_codec::Encode, - Vec: _parity_scale_codec::Encode, - FlatSupportMap: _parity_scale_codec::Encode, - FlatSupportMap: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, { fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.winners); dest.push(&self.supports); dest.push(&self.compute); } } - impl _parity_scale_codec::EncodeLike for ReadySolution + impl _parity_scale_codec::EncodeLike for ReadySolution where - Vec: _parity_scale_codec::Encode, - Vec: _parity_scale_codec::Encode, - FlatSupportMap: _parity_scale_codec::Encode, - FlatSupportMap: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, + FlatSupportMap: _parity_scale_codec::Encode, { } }; @@ -3788,26 +1161,15 @@ pub mod two_phase { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for ReadySolution + impl _parity_scale_codec::Decode for ReadySolution where - Vec: _parity_scale_codec::Decode, - Vec: _parity_scale_codec::Decode, - FlatSupportMap: _parity_scale_codec::Decode, - FlatSupportMap: _parity_scale_codec::Decode, + FlatSupportMap: _parity_scale_codec::Decode, + FlatSupportMap: _parity_scale_codec::Decode, { fn decode( input: &mut DecIn, ) -> core::result::Result { Ok(ReadySolution { - winners: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field ReadySolution.winners".into()) - } - Ok(a) => a, - } - }, supports: { let res = _parity_scale_codec::Decode::decode(input); match res { @@ -3830,13 +1192,12 @@ pub mod two_phase { } } }; - impl core::fmt::Debug for ReadySolution + impl core::fmt::Debug for ReadySolution where - AccountId: core::fmt::Debug, + A: core::fmt::Debug, { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { fmt.debug_struct("ReadySolution") - .field("winners", &self.winners) .field("supports", &self.supports) .field("compute", &self.compute) .finish() @@ -3844,33 +1205,243 @@ pub mod two_phase { } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::default::Default for ReadySolution { + impl ::core::default::Default for ReadySolution { #[inline] - fn default() -> ReadySolution { + fn default() -> ReadySolution { ReadySolution { - winners: ::core::default::Default::default(), supports: ::core::default::Default::default(), compute: ::core::default::Default::default(), } } } - pub trait WeightInfo {} - impl WeightInfo for () {} + /// The crate errors. Note that this is different from the [`PalletError`]. + pub enum Error { + /// A feasibility error. + Feasibility(FeasibilityError), + /// An error in the on-chain fallback. + OnChainFallback(crate::onchain::Error), + /// Snapshot data was unavailable unexpectedly. + SnapshotUnAvailable, + } + impl core::fmt::Debug for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::Feasibility(ref a0) => { + fmt.debug_tuple("Error::Feasibility").field(a0).finish() + } + Self::OnChainFallback(ref a0) => { + fmt.debug_tuple("Error::OnChainFallback").field(a0).finish() + } + Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), + _ => Ok(()), + } + } + } + impl ::core::marker::StructuralEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + impl ::core::marker::StructuralPartialEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + ( + &Error::OnChainFallback(ref __self_0), + &Error::OnChainFallback(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + ( + &Error::OnChainFallback(ref __self_0), + &Error::OnChainFallback(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => false, + } + } else { + true + } + } + } + } + impl From for Error { + fn from(e: crate::onchain::Error) -> Self { + Error::OnChainFallback(e) + } + } + /// Errors that can happen in the feasibility check. + pub enum FeasibilityError { + /// Wrong number of winners presented. + WrongWinnerCount, + /// The snapshot is not available. + /// + /// This must be an internal error of the chain. + SnapshotUnavailable, + /// Internal error from the election crate. + NposElectionError(sp_npos_elections::Error), + /// A vote is invalid. + InvalidVote, + /// A voter is invalid. + InvalidVoter, + /// A winner is invalid. + InvalidWinner, + /// The given score was invalid. + InvalidScore, + } + impl core::fmt::Debug for FeasibilityError { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::WrongWinnerCount => fmt + .debug_tuple("FeasibilityError::WrongWinnerCount") + .finish(), + Self::SnapshotUnavailable => fmt + .debug_tuple("FeasibilityError::SnapshotUnavailable") + .finish(), + Self::NposElectionError(ref a0) => fmt + .debug_tuple("FeasibilityError::NposElectionError") + .field(a0) + .finish(), + Self::InvalidVote => fmt.debug_tuple("FeasibilityError::InvalidVote").finish(), + Self::InvalidVoter => fmt.debug_tuple("FeasibilityError::InvalidVoter").finish(), + Self::InvalidWinner => fmt.debug_tuple("FeasibilityError::InvalidWinner").finish(), + Self::InvalidScore => fmt.debug_tuple("FeasibilityError::InvalidScore").finish(), + _ => Ok(()), + } + } + } + impl ::core::marker::StructuralEq for FeasibilityError {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for FeasibilityError { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } + impl ::core::marker::StructuralPartialEq for FeasibilityError {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for FeasibilityError { + #[inline] + fn eq(&self, other: &FeasibilityError) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &FeasibilityError::NposElectionError(ref __self_0), + &FeasibilityError::NposElectionError(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &FeasibilityError) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &FeasibilityError::NposElectionError(ref __self_0), + &FeasibilityError::NposElectionError(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => false, + } + } else { + true + } + } + } + } + impl From for FeasibilityError { + fn from(e: sp_npos_elections::Error) -> Self { + FeasibilityError::NposElectionError(e) + } + } + /// The weights for this pallet. + pub trait WeightInfo { + fn feasibility_check() -> Weight; + fn submit() -> Weight; + fn submit_unsigned() -> Weight; + } + impl WeightInfo for () { + fn feasibility_check() -> Weight { + Default::default() + } + fn submit() -> Weight { + Default::default() + } + fn submit_unsigned() -> Weight { + Default::default() + } + } pub trait Trait: frame_system::Trait { + /// Event type. type Event: From> + Into<::Event>; + /// Currency type. type Currency: ReservableCurrency + Currency; + /// Duration of the signed phase. type SignedPhase: Get; + /// Duration of the unsigned phase. type UnsignedPhase: Get; + /// Maximum number of singed submissions that can be queued. type MaxSignedSubmissions: Get; type SignedRewardBase: Get>; type SignedRewardFactor: Get; type SignedDepositBase: Get>; type SignedDepositByte: Get>; type SignedDepositWeight: Get>; + /// The minimum amount of improvement to the solution score that defines a solution as "better". type SolutionImprovementThreshold: Get; + /// Handler for the slashed deposits. type SlashHandler: OnUnbalanced>; + /// Handler for the rewards. type RewardHandler: OnUnbalanced>; + /// Something that will provide the election data. type ElectionDataProvider: ElectionDataProvider; + /// The weight of the pallet. type WeightInfo: WeightInfo; } use self::sp_api_hidden_includes_decl_storage::hidden_include::{ @@ -3889,7 +1460,10 @@ pub mod two_phase { type SnapshotVoters; type DesiredTargets; } - impl Store for Module { + impl Store for Module + where + ExtendedBalance: From>>, + { type CurrentPhase = CurrentPhase; type SignedSubmissions = SignedSubmissions; type QueuedSolution = QueuedSolution; @@ -3897,32 +1471,38 @@ pub mod two_phase { type SnapshotVoters = SnapshotVoters; type DesiredTargets = DesiredTargets; } - impl Module { + impl Module + where + ExtendedBalance: From>>, + { /// Current phase. pub fn current_phase() -> Phase { < CurrentPhase < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase > > :: get ( ) } - /// Sorted list of unchecked, signed solutions. - pub fn signed_submissions() -> Vec>> { - < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > > > > > :: get ( ) + /// Sorted (worse -> best) list of unchecked, signed solutions. + pub fn signed_submissions( + ) -> Vec, CompactOf>> { + < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > > > :: get ( ) } - /// Current, best, unsigned solution. + /// Current best solution, signed or unsigned. pub fn queued_solution() -> Option> { < QueuedSolution < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < ReadySolution < T :: AccountId > > > :: get ( ) } - /// Snapshot of all Voters. The indices if this will be used in election. + /// Snapshot of all Voters. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub fn snapshot_targets() -> Option> { < SnapshotTargets < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < T :: AccountId > > > :: get ( ) } - /// Snapshot of all targets. The indices if this will be used in election. + /// Snapshot of all targets. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub fn snapshot_voters() -> Option)>> { < SnapshotVoters < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < ( T :: AccountId , VoteWeight , Vec < T :: AccountId > ) > > > :: get ( ) } - /// Desired number of targets to elect + /// Desired number of targets to elect. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub fn desired_targets() -> u32 { < DesiredTargets < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) } @@ -3942,6 +1522,8 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructCurrentPhase + where + ExtendedBalance: From>>, { fn default_byte( &self, @@ -3955,8 +1537,14 @@ pub mod two_phase { .clone() } } - unsafe impl Send for __GetByteStructCurrentPhase {} - unsafe impl Sync for __GetByteStructCurrentPhase {} + unsafe impl Send for __GetByteStructCurrentPhase where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructCurrentPhase where + ExtendedBalance: From>> + { + } #[doc(hidden)] pub struct __GetByteStructSignedSubmissions( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< @@ -3972,22 +1560,24 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructSignedSubmissions + where + ExtendedBalance: From>>, { fn default_byte( &self, ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SignedSubmissions - .get_or_init(|| { - let def_val: Vec>> = - Default::default(); - >> as Encode>::encode(&def_val) - }) - .clone() + __CACHE_GET_BYTE_STRUCT_SignedSubmissions . get_or_init ( | | { let def_val : Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > = Default :: default ( ) ; < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > as Encode > :: encode ( & def_val ) } ) . clone ( ) } } - unsafe impl Send for __GetByteStructSignedSubmissions {} - unsafe impl Sync for __GetByteStructSignedSubmissions {} + unsafe impl Send for __GetByteStructSignedSubmissions where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructSignedSubmissions where + ExtendedBalance: From>> + { + } #[doc(hidden)] pub struct __GetByteStructQueuedSolution( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< @@ -4003,6 +1593,8 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructQueuedSolution + where + ExtendedBalance: From>>, { fn default_byte( &self, @@ -4016,8 +1608,14 @@ pub mod two_phase { .clone() } } - unsafe impl Send for __GetByteStructQueuedSolution {} - unsafe impl Sync for __GetByteStructQueuedSolution {} + unsafe impl Send for __GetByteStructQueuedSolution where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructQueuedSolution where + ExtendedBalance: From>> + { + } #[doc(hidden)] pub struct __GetByteStructSnapshotTargets( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< @@ -4033,6 +1631,8 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructSnapshotTargets + where + ExtendedBalance: From>>, { fn default_byte( &self, @@ -4046,8 +1646,14 @@ pub mod two_phase { .clone() } } - unsafe impl Send for __GetByteStructSnapshotTargets {} - unsafe impl Sync for __GetByteStructSnapshotTargets {} + unsafe impl Send for __GetByteStructSnapshotTargets where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructSnapshotTargets where + ExtendedBalance: From>> + { + } #[doc(hidden)] pub struct __GetByteStructSnapshotVoters( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< @@ -4063,6 +1669,8 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructSnapshotVoters + where + ExtendedBalance: From>>, { fn default_byte( &self, @@ -4079,8 +1687,14 @@ pub mod two_phase { .clone() } } - unsafe impl Send for __GetByteStructSnapshotVoters {} - unsafe impl Sync for __GetByteStructSnapshotVoters {} + unsafe impl Send for __GetByteStructSnapshotVoters where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructSnapshotVoters where + ExtendedBalance: From>> + { + } #[doc(hidden)] pub struct __GetByteStructDesiredTargets( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< @@ -4096,6 +1710,8 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructDesiredTargets + where + ExtendedBalance: From>>, { fn default_byte( &self, @@ -4109,13 +1725,22 @@ pub mod two_phase { .clone() } } - unsafe impl Send for __GetByteStructDesiredTargets {} - unsafe impl Sync for __GetByteStructDesiredTargets {} - impl Module { + unsafe impl Send for __GetByteStructDesiredTargets where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructDesiredTargets where + ExtendedBalance: From>> + { + } + impl Module + where + ExtendedBalance: From>>, + { #[doc(hidden)] pub fn storage_metadata( ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::StorageMetadata { - self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current, best, unsigned solution." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters. The indices if this will be used in election." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets. The indices if this will be used in election." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect" ] ) , } ] [ .. ] ) , } + self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec, CompactOf>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted (worse -> best) list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current best solution, signed or unsigned." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } ] [ .. ] ) , } } } /// Hidden instance generated to be internally used when module is used without @@ -4209,18 +1834,22 @@ pub mod two_phase { Some(v) } } - /// Sorted list of unchecked, signed solutions. + /// Sorted (worse -> best) list of unchecked, signed solutions. pub struct SignedSubmissions( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T,), >, - ); + ) + where + ExtendedBalance: From>>; impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec>>, + Vec, CompactOf>>, > for SignedSubmissions + where + ExtendedBalance: From>>, { - type Query = Vec>>; + type Query = Vec, CompactOf>>; fn module_prefix() -> &'static [u8] { < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) } @@ -4228,26 +1857,30 @@ pub mod two_phase { b"SignedSubmissions" } fn from_optional_value_to_query( - v: Option>>>, + v: Option, CompactOf>>>, ) -> Self::Query { v.unwrap_or_else(|| Default::default()) } fn from_query_to_optional_value( v: Self::Query, - ) -> Option>>> { + ) -> Option, CompactOf>>> { Some(v) } } - /// Current, best, unsigned solution. + /// Current best solution, signed or unsigned. pub struct QueuedSolution( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T,), >, - ); + ) + where + ExtendedBalance: From>>; impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< ReadySolution, > for QueuedSolution + where + ExtendedBalance: From>>, { type Query = Option>; fn module_prefix() -> &'static [u8] { @@ -4263,18 +1896,22 @@ pub mod two_phase { v } } - /// Snapshot of all Voters. The indices if this will be used in election. + /// Snapshot of all Voters. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub struct SnapshotTargets( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T,), >, - ); + ) + where + ExtendedBalance: From>>; impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< Vec, > for SnapshotTargets + where + ExtendedBalance: From>>, { type Query = Option>; fn module_prefix() -> &'static [u8] { @@ -4290,18 +1927,22 @@ pub mod two_phase { v } } - /// Snapshot of all targets. The indices if this will be used in election. + /// Snapshot of all targets. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub struct SnapshotVoters( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T,), >, - ); + ) + where + ExtendedBalance: From>>; impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< Vec<(T::AccountId, VoteWeight, Vec)>, > for SnapshotVoters + where + ExtendedBalance: From>>, { type Query = Option)>>; fn module_prefix() -> &'static [u8] { @@ -4321,7 +1962,9 @@ pub mod two_phase { v } } - /// Desired number of targets to elect + /// Desired number of targets to elect. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub struct DesiredTargets( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, ); @@ -4352,10 +1995,17 @@ pub mod two_phase { /// Events for this module. /// pub enum RawEvent { - /// A solution was sot + /// A solution was stored with the given compute. + /// + /// If the solution is signed, this means that it hasn't yet been processed. If the solution + /// is unsigned, this means that it has also been processed. SolutionStored(ElectionCompute), + /// The election has been finalized, with `Some` of the given computation, or else if the + /// election failed, `None`. ElectionFinalized(Option), + /// An account has been rewarded for their signed submission being finalized. Rewarded(AccountId), + /// An account has been slashed for submitting an invalid signed submission. Slashed(AccountId), } #[automatically_derived] @@ -4593,7 +2243,10 @@ pub mod two_phase { "ElectionCompute", ]), documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" A solution was sot", + r" A solution was stored with the given compute.", + r"", + r" If the solution is signed, this means that it hasn't yet been processed. If the solution", + r" is unsigned, this means that it has also been processed.", ]), }, ::frame_support::event::EventMetadata { @@ -4601,122 +2254,37 @@ pub mod two_phase { arguments: ::frame_support::event::DecodeDifferent::Encode(&[ "Option", ]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" The election has been finalized, with `Some` of the given computation, or else if the", + r" election failed, `None`.", + ]), }, ::frame_support::event::EventMetadata { name: ::frame_support::event::DecodeDifferent::Encode("Rewarded"), arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" An account has been rewarded for their signed submission being finalized.", + ]), }, ::frame_support::event::EventMetadata { name: ::frame_support::event::DecodeDifferent::Encode("Slashed"), arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[]), - }, - ] - } - } - pub enum PalletError { - #[doc(hidden)] - __Ignore( - ::frame_support::sp_std::marker::PhantomData<(T,)>, - ::frame_support::Never, - ), - EarlySubmission, - QueueFull, - SubmissionQueuedFull, - CannotPayDeposit, - } - impl ::frame_support::sp_std::fmt::Debug for PalletError { - fn fmt( - &self, - f: &mut ::frame_support::sp_std::fmt::Formatter<'_>, - ) -> ::frame_support::sp_std::fmt::Result { - f.write_str(self.as_str()) - } - } - impl PalletError { - fn as_u8(&self) -> u8 { - match self { - PalletError::__Ignore(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"`__Ignore` can never be constructed",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - PalletError::EarlySubmission => 0, - PalletError::QueueFull => 0 + 1, - PalletError::SubmissionQueuedFull => 0 + 1 + 1, - PalletError::CannotPayDeposit => 0 + 1 + 1 + 1, - } - } - fn as_str(&self) -> &'static str { - match self { - Self::__Ignore(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"`__Ignore` can never be constructed",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - PalletError::EarlySubmission => "EarlySubmission", - PalletError::QueueFull => "QueueFull", - PalletError::SubmissionQueuedFull => "SubmissionQueuedFull", - PalletError::CannotPayDeposit => "CannotPayDeposit", - } - } - } - impl From> for &'static str { - fn from(err: PalletError) -> &'static str { - err.as_str() - } - } - impl From> for ::frame_support::sp_runtime::DispatchError { - fn from(err: PalletError) -> Self { - let index = ::index::>() - .expect("Every active module has an index in the runtime; qed") as u8; - ::frame_support::sp_runtime::DispatchError::Module { - index, - error: err.as_u8(), - message: Some(err.as_str()), - } - } - } - impl ::frame_support::error::ModuleErrorMetadata for PalletError { - fn metadata() -> &'static [::frame_support::error::ErrorMetadata] { - &[ - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("EarlySubmission"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), - }, - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("QueueFull"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), - }, - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("SubmissionQueuedFull"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), - }, - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("CannotPayDeposit"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" An account has been slashed for submitting an invalid signed submission.", + ]), }, ] } } - pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>); + pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>) + where + ExtendedBalance: From>>; #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::clone::Clone for Module { + impl ::core::clone::Clone for Module + where + ExtendedBalance: From>>, + { #[inline] fn clone(&self) -> Module { match *self { @@ -4726,11 +2294,20 @@ pub mod two_phase { } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::marker::Copy for Module {} - impl ::core::marker::StructuralPartialEq for Module {} + impl ::core::marker::Copy for Module where + ExtendedBalance: From>> + { + } + impl ::core::marker::StructuralPartialEq for Module where + ExtendedBalance: From>> + { + } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Module { + impl ::core::cmp::PartialEq for Module + where + ExtendedBalance: From>>, + { #[inline] fn eq(&self, other: &Module) -> bool { match *other { @@ -4748,10 +2325,16 @@ pub mod two_phase { } } } - impl ::core::marker::StructuralEq for Module {} + impl ::core::marker::StructuralEq for Module where + ExtendedBalance: From>> + { + } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Module { + impl ::core::cmp::Eq for Module + where + ExtendedBalance: From>>, + { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { @@ -4764,6 +2347,7 @@ pub mod two_phase { } impl core::fmt::Debug for Module where + ExtendedBalance: From>>, T: core::fmt::Debug, { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { @@ -4772,6 +2356,8 @@ pub mod two_phase { } impl ::frame_support::traits::OnInitialize<::BlockNumber> for Module + where + ExtendedBalance: From>>, { fn on_initialize(now: T::BlockNumber) -> Weight { let __within_span__ = { @@ -4787,7 +2373,7 @@ pub mod two_phase { "frame_election_providers::two_phase", ::tracing::Level::TRACE, Some("frame/election-providers/src/two_phase/mod.rs"), - Some(250u32), + Some(407u32), Some("frame_election_providers::two_phase"), ::tracing_core::field::FieldSet::new( &[], @@ -4832,31 +2418,59 @@ pub mod two_phase { } } } - impl ::frame_support::traits::OnRuntimeUpgrade for Module {} + impl ::frame_support::traits::OnRuntimeUpgrade for Module where + ExtendedBalance: From>> + { + } impl ::frame_support::traits::OnFinalize<::BlockNumber> for Module + where + ExtendedBalance: From>>, { } impl ::frame_support::traits::OffchainWorker<::BlockNumber> for Module + where + ExtendedBalance: From>>, { fn offchain_worker(n: T::BlockNumber) {} } - impl Module { + impl Module + where + ExtendedBalance: From>>, + { /// Deposits an event using `frame_system::Module::deposit_event`. fn deposit_event(event: impl Into<::Event>) { >::deposit_event(event.into()) } } #[cfg(feature = "std")] - impl ::frame_support::traits::IntegrityTest for Module {} + impl ::frame_support::traits::IntegrityTest for Module where + ExtendedBalance: From>> + { + } /// Can also be called using [`Call`]. /// /// [`Call`]: enum.Call.html - impl Module { + impl Module + where + ExtendedBalance: From>>, + { + /// Submit a solution for the signed phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// The solution potentially queued, based on the claimed score and processed at the end of + /// the signed phase. + /// + /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution + /// might be rewarded, slashed, or get all or a part of the deposit back. /// /// NOTE: Calling this function will bypass origin filters. - fn submit(origin: T::Origin, solution: RawSolution) -> DispatchResultWithPostInfo { + fn submit( + origin: T::Origin, + solution: RawSolution>, + ) -> DispatchResultWithPostInfo { let __within_span__ = { if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() @@ -4870,7 +2484,7 @@ pub mod two_phase { "frame_election_providers::two_phase", ::tracing::Level::TRACE, Some("frame/election-providers/src/two_phase/mod.rs"), - Some(250u32), + Some(407u32), Some("frame_election_providers::two_phase"), ::tracing_core::field::FieldSet::new( &[], @@ -4898,15 +2512,7 @@ pub mod two_phase { { if !Self::current_phase().is_signed() { { - return Err(PalletError::::EarlySubmission.into()); - }; - } - }; - let queue_size = >::decode_len().unwrap_or_default() as u32; - { - if !(queue_size <= T::MaxSignedSubmissions::get()) { - { - return Err(PalletError::::SubmissionQueuedFull.into()); + return Err("EarlySubmission".into()); }; } }; @@ -4915,19 +2521,17 @@ pub mod two_phase { { if !maybe_index.is_some() { { - return Err(PalletError::::QueueFull.into()); + return Err("QueueFull".into()); }; } }; let index = maybe_index.expect("Option checked to be `Some`; qed."); let deposit = signed_submissions[index].deposit; - T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; + T::Currency::reserve(&who, deposit).map_err(|_| "CannotPayDeposit")?; if true { - if !(signed_submissions.len() as u32 == queue_size + 1 - || signed_submissions.len() as u32 == T::MaxSignedSubmissions::get()) - { + if !(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()) { { - :: std :: rt :: begin_panic ( "assertion failed: signed_submissions.len() as u32 == queue_size + 1 ||\n signed_submissions.len() as u32 == T::MaxSignedSubmissions::get()" ) + :: std :: rt :: begin_panic ( "assertion failed: signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()" ) } }; }; @@ -4936,11 +2540,25 @@ pub mod two_phase { Ok(None.into()) } #[allow(unreachable_code)] + /// Submit a solution for the unsigned phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. + /// Moreover, this unsigned solution is only validated when submitted to the pool from the + /// local process. Effectively, this means that only active validators can submit this + /// transaction when authoring a block. + /// + /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will + /// panic if the solution submitted by the validator is invalid, effectively putting their + /// authoring reward at risk. + /// + /// No deposit or reward is associated with this. /// /// NOTE: Calling this function will bypass origin filters. fn submit_unsigned( origin: T::Origin, - solution: RawSolution, + solution: RawSolution>, ) -> ::frame_support::dispatch::DispatchResult { let __within_span__ = { if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL @@ -4955,7 +2573,7 @@ pub mod two_phase { "frame_election_providers::two_phase", ::tracing::Level::TRACE, Some("frame/election-providers/src/two_phase/mod.rs"), - Some(250u32), + Some(407u32), Some("frame_election_providers::two_phase"), ::tracing_core::field::FieldSet::new( &[], @@ -4981,6 +2599,25 @@ pub mod two_phase { let __tracing_guard__ = __within_span__.enter(); { ensure_none(origin)?; + { + if !Self::current_phase().is_signed() { + { + return Err("EarlySubmission".into()); + }; + } + }; + use sp_npos_elections::is_score_better; + if !Self::queued_solution().map_or(true, |q| { + is_score_better( + solution.score, + q.score, + T::SolutionImprovementThreshold::get(), + ) + }) { + { + ::std::rt::begin_panic("WeakSolution") + } + }; Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); { ::std::rt::begin_panic("not implemented") @@ -4992,7 +2629,10 @@ pub mod two_phase { /// Dispatchable calls. /// /// Each variant of this enum maps to a dispatchable function from the associated module. - pub enum Call { + pub enum Call + where + ExtendedBalance: From>>, + { #[doc(hidden)] #[codec(skip)] __PhantomItem( @@ -5000,15 +2640,45 @@ pub mod two_phase { ::frame_support::Never, ), #[allow(non_camel_case_types)] - submit(RawSolution), + /// Submit a solution for the signed phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// The solution potentially queued, based on the claimed score and processed at the end of + /// the signed phase. + /// + /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution + /// might be rewarded, slashed, or get all or a part of the deposit back. + submit(RawSolution>), #[allow(non_camel_case_types)] - submit_unsigned(RawSolution), + /// Submit a solution for the unsigned phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. + /// Moreover, this unsigned solution is only validated when submitted to the pool from the + /// local process. Effectively, this means that only active validators can submit this + /// transaction when authoring a block. + /// + /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will + /// panic if the solution submitted by the validator is invalid, effectively putting their + /// authoring reward at risk. + /// + /// No deposit or reward is associated with this. + submit_unsigned(RawSolution>), } const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Call { + impl _parity_scale_codec::Encode for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + { fn encode_to(&self, dest: &mut EncOut) { match *self { Call::submit(ref aa) => { @@ -5023,13 +2693,28 @@ pub mod two_phase { } } } - impl _parity_scale_codec::EncodeLike for Call {} + impl _parity_scale_codec::EncodeLike for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + { + } }; const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Call { + impl _parity_scale_codec::Decode for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + { fn decode( input: &mut DecIn, ) -> core::result::Result { @@ -5055,22 +2740,23 @@ pub mod two_phase { } } }; - impl ::frame_support::dispatch::GetDispatchInfo for Call { + impl ::frame_support::dispatch::GetDispatchInfo for Call + where + ExtendedBalance: From>>, + { fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { match *self { Call::submit(ref solution) => { - let base_weight = 0; - let weight = - >::weigh_data( - &base_weight, - (solution,), - ); - let class = < dyn :: frame_support :: dispatch :: ClassifyDispatch < ( & RawSolution , ) > > :: classify_dispatch ( & base_weight , ( solution , ) ) ; - let pays_fee = - >::pays_fee( - &base_weight, - (solution,), - ); + let base_weight = T::WeightInfo::submit(); + let weight = >, + )>>::weigh_data(&base_weight, (solution,)); + let class = >, + )>>::classify_dispatch(&base_weight, (solution,)); + let pays_fee = >, + )>>::pays_fee(&base_weight, (solution,)); ::frame_support::dispatch::DispatchInfo { weight, class, @@ -5078,18 +2764,16 @@ pub mod two_phase { } } Call::submit_unsigned(ref solution) => { - let base_weight = 0; - let weight = - >::weigh_data( - &base_weight, - (solution,), - ); - let class = < dyn :: frame_support :: dispatch :: ClassifyDispatch < ( & RawSolution , ) > > :: classify_dispatch ( & base_weight , ( solution , ) ) ; - let pays_fee = - >::pays_fee( - &base_weight, - (solution,), - ); + let base_weight = T::WeightInfo::submit_unsigned(); + let weight = >, + )>>::weigh_data(&base_weight, (solution,)); + let class = >, + )>>::classify_dispatch(&base_weight, (solution,)); + let pays_fee = >, + )>>::pays_fee(&base_weight, (solution,)); ::frame_support::dispatch::DispatchInfo { weight, class, @@ -5110,7 +2794,10 @@ pub mod two_phase { } } } - impl ::frame_support::dispatch::GetCallName for Call { + impl ::frame_support::dispatch::GetCallName for Call + where + ExtendedBalance: From>>, + { fn get_call_name(&self) -> &'static str { match *self { Call::submit(ref solution) => { @@ -5138,7 +2825,10 @@ pub mod two_phase { &["submit", "submit_unsigned"] } } - impl ::frame_support::dispatch::Clone for Call { + impl ::frame_support::dispatch::Clone for Call + where + ExtendedBalance: From>>, + { fn clone(&self) -> Self { match *self { Call::submit(ref solution) => Call::submit((*solution).clone()), @@ -5147,7 +2837,10 @@ pub mod two_phase { } } } - impl ::frame_support::dispatch::PartialEq for Call { + impl ::frame_support::dispatch::PartialEq for Call + where + ExtendedBalance: From>>, + { fn eq(&self, _other: &Self) -> bool { match *self { Call::submit(ref solution) => { @@ -5180,8 +2873,14 @@ pub mod two_phase { } } } - impl ::frame_support::dispatch::Eq for Call {} - impl ::frame_support::dispatch::fmt::Debug for Call { + impl ::frame_support::dispatch::Eq for Call where + ExtendedBalance: From>> + { + } + impl ::frame_support::dispatch::fmt::Debug for Call + where + ExtendedBalance: From>>, + { fn fmt( &self, _f: &mut ::frame_support::dispatch::fmt::Formatter, @@ -5211,7 +2910,10 @@ pub mod two_phase { } } } - impl ::frame_support::traits::UnfilteredDispatchable for Call { + impl ::frame_support::traits::UnfilteredDispatchable for Call + where + ExtendedBalance: From>>, + { type Origin = T::Origin; fn dispatch_bypass_filter( self, @@ -5238,10 +2940,16 @@ pub mod two_phase { } } } - impl ::frame_support::dispatch::Callable for Module { + impl ::frame_support::dispatch::Callable for Module + where + ExtendedBalance: From>>, + { type Call = Call; } - impl Module { + impl Module + where + ExtendedBalance: From>>, + { #[doc(hidden)] #[allow(dead_code)] pub fn call_functions() -> &'static [::frame_support::dispatch::FunctionMetadata] { @@ -5251,25 +2959,57 @@ pub mod two_phase { arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ ::frame_support::dispatch::FunctionArgumentMetadata { name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), - ty: ::frame_support::dispatch::DecodeDifferent::Encode("RawSolution"), + ty: ::frame_support::dispatch::DecodeDifferent::Encode( + "RawSolution>", + ), }, ]), - documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[]), + documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + r" Submit a solution for the signed phase.", + r"", + r" The dispatch origin fo this call must be __signed__.", + r"", + r" The solution potentially queued, based on the claimed score and processed at the end of", + r" the signed phase.", + r"", + r" A deposit is reserved and recorded for the solution. Based on the outcome, the solution", + r" might be rewarded, slashed, or get all or a part of the deposit back.", + ]), }, ::frame_support::dispatch::FunctionMetadata { name: ::frame_support::dispatch::DecodeDifferent::Encode("submit_unsigned"), arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ ::frame_support::dispatch::FunctionArgumentMetadata { name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), - ty: ::frame_support::dispatch::DecodeDifferent::Encode("RawSolution"), + ty: ::frame_support::dispatch::DecodeDifferent::Encode( + "RawSolution>", + ), }, ]), - documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[]), + documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + r" Submit a solution for the unsigned phase.", + r"", + r" The dispatch origin fo this call must be __signed__.", + r"", + r" This submission is checked on the fly, thus it is likely yo be more limited and smaller.", + r" Moreover, this unsigned solution is only validated when submitted to the pool from the", + r" local process. Effectively, this means that only active validators can submit this", + r" transaction when authoring a block.", + r"", + r" To prevent any incorrect solution (and thus wasted time/weight), this transaction will", + r" panic if the solution submitted by the validator is invalid, effectively putting their", + r" authoring reward at risk.", + r"", + r" No deposit or reward is associated with this.", + ]), }, ] } } - impl Module { + impl Module + where + ExtendedBalance: From>>, + { #[doc(hidden)] #[allow(dead_code)] pub fn module_constants_metadata( @@ -5277,52 +3017,33 @@ pub mod two_phase { &[] } } - impl ::frame_support::dispatch::ModuleErrorMetadata for Module { + impl ::frame_support::dispatch::ModuleErrorMetadata for Module + where + ExtendedBalance: From>>, + { fn metadata() -> &'static [::frame_support::dispatch::ErrorMetadata] { <&'static str as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() } } - pub enum FeasibilityError { - /// Wrong number of winners presented. - WrongWinnerCount, - /// The snapshot is not available. - /// - /// This must be an internal error of the chain. - SnapshotUnavailable, - /// Internal error from the election crate. - NposElectionError(sp_npos_elections::Error), - /// A vote is invalid. - InvalidVote, - /// A voter is invalid. - InvalidVoter, - /// A winner is invalid. - InvalidWinner, - /// The given score was invalid. - InvalidScore, - } - impl From for FeasibilityError { - fn from(e: sp_npos_elections::Error) -> Self { - FeasibilityError::NposElectionError(e) - } - } - impl Module { + impl Module + where + ExtendedBalance: From>>, + { /// Checks the feasibility of a solution. + /// + /// This checks the solution for the following: + /// + /// 0. **all** of the used indices must be correct. + /// 1. present correct number of winners. + /// 2. any assignment is checked to match with `SnapshotVoters`. + /// 3. for each assignment, the check of `ElectionDataProvider` is also examined. + /// 4. the claimed score is valid. fn feasibility_check( - solution: RawSolution, + solution: RawSolution>, compute: ElectionCompute, ) -> Result, FeasibilityError> { - let RawSolution { - winners, - compact, - score, - } = solution; - { - if !(compact.unique_targets().len() == winners.len()) { - { - return Err(FeasibilityError::WrongWinnerCount.into()); - }; - } - }; + let RawSolution { compact, score } = solution; + let winners = compact.unique_targets(); { if !(winners.len() as u32 == Self::desired_targets()) { { @@ -5334,11 +3055,15 @@ pub mod two_phase { Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; let snapshot_targets = Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - let voter_at = |i: VoterIndex| -> Option { - snapshot_voters.get(i as usize).map(|(x, _, _)| x).cloned() + use sp_runtime::traits::UniqueSaturatedInto; + let voter_at = |i: CompactVoterIndexOf| -> Option { + snapshot_voters + .get(i.unique_saturated_into()) + .map(|(x, _, _)| x) + .cloned() }; - let target_at = |i: TargetIndex| -> Option { - snapshot_targets.get(i as usize).cloned() + let target_at = |i: CompactTargetIndexOf| -> Option { + snapshot_targets.get(i.unique_saturated_into()).cloned() }; let winners = winners .into_iter() @@ -5355,7 +3080,7 @@ pub mod two_phase { |(_, _, t)| { if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) && T::ElectionDataProvider::feasibility_check_assignment::< - OffchainAccuracy, + CompactAccuracyOf, >(who, distribution) { Ok(()) @@ -5373,12 +3098,13 @@ pub mod two_phase { .map(|(_, x, _)| *x) .unwrap_or_default() }; - use sp_npos_elections::{assignment_ratio_to_staked_normalized, build_support_map}; let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) .map_err::(Into::into)?; let supports = build_support_map(&winners, &staked_assignments) + .map(FlattenSupportMap::flatten) .map_err::(Into::into)?; - let known_score = evaluate_support(&supports); + let known_score = + evaluate_support::(supports.iter().map(|&(ref x, ref y)| (x, y))); { if !(known_score == score) { { @@ -5386,37 +3112,42 @@ pub mod two_phase { }; } }; - let supports = supports.flatten(); - Ok(ReadySolution { - winners, - supports, - compute, - }) - } - fn onchain_fallback() -> Result, crate::Error> { + Ok(ReadySolution { supports, compute }) + } + /// On-chain fallback of election. + fn onchain_fallback() -> Result, Error> { let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(crate::Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(crate::Error::SnapshotUnAvailable)?; - >::elect::( + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + >::elect::( desired_targets, targets, voters, ) + .map_err(Into::into) } } - impl crate::ElectionProvider for Module { - fn elect( + impl crate::ElectionProvider for Module + where + ExtendedBalance: From>>, + { + type Error = Error; + const NEEDS_ELECT_DATA: bool = false; + fn elect( _to_elect: usize, _targets: Vec, _voters: Vec<(T::AccountId, VoteWeight, Vec)>, - ) -> Result, crate::Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, - P: sp_std::ops::Mul, { Self::queued_solution() .map_or_else( - || Self::onchain_fallback().map(|r| (r, ElectionCompute::OnChain)), + || { + Self::onchain_fallback() + .map(|r| (r, ElectionCompute::OnChain)) + .map_err(Into::into) + }, |ReadySolution { supports, compute, .. }| Ok((supports, compute)), @@ -5444,124 +3175,98 @@ pub mod two_phase { use sp_arithmetic::PerThing; #[doc(hidden)] pub use sp_npos_elections::VoteWeight; -use sp_npos_elections::{ExtendedBalance, FlatSupportMap}; -use sp_runtime::RuntimeDebug; +use sp_npos_elections::{CompactSolution, ExtendedBalance, PerThing128, Support, SupportMap}; #[doc(hidden)] pub use sp_std::convert::TryInto; -/// A bridge between the entity requesting a long-lasting election from something that implements -/// [`ElectionProvider`], such as the [`two_phase`] module. +/// A flat variant of [`sp_npos_elections::SupportMap`]. +/// +/// The main advantage of this is that it is encodable. +pub type FlatSupportMap = Vec<(A, Support)>; +/// Helper trait to convert from a support map to a flat support vector. +pub trait FlattenSupportMap { + fn flatten(self) -> FlatSupportMap; +} +impl FlattenSupportMap for SupportMap { + fn flatten(self) -> FlatSupportMap { + self.into_iter().map(|(k, v)| (k, v)).collect::>() + } +} +/// Something that can provide the data to something else that implements [`ElectionProvider`], such +/// as the [`two_phase`] module. +/// +/// The underlying purpose of this is to provide auxillary data to long-lasting election providers. +/// For example, the [`two_phase`] election provider needs to know the voters/targets list well in +/// advance and before a call to [`ElectionProvider::elect`]. +/// +/// For example, if pallet A wants to use the two-phase election: +/// +/// ```rust,ignore +/// pub trait TraitA { +/// type ElectionProvider: ElectionProvider<_, _>; +/// } +/// +/// // these function will be called by `Self::ElectionProvider` whenever needed. +/// impl ElectionDataProvider for PalletA { /* .. */ } +/// +/// impl Module { +/// fn do_election() { +/// // finalize the election. +/// T::ElectionProvider::elect( /* .. */ ); +/// } +/// } +/// ``` pub trait ElectionDataProvider { + /// The compact solution type. + /// + /// This should encode the entire solution with the least possible space usage. + type CompactSolution: codec::Codec + Default + PartialEq + Eq + Clone + Debug + CompactSolution; + /// All possible targets for the election, i.e. the candidates. fn targets() -> Vec; + /// All possible voters for the election. + /// + /// Note that if a notion of self-vote exists, it should be represented here. fn voters() -> Vec<(AccountId, VoteWeight, Vec)>; + /// The number of targets to elect. fn desired_targets() -> u32; + /// Check the feasibility of a single assignment for the underlying `ElectionProvider`. In other + /// words, check if `who` having a weight distribution described as `distribution` is correct or + /// not. + /// + /// This might be called by the [`ElectionProvider`] upon processing solutions. fn feasibility_check_assignment( who: &AccountId, distribution: &[(AccountId, P)], ) -> bool; + /// Provide a best effort prediction about when the next election is about to happen. + /// + /// In essence, `Self` should predict with this function when it will trigger the + /// `ElectionDataProvider::elect`. fn next_election_prediction(now: B) -> B; } -#[cfg(feature = "std")] -impl ElectionDataProvider for () { - fn targets() -> Vec { - Default::default() - } - fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { - Default::default() - } - fn desired_targets() -> u32 { - Default::default() - } - fn feasibility_check_assignment(_: &AccountId, _: &[(AccountId, P)]) -> bool { - Default::default() - } - fn next_election_prediction(_: B) -> B { - Default::default() - } -} -/// Something that can compute the result of an election and pass it back to a pallet. +/// Something that can compute the result of an election and pass it back to the caller. pub trait ElectionProvider { + /// Indicate weather this election provider needs data when calling [`elect`] or not. + const NEEDS_ELECT_DATA: bool; + /// The error type that is returned by the provider. + type Error; /// Elect a new set of winners. /// /// The result is returned in a target major format, namely as a support map. - fn elect( + /// + /// Note that based on the logic of the type that will implement this trait, the input data may + /// or may not be used. To hint about this to the call site, [`NEEDS_ELECT_DATA`] should be + /// properly set. + /// + /// The implementation should, if possible, use the accuracy `P` to compute the election result. + fn elect( to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Error> + ) -> Result, Self::Error> where - ExtendedBalance: From<

::Inner>, - P: sp_std::ops::Mul; - /// Returns true if an election is still ongoing. + ExtendedBalance: From<

::Inner>; + /// Returns true if an election is still ongoing. This can be used by the call site to + /// dynamically check of a long-lasting election (such as [`two_phase`]) is still on-going or + /// not. fn ongoing() -> bool; } -pub enum Error { - ElectionFailed, - SnapshotUnAvailable, - Internal(sp_npos_elections::Error), -} -impl core::fmt::Debug for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::ElectionFailed => fmt.debug_tuple("Error::ElectionFailed").finish(), - Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), - Self::Internal(ref a0) => fmt.debug_tuple("Error::Internal").field(a0).finish(), - _ => Ok(()), - } - } -} -impl ::core::marker::StructuralEq for Error {} -#[automatically_derived] -#[allow(unused_qualifications)] -impl ::core::cmp::Eq for Error { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - } - } -} -impl ::core::marker::StructuralPartialEq for Error {} -#[automatically_derived] -#[allow(unused_qualifications)] -impl ::core::cmp::PartialEq for Error { - #[inline] - fn eq(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Internal(ref __self_0), &Error::Internal(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Internal(ref __self_0), &Error::Internal(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - _ => false, - } - } else { - true - } - } - } -} -impl From for Error { - fn from(err: sp_npos_elections::Error) -> Self { - Error::Internal(err) - } -} diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 4e2c556bbf25c..cfba0a68a6c9b 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -245,6 +245,10 @@ pub struct ReadySolution { /// The final supports of the solution. This is target-major vector, storing each winners, total /// backing, and each individual backer. supports: FlatSupportMap, + /// The score of the solution. + /// + /// This is needed to potentially challenge the solution. + score: ElectionScore, /// How this election was computed. compute: ElectionCompute, } @@ -452,7 +456,7 @@ decl_module! { /// /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution /// might be rewarded, slashed, or get all or a part of the deposit back. - #[weight = 0] + #[weight = T::WeightInfo::submit()] fn submit(origin, solution: RawSolution>) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -477,11 +481,52 @@ decl_module! { Ok(None.into()) } - #[weight = 0] + /// Submit a solution for the unsigned phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. + /// Moreover, this unsigned solution is only validated when submitted to the pool from the + /// local process. Effectively, this means that only active validators can submit this + /// transaction when authoring a block. + /// + /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will + /// panic if the solution submitted by the validator is invalid, effectively putting their + /// authoring reward at risk. + /// + /// No deposit or reward is associated with this. + #[weight = T::WeightInfo::submit_unsigned()] fn submit_unsigned(origin, solution: RawSolution>) { ensure_none(origin)?; + + // ensure solution is timely. Don't panic yet. This is a cheap check. + ensure!(Self::current_phase().is_signed(), "EarlySubmission"); + + use sp_npos_elections::is_score_better; + // ensure score is being improved. Panic henceforth. + assert!( + Self::queued_solution().map_or( + true, + |q: ReadySolution<_>| + is_score_better::( + solution.score, + q.score, + T::SolutionImprovementThreshold::get() + ) + ), + "WeakSolution" + ); + + let ready = + Self::feasibility_check(solution, ElectionCompute::Unsigned) + .expect( + "Invalid unsigned submission must produce invalid block and deprive \ + validator from their authoring reward." + ); + + // store the newly received solution. + >::put(ready); Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); - unimplemented!() } } } @@ -582,7 +627,11 @@ where ensure!(known_score == score, FeasibilityError::InvalidScore); // let supports = supports.flatten(); - Ok(ReadySolution { supports, compute }) + Ok(ReadySolution { + supports, + compute, + score, + }) } /// On-chain fallback of election. @@ -622,9 +671,7 @@ where .map(|r| (r, ElectionCompute::OnChain)) .map_err(Into::into) }, - |ReadySolution { - supports, compute, .. - }| Ok((supports, compute)), + |ReadySolution { supports, compute, ..}| Ok((supports, compute)), ) .map(|(supports, compute)| { // reset phase. @@ -735,5 +782,7 @@ mod tests { } #[test] - fn can_only_submit_threshold_better() {} + fn can_only_submit_threshold_better() { + unimplemented!() + } } diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index e69de29bb2d1d..2fae4c043cbb2 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -0,0 +1,31 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The unsigned phase implementation. + +use crate::two_phase::*; +use codec::Encode; +use sp_arithmetic::traits::SaturatedConversion; +use sp_npos_elections::is_score_better; +use sp_runtime::Perbill; + +impl Module where ExtendedBalance: From>> {} + +#[cfg(test)] +mod tests { + use super::{mock::*, *}; +} From 6a2542d0be66f8a05cf3cb44464885d9ef95d9c9 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 13 Oct 2020 19:13:01 +0200 Subject: [PATCH 09/62] Staking builds and tests compile, some tests fail --- frame/staking/src/benchmarking.rs | 440 ++-- frame/staking/src/default_weights.rs | 19 +- frame/staking/src/lib.rs | 1260 ++-------- frame/staking/src/mock.rs | 393 ++-- frame/staking/src/testing_utils.rs | 358 +-- frame/staking/src/tests.rs | 2669 +++++++++++----------- primitives/npos-elections/src/helpers.rs | 5 - 7 files changed, 2167 insertions(+), 2977 deletions(-) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index e9467fa50be15..20716b1280c37 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -484,220 +484,220 @@ benchmarks! { assert!(balance_before > balance_after); } - // This benchmark create `v` validators intent, `n` nominators intent, in total creating `e` - // edges. - #[extra] - submit_solution_initial { - // number of validator intention. This will be equal to `ElectionSize::validators`. - let v in 200 .. 400; - // number of nominator intention. This will be equal to `ElectionSize::nominators`. - let n in 500 .. 1000; - // number of assignments. Basically, number of active nominators. This will be equal to - // `compact.len()`. - let a in 200 .. 400; - // number of winners, also ValidatorCount. This will be equal to `winner.len()`. - let w in 16 .. 100; - - ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); - - let winners = create_validators_with_nominators_for_era::( - v, - n, - MAX_NOMINATIONS, - false, - Some(w), - )?; - - // needed for the solution to be generates. - assert!(>::create_stakers_snapshot().0); - - // set number of winners - ValidatorCount::put(w); - - // create a assignments in total for the w winners. - let (winners, assignments) = create_assignments_for_offchain::(a, winners)?; - - let ( - winners, - compact, - score, - size - ) = offchain_election::prepare_submission::(assignments, winners, false, T::MaximumBlockWeight::get()).unwrap(); - - assert_eq!( - winners.len(), compact.unique_targets().len(), - "unique targets ({}) and winners ({}) count not same. This solution is not valid.", - compact.unique_targets().len(), - winners.len(), - ); - - // needed for the solution to be accepted - >::put(ElectionStatus::Open(T::BlockNumber::from(1u32))); - - let era = >::current_era().unwrap_or(0); - let caller: T::AccountId = account("caller", n, SEED); - whitelist_account!(caller); - }: { - let result = >::submit_election_solution( - RawOrigin::Signed(caller.clone()).into(), - winners, - compact, - score.clone(), - era, - size, - ); - assert!(result.is_ok()); - } - verify { - // new solution has been accepted. - assert_eq!(>::queued_score().unwrap(), score); - } - - // same as submit_solution_initial but we place a very weak solution on chian first. - submit_solution_better { - // number of validator intention. - let v in 200 .. 400; - // number of nominator intention. - let n in 500 .. 1000; - // number of assignments. Basically, number of active nominators. - let a in 200 .. 400; - // number of winners, also ValidatorCount. - let w in 16 .. 100; - - ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); - - let winners = create_validators_with_nominators_for_era::( - v, - n, - MAX_NOMINATIONS, - false, - Some(w), - )?; - - // needed for the solution to be generates. - assert!(>::create_stakers_snapshot().0); - - // set number of winners - ValidatorCount::put(w); - - // create a assignments in total for the w winners. - let (winners, assignments) = create_assignments_for_offchain::(a, winners)?; - - let single_winner = winners[0].0.clone(); - - let ( - winners, - compact, - score, - size - ) = offchain_election::prepare_submission::(assignments, winners, false, T::MaximumBlockWeight::get()).unwrap(); - - assert_eq!( - winners.len(), compact.unique_targets().len(), - "unique targets ({}) and winners ({}) count not same. This solution is not valid.", - compact.unique_targets().len(), - winners.len(), - ); - - // needed for the solution to be accepted - >::put(ElectionStatus::Open(T::BlockNumber::from(1u32))); - - let era = >::current_era().unwrap_or(0); - let caller: T::AccountId = account("caller", n, SEED); - whitelist_account!(caller); - - // submit a very bad solution on-chain - { - // this is needed to fool the chain to accept this solution. - ValidatorCount::put(1); - let (winners, compact, score, size) = get_single_winner_solution::(single_winner)?; - assert!( - >::submit_election_solution( - RawOrigin::Signed(caller.clone()).into(), - winners, - compact, - score.clone(), - era, - size, - ).is_ok()); - - // new solution has been accepted. - assert_eq!(>::queued_score().unwrap(), score); - ValidatorCount::put(w); - } - }: { - let result = >::submit_election_solution( - RawOrigin::Signed(caller.clone()).into(), - winners, - compact, - score.clone(), - era, - size, - ); - assert!(result.is_ok()); - } - verify { - // new solution has been accepted. - assert_eq!(>::queued_score().unwrap(), score); - } - - // This will be early rejected based on the score. - #[extra] - submit_solution_weaker { - // number of validator intention. - let v in 200 .. 400; - // number of nominator intention. - let n in 500 .. 1000; - - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None)?; - - // needed for the solution to be generates. - assert!(>::create_stakers_snapshot().0); - - // needed for the solution to be accepted - >::put(ElectionStatus::Open(T::BlockNumber::from(1u32))); - let era = >::current_era().unwrap_or(0); - let caller: T::AccountId = account("caller", n, SEED); - whitelist_account!(caller); - - // submit a seq-phragmen with all the good stuff on chain. - { - let (winners, compact, score, size) = get_seq_phragmen_solution::(true); - assert_eq!( - winners.len(), compact.unique_targets().len(), - "unique targets ({}) and winners ({}) count not same. This solution is not valid.", - compact.unique_targets().len(), - winners.len(), - ); - assert!( - >::submit_election_solution( - RawOrigin::Signed(caller.clone()).into(), - winners, - compact, - score.clone(), - era, - size, - ).is_ok() - ); - - // new solution has been accepted. - assert_eq!(>::queued_score().unwrap(), score); - } - - // prepare a bad solution. This will be very early rejected. - let (winners, compact, score, size) = get_weak_solution::(true); - }: { - assert!( - >::submit_election_solution( - RawOrigin::Signed(caller.clone()).into(), - winners, - compact, - score.clone(), - era, - size, - ).is_err() - ); - } + // // This benchmark create `v` validators intent, `n` nominators intent, in total creating `e` + // // edges. + // #[extra] + // submit_solution_initial { + // // number of validator intention. This will be equal to `ElectionSize::validators`. + // let v in 200 .. 400; + // // number of nominator intention. This will be equal to `ElectionSize::nominators`. + // let n in 500 .. 1000; + // // number of assignments. Basically, number of active nominators. This will be equal to + // // `compact.len()`. + // let a in 200 .. 400; + // // number of winners, also ValidatorCount. This will be equal to `winner.len()`. + // let w in 16 .. 100; + + // ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); + + // let winners = create_validators_with_nominators_for_era::( + // v, + // n, + // MAX_NOMINATIONS, + // false, + // Some(w), + // )?; + + // // needed for the solution to be generates. + // assert!(>::create_stakers_snapshot().0); + + // // set number of winners + // ValidatorCount::put(w); + + // // create a assignments in total for the w winners. + // let (winners, assignments) = create_assignments_for_offchain::(a, winners)?; + + // let ( + // winners, + // compact, + // score, + // size + // ) = offchain_election::prepare_submission::(assignments, winners, false, T::MaximumBlockWeight::get()).unwrap(); + + // assert_eq!( + // winners.len(), compact.unique_targets().len(), + // "unique targets ({}) and winners ({}) count not same. This solution is not valid.", + // compact.unique_targets().len(), + // winners.len(), + // ); + + // // needed for the solution to be accepted + // >::put(ElectionStatus::Open(T::BlockNumber::from(1u32))); + + // let era = >::current_era().unwrap_or(0); + // let caller: T::AccountId = account("caller", n, SEED); + // whitelist_account!(caller); + // }: { + // let result = >::submit_election_solution( + // RawOrigin::Signed(caller.clone()).into(), + // winners, + // compact, + // score.clone(), + // era, + // size, + // ); + // assert!(result.is_ok()); + // } + // verify { + // // new solution has been accepted. + // assert_eq!(>::queued_score().unwrap(), score); + // } + + // // same as submit_solution_initial but we place a very weak solution on chian first. + // submit_solution_better { + // // number of validator intention. + // let v in 200 .. 400; + // // number of nominator intention. + // let n in 500 .. 1000; + // // number of assignments. Basically, number of active nominators. + // let a in 200 .. 400; + // // number of winners, also ValidatorCount. + // let w in 16 .. 100; + + // ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); + + // let winners = create_validators_with_nominators_for_era::( + // v, + // n, + // MAX_NOMINATIONS, + // false, + // Some(w), + // )?; + + // // needed for the solution to be generates. + // assert!(>::create_stakers_snapshot().0); + + // // set number of winners + // ValidatorCount::put(w); + + // // create a assignments in total for the w winners. + // let (winners, assignments) = create_assignments_for_offchain::(a, winners)?; + + // let single_winner = winners[0].0.clone(); + + // let ( + // winners, + // compact, + // score, + // size + // ) = offchain_election::prepare_submission::(assignments, winners, false, T::MaximumBlockWeight::get()).unwrap(); + + // assert_eq!( + // winners.len(), compact.unique_targets().len(), + // "unique targets ({}) and winners ({}) count not same. This solution is not valid.", + // compact.unique_targets().len(), + // winners.len(), + // ); + + // // needed for the solution to be accepted + // >::put(ElectionStatus::Open(T::BlockNumber::from(1u32))); + + // let era = >::current_era().unwrap_or(0); + // let caller: T::AccountId = account("caller", n, SEED); + // whitelist_account!(caller); + + // // submit a very bad solution on-chain + // { + // // this is needed to fool the chain to accept this solution. + // ValidatorCount::put(1); + // let (winners, compact, score, size) = get_single_winner_solution::(single_winner)?; + // assert!( + // >::submit_election_solution( + // RawOrigin::Signed(caller.clone()).into(), + // winners, + // compact, + // score.clone(), + // era, + // size, + // ).is_ok()); + + // // new solution has been accepted. + // assert_eq!(>::queued_score().unwrap(), score); + // ValidatorCount::put(w); + // } + // }: { + // let result = >::submit_election_solution( + // RawOrigin::Signed(caller.clone()).into(), + // winners, + // compact, + // score.clone(), + // era, + // size, + // ); + // assert!(result.is_ok()); + // } + // verify { + // // new solution has been accepted. + // assert_eq!(>::queued_score().unwrap(), score); + // } + + // // This will be early rejected based on the score. + // #[extra] + // submit_solution_weaker { + // // number of validator intention. + // let v in 200 .. 400; + // // number of nominator intention. + // let n in 500 .. 1000; + + // create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None)?; + + // // needed for the solution to be generates. + // assert!(>::create_stakers_snapshot().0); + + // // needed for the solution to be accepted + // >::put(ElectionStatus::Open(T::BlockNumber::from(1u32))); + // let era = >::current_era().unwrap_or(0); + // let caller: T::AccountId = account("caller", n, SEED); + // whitelist_account!(caller); + + // // submit a seq-phragmen with all the good stuff on chain. + // { + // let (winners, compact, score, size) = get_seq_phragmen_solution::(true); + // assert_eq!( + // winners.len(), compact.unique_targets().len(), + // "unique targets ({}) and winners ({}) count not same. This solution is not valid.", + // compact.unique_targets().len(), + // winners.len(), + // ); + // assert!( + // >::submit_election_solution( + // RawOrigin::Signed(caller.clone()).into(), + // winners, + // compact, + // score.clone(), + // era, + // size, + // ).is_ok() + // ); + + // // new solution has been accepted. + // assert_eq!(>::queued_score().unwrap(), score); + // } + + // // prepare a bad solution. This will be very early rejected. + // let (winners, compact, score, size) = get_weak_solution::(true); + // }: { + // assert!( + // >::submit_election_solution( + // RawOrigin::Signed(caller.clone()).into(), + // winners, + // compact, + // score.clone(), + // era, + // size, + // ).is_err() + // ); + // } } #[cfg(test)] @@ -825,18 +825,6 @@ mod tests { assert_ok!(test_benchmark_new_era::()); assert_ok!(test_benchmark_do_slash::()); assert_ok!(test_benchmark_payout_all::()); - // only run one of them to same time on the CI. ignore the other two. - assert_ok!(test_benchmark_submit_solution_initial::()); }); } - - #[test] - #[ignore] - fn test_benchmarks_offchain() { - ExtBuilder::default().has_stakers(false).build().execute_with(|| { - assert_ok!(test_benchmark_submit_solution_better::()); - assert_ok!(test_benchmark_submit_solution_weaker::()); - }); - } - } diff --git a/frame/staking/src/default_weights.rs b/frame/staking/src/default_weights.rs index fa5a05f63824e..ee30d3ea1e9e2 100644 --- a/frame/staking/src/default_weights.rs +++ b/frame/staking/src/default_weights.rs @@ -125,27 +125,27 @@ impl crate::WeightInfo for () { .saturating_add(DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(DbWeight::get().writes((3 as Weight).saturating_mul(n as Weight))) } - fn rebond(l: u32, ) -> Weight { + fn rebond(l: u32) -> Weight { (71316000 as Weight) .saturating_add((142000 as Weight).saturating_mul(l as Weight)) .saturating_add(DbWeight::get().reads(4 as Weight)) .saturating_add(DbWeight::get().writes(3 as Weight)) } - fn set_history_depth(e: u32, ) -> Weight { + fn set_history_depth(e: u32) -> Weight { (0 as Weight) .saturating_add((51901000 as Weight).saturating_mul(e as Weight)) .saturating_add(DbWeight::get().reads(2 as Weight)) .saturating_add(DbWeight::get().writes(4 as Weight)) .saturating_add(DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) } - fn reap_stash(s: u32, ) -> Weight { + fn reap_stash(s: u32) -> Weight { (147166000 as Weight) .saturating_add((6661000 as Weight).saturating_mul(s as Weight)) .saturating_add(DbWeight::get().reads(4 as Weight)) .saturating_add(DbWeight::get().writes(8 as Weight)) .saturating_add(DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) } - fn new_era(v: u32, n: u32, ) -> Weight { + fn new_era(v: u32, n: u32) -> Weight { (0 as Weight) .saturating_add((1440459000 as Weight).saturating_mul(v as Weight)) .saturating_add((182580000 as Weight).saturating_mul(n as Weight)) @@ -155,15 +155,4 @@ impl crate::WeightInfo for () { .saturating_add(DbWeight::get().writes(8 as Weight)) .saturating_add(DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) } - fn submit_solution_better(v: u32, n: u32, a: u32, w: u32, ) -> Weight { - (0 as Weight) - .saturating_add((964000 as Weight).saturating_mul(v as Weight)) - .saturating_add((432000 as Weight).saturating_mul(n as Weight)) - .saturating_add((204294000 as Weight).saturating_mul(a as Weight)) - .saturating_add((9546000 as Weight).saturating_mul(w as Weight)) - .saturating_add(DbWeight::get().reads(6 as Weight)) - .saturating_add(DbWeight::get().reads((4 as Weight).saturating_mul(a as Weight))) - .saturating_add(DbWeight::get().reads((1 as Weight).saturating_mul(w as Weight))) - .saturating_add(DbWeight::get().writes(2 as Weight)) - } } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 3d913506eaa3b..72d5612cd4f29 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -277,63 +277,54 @@ pub mod testing_utils; pub mod benchmarking; pub mod slashing; -pub mod offchain_election; -pub mod inflation; +// pub mod offchain_election; pub mod default_weights; +pub mod inflation; -use sp_std::{ - result, - prelude::*, - collections::btree_map::BTreeMap, - convert::{TryInto, From}, - mem::size_of, -}; -use codec::{HasCompact, Encode, Decode}; +use codec::{Decode, Encode, HasCompact}; +use frame_election_providers::{ElectionDataProvider, ElectionProvider, FlatSupportMap}; use frame_support::{ - decl_module, decl_event, decl_storage, ensure, decl_error, - weights::{Weight, constants::{WEIGHT_PER_MICROS, WEIGHT_PER_NANOS}}, + decl_error, decl_event, decl_module, decl_storage, + dispatch::{DispatchResult, DispatchResultWithPostInfo}, + ensure, storage::IterableStorageMap, - dispatch::{ - IsSubType, DispatchResult, DispatchResultWithPostInfo, DispatchErrorWithPostInfo, - WithPostDispatchInfo, - }, traits::{ - Currency, LockIdentifier, LockableCurrency, WithdrawReasons, OnUnbalanced, Imbalance, Get, - UnixTime, EstimateNextNewSession, EnsureOrigin, CurrencyToVote, - } + Currency, CurrencyToVote, EnsureOrigin, EstimateNextNewSession, Get, Imbalance, + LockIdentifier, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, + }, + weights::{ + constants::{WEIGHT_PER_MICROS, WEIGHT_PER_NANOS}, + Weight, + }, }; +use frame_system::{self as system, ensure_root, ensure_signed, offchain::SendTransactionTypes}; use pallet_session::historical; +use sp_npos_elections::{generate_solution_type, CompactSolution, ExtendedBalance, VoteWeight}; use sp_runtime::{ - Percent, Perbill, PerU16, PerThing, InnerOf, RuntimeDebug, DispatchError, curve::PiecewiseLinear, traits::{ - Convert, Zero, StaticLookup, CheckedSub, Saturating, SaturatedConversion, - AtLeast32BitUnsigned, Dispatchable, - }, - transaction_validity::{ - TransactionValidityError, TransactionValidity, ValidTransaction, InvalidTransaction, - TransactionSource, TransactionPriority, + AtLeast32BitUnsigned, CheckedSub, Convert, SaturatedConversion, Saturating, StaticLookup, + Zero, }, + PerThing, PerU16, Perbill, Percent, RuntimeDebug, }; +#[cfg(feature = "std")] +use sp_runtime::{Deserialize, Serialize}; use sp_staking::{ + offence::{Offence, OffenceDetails, OffenceError, OnOffenceHandler, ReportOffence}, SessionIndex, - offence::{OnOffenceHandler, OffenceDetails, Offence, ReportOffence, OffenceError}, -}; -#[cfg(feature = "std")] -use sp_runtime::{Serialize, Deserialize}; -use frame_system::{ - self as system, ensure_signed, ensure_root, ensure_none, - offchain::SendTransactionTypes, }; -use sp_npos_elections::{ - ExtendedBalance, Assignment, ElectionScore, ElectionResult as PrimitiveElectionResult, - build_support_map, evaluate_support, seq_phragmen, generate_solution_type, - is_score_better, VotingLimit, SupportMap, VoteWeight, +use sp_std::{ + collections::btree_map::BTreeMap, + convert::{From, TryInto}, + mem::size_of, + prelude::*, + result, }; const STAKING_ID: LockIdentifier = *b"staking "; pub const MAX_UNLOCKING_CHUNKS: usize = 32; -pub const MAX_NOMINATIONS: usize = ::LIMIT; +pub const MAX_NOMINATIONS: usize = ::LIMIT; pub(crate) const LOG_TARGET: &'static str = "staking"; @@ -360,10 +351,6 @@ static_assertions::const_assert!(size_of::() <= size_of:: static_assertions::const_assert!(size_of::() <= size_of::()); static_assertions::const_assert!(size_of::() <= size_of::()); -/// Maximum number of stakers that can be stored in a snapshot. -pub(crate) const MAX_VALIDATORS: usize = ValidatorIndex::max_value() as usize; -pub(crate) const MAX_NOMINATORS: usize = NominatorIndex::max_value() as usize; - /// Counter for the number of eras that have passed. pub type EraIndex = u32; @@ -373,7 +360,7 @@ pub type RewardPoint = u32; // Note: Maximum nomination limit is set here -- 16. generate_solution_type!( #[compact] - pub struct CompactAssignments::(16) + pub struct CompactU16Solution::(16) ); /// Accuracy used for on-chain election. @@ -657,75 +644,40 @@ pub struct UnappliedSlash { payout: Balance, } -/// Indicate how an election round was computed. -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] -pub enum ElectionCompute { - /// Result was forcefully computed on chain at the end of the session. - OnChain, - /// Result was submitted and accepted to the chain via a signed transaction. - Signed, - /// Result was submitted and accepted to the chain via an unsigned transaction (by an - /// authority). - Unsigned, -} - -/// The result of an election round. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] -pub struct ElectionResult { - /// Flat list of validators who have been elected. - elected_stashes: Vec, - /// Flat list of new exposures, to be updated in the [`Exposure`] storage. - exposures: Vec<(AccountId, Exposure)>, - /// Type of the result. This is kept on chain only to track and report the best score's - /// submission type. An optimisation could remove this. - compute: ElectionCompute, -} - -/// The status of the upcoming (offchain) election. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] -pub enum ElectionStatus { - /// Nothing has and will happen for now. submission window is not open. - Closed, - /// The submission window has been open since the contained block number. - Open(BlockNumber), -} - -/// Some indications about the size of the election. This must be submitted with the solution. -/// -/// Note that these values must reflect the __total__ number, not only those that are present in the -/// solution. In short, these should be the same size as the size of the values dumped in -/// `SnapshotValidators` and `SnapshotNominators`. -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, Default)] -pub struct ElectionSize { - /// Number of validators in the snapshot of the current election round. - #[codec(compact)] - pub validators: ValidatorIndex, - /// Number of nominators in the snapshot of the current election round. - #[codec(compact)] - pub nominators: NominatorIndex, +/// Mode of era-forcing. +#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum Forcing { + /// Not forcing anything - just let whatever happen. + NotForcing, + /// Force a new era, then reset to `NotForcing` as soon as it is done. + ForceNew, + /// Avoid a new era indefinitely. + ForceNone, + /// Force a new era at the end of all sessions indefinitely. + ForceAlways, } - -impl ElectionStatus { - pub fn is_open_at(&self, n: BlockNumber) -> bool { - *self == Self::Open(n) - } - - pub fn is_closed(&self) -> bool { - match self { - Self::Closed => true, - _ => false - } +impl Default for Forcing { + fn default() -> Self { + Forcing::NotForcing } +} - pub fn is_open(&self) -> bool { - !self.is_closed() - } +// A value placed in storage that represents the current version of the Staking storage. This value +// is used by the `on_runtime_upgrade` logic to determine whether we run storage migration logic. +// This should match directly with the semantic versions of the Rust crate. +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)] +enum Releases { + V1_0_0Ancient, + V2_0_0, + V3_0_0, + V4_0_0, } -impl Default for ElectionStatus { +impl Default for Releases { fn default() -> Self { - Self::Closed + Releases::V4_0_0 } } @@ -785,15 +737,14 @@ pub trait WeightInfo { fn force_new_era() -> Weight; fn force_new_era_always() -> Weight; fn set_invulnerables(v: u32, ) -> Weight; - fn force_unstake(s: u32, ) -> Weight; - fn cancel_deferred_slash(s: u32, ) -> Weight; - fn payout_stakers_alive_staked(n: u32, ) -> Weight; - fn payout_stakers_dead_controller(n: u32, ) -> Weight; - fn rebond(l: u32, ) -> Weight; - fn set_history_depth(e: u32, ) -> Weight; - fn reap_stash(s: u32, ) -> Weight; - fn new_era(v: u32, n: u32, ) -> Weight; - fn submit_solution_better(v: u32, n: u32, a: u32, w: u32, ) -> Weight; + fn force_unstake(s: u32) -> Weight; + fn cancel_deferred_slash(s: u32) -> Weight; + fn payout_stakers_alive_staked(n: u32) -> Weight; + fn payout_stakers_dead_controller(n: u32) -> Weight; + fn rebond(l: u32) -> Weight; + fn set_history_depth(e: u32) -> Weight; + fn reap_stash(s: u32) -> Weight; + fn new_era(v: u32, n: u32) -> Weight; } pub trait Trait: frame_system::Trait + SendTransactionTypes> { @@ -813,6 +764,9 @@ pub trait Trait: frame_system::Trait + SendTransactionTypes> { /// [`BalanceOf`]. type CurrencyToVote: CurrencyToVote>; + /// Something that provides the election functionality. + type ElectionProvider: frame_election_providers::ElectionProvider; + /// Tokens have been minted and are unused for validator-reward. /// See [Era payout](./index.html#era-payout). type RewardRemainder: OnUnbalanced>; @@ -851,84 +805,14 @@ pub trait Trait: frame_system::Trait + SendTransactionTypes> { /// Something that can estimate the next session change, accurately or as a best effort guess. type NextNewSession: EstimateNextNewSession; - /// The number of blocks before the end of the era from which election submissions are allowed. - /// - /// Setting this to zero will disable the offchain compute and only on-chain seq-phragmen will - /// be used. - /// - /// This is bounded by being within the last session. Hence, setting it to a value more than the - /// length of a session will be pointless. - type ElectionLookahead: Get; - - /// The overarching call type. - type Call: Dispatchable + From> + IsSubType> + Clone; - - /// Maximum number of balancing iterations to run in the offchain submission. - /// - /// If set to 0, balance_solution will not be executed at all. - type MaxIterations: Get; - - /// The threshold of improvement that should be provided for a new solution to be accepted. - type MinSolutionScoreBump: Get; - /// The maximum number of nominators rewarded for each validator. /// /// For each validator only the `$MaxNominatorRewardedPerValidator` biggest stakers can claim /// their reward. This used to limit the i/o cost for the nominator payout. type MaxNominatorRewardedPerValidator: Get; - /// A configuration for base priority of unsigned transactions. - /// - /// This is exposed so that it can be tuned for particular runtime, when - /// multiple pallets send unsigned transactions. - type UnsignedPriority: Get; - - /// Maximum weight that the unsigned transaction can have. - /// - /// Chose this value with care. On one hand, it should be as high as possible, so the solution - /// can contain as many nominators/validators as possible. On the other hand, it should be small - /// enough to fit in the block. - type OffchainSolutionWeightLimit: Get; - /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; - - type ElectionProvider: frame_election_providers::ElectionProvider; -} - -/// Mode of era-forcing. -#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub enum Forcing { - /// Not forcing anything - just let whatever happen. - NotForcing, - /// Force a new era, then reset to `NotForcing` as soon as it is done. - ForceNew, - /// Avoid a new era indefinitely. - ForceNone, - /// Force a new era at the end of all sessions indefinitely. - ForceAlways, -} - -impl Default for Forcing { - fn default() -> Self { Forcing::NotForcing } -} - -// A value placed in storage that represents the current version of the Staking storage. This value -// is used by the `on_runtime_upgrade` logic to determine whether we run storage migration logic. -// This should match directly with the semantic versions of the Rust crate. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)] -enum Releases { - V1_0_0Ancient, - V2_0_0, - V3_0_0, - V4_0_0, -} - -impl Default for Releases { - fn default() -> Self { - Releases::V4_0_0 - } } decl_storage! { @@ -1084,29 +968,13 @@ decl_storage! { /// The earliest era for which we have a pending, unapplied slash. EarliestUnappliedSlash: Option; - /// Snapshot of validators at the beginning of the current election window. This should only - /// have a value when [`EraElectionStatus`] == `ElectionStatus::Open(_)`. - pub SnapshotValidators get(fn snapshot_validators): Option>; - - /// Snapshot of nominators at the beginning of the current election window. This should only - /// have a value when [`EraElectionStatus`] == `ElectionStatus::Open(_)`. - pub SnapshotNominators get(fn snapshot_nominators): Option>; - - /// The next validator set. At the end of an era, if this is available (potentially from the - /// result of an offchain worker), it is immediately used. Otherwise, the on-chain election - /// is executed. - pub QueuedElected get(fn queued_elected): Option>>; - - /// The score of the current [`QueuedElected`]. - pub QueuedScore get(fn queued_score): Option; - - /// Flag to control the execution of the offchain election. When `Open(_)`, we accept - /// solutions to be submitted. - pub EraElectionStatus get(fn era_election_status): ElectionStatus; - - /// True if the current **planned** session is final. Note that this does not take era - /// forcing into account. - pub IsCurrentSessionFinal get(fn is_current_session_final): bool = false; + // TODO: removed storage items: + // IsCurrentSessionFinal + // EraElectionStatus + // QueuedScore + // QueuedElected + // SnapshotNominators + // SnapshotValidators /// True if network has been upgraded to this version. /// Storage version of the pallet. @@ -1163,9 +1031,7 @@ decl_event!( /// not be processed. \[session_index\] OldSlashingReportDiscarded(SessionIndex), /// A new set of stakers was elected with the given \[compute\]. - StakingElection(ElectionCompute), - /// A new solution for the upcoming election has been stored. \[compute\] - SolutionStored(ElectionCompute), + StakingElection, /// An account has bonded this amount. \[stash, amount\] /// /// NOTE: This event is only emitted when funds are bonded via a dispatchable. Notably, @@ -1265,23 +1131,6 @@ decl_module! { /// intervention. const SlashDeferDuration: EraIndex = T::SlashDeferDuration::get(); - /// The number of blocks before the end of the era from which election submissions are allowed. - /// - /// Setting this to zero will disable the offchain compute and only on-chain seq-phragmen will - /// be used. - /// - /// This is bounded by being within the last session. Hence, setting it to a value more than the - /// length of a session will be pointless. - const ElectionLookahead: T::BlockNumber = T::ElectionLookahead::get(); - - /// Maximum number of balancing iterations to run in the offchain submission. - /// - /// If set to 0, balance_solution will not be executed at all. - const MaxIterations: u32 = T::MaxIterations::get(); - - /// The threshold of improvement that should be provided for a new solution to be accepted. - const MinSolutionScoreBump: Perbill = T::MinSolutionScoreBump::get(); - /// The maximum number of nominators rewarded for each validator. /// /// For each validator only the `$MaxNominatorRewardedPerValidator` biggest stakers can claim @@ -1292,74 +1141,6 @@ decl_module! { fn deposit_event() = default; - /// sets `ElectionStatus` to `Open(now)` where `now` is the block number at which the - /// election window has opened, if we are at the last session and less blocks than - /// `T::ElectionLookahead` is remaining until the next new session schedule. The offchain - /// worker, if applicable, will execute at the end of the current block, and solutions may - /// be submitted. - fn on_initialize(now: T::BlockNumber) -> Weight { - let mut consumed_weight = 0; - let mut add_weight = |reads, writes, weight| { - consumed_weight += T::DbWeight::get().reads_writes(reads, writes); - consumed_weight += weight; - }; - - if - // if we don't have any ongoing offchain compute. - Self::era_election_status().is_closed() && - // either current session final based on the plan, or we're forcing. - (Self::is_current_session_final() || Self::will_era_be_forced()) - { - if let Some(next_session_change) = T::NextNewSession::estimate_next_new_session(now) { - if let Some(remaining) = next_session_change.checked_sub(&now) { - if remaining <= T::ElectionLookahead::get() && !remaining.is_zero() { - // create snapshot. - let (did_snapshot, snapshot_weight) = Self::create_stakers_snapshot(); - add_weight(0, 0, snapshot_weight); - if did_snapshot { - // Set the flag to make sure we don't waste any compute here in the same era - // after we have triggered the offline compute. - >::put( - ElectionStatus::::Open(now) - ); - add_weight(0, 1, 0); - log!(info, "💸 Election window is Open({:?}). Snapshot created", now); - } else { - log!(warn, "💸 Failed to create snapshot at {:?}.", now); - } - } - } - } else { - log!(warn, "💸 Estimating next session change failed."); - } - add_weight(0, 0, T::NextNewSession::weight(now)) - } - // For `era_election_status`, `is_current_session_final`, `will_era_be_forced` - add_weight(3, 0, 0); - // Additional read from `on_finalize` - add_weight(1, 0, 0); - consumed_weight - } - - /// Check if the current block number is the one at which the election window has been set - /// to open. If so, it runs the offchain worker code. - fn offchain_worker(now: T::BlockNumber) { - use offchain_election::{set_check_offchain_execution_status, compute_offchain_election}; - - if Self::era_election_status().is_open_at(now) { - let offchain_status = set_check_offchain_execution_status::(now); - if let Err(why) = offchain_status { - log!(warn, "💸 skipping offchain worker in open election window due to [{}]", why); - } else { - if let Err(e) = compute_offchain_election::() { - log!(error, "💸 Error in election offchain worker: {:?}", e); - } else { - log!(debug, "💸 Executed offchain worker thread without errors."); - } - } - } - } - fn on_finalize() { // Set the start of the first era. if let Some(mut active_era) = Self::active_era() { @@ -1495,7 +1276,6 @@ decl_module! { /// # #[weight = T::WeightInfo::bond_extra()] fn bond_extra(origin, #[compact] max_additional: BalanceOf) { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let stash = ensure_signed(origin)?; let controller = Self::bonded(&stash).ok_or(Error::::NotStash)?; @@ -1546,7 +1326,6 @@ decl_module! { /// #[weight = T::WeightInfo::unbond()] fn unbond(origin, #[compact] value: BalanceOf) { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; ensure!( @@ -1606,7 +1385,6 @@ decl_module! { /// # #[weight = T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans)] fn withdraw_unbonded(origin, num_slashing_spans: u32) -> DispatchResultWithPostInfo { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let (stash, old_total) = (ledger.stash.clone(), ledger.total); @@ -1661,7 +1439,6 @@ decl_module! { /// # #[weight = T::WeightInfo::validate()] pub fn validate(origin, prefs: ValidatorPrefs) { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let stash = &ledger.stash; @@ -1690,7 +1467,6 @@ decl_module! { /// # #[weight = T::WeightInfo::nominate(targets.len() as u32)] pub fn nominate(origin, targets: Vec<::Source>) { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let stash = &ledger.stash; @@ -1730,7 +1506,6 @@ decl_module! { /// # #[weight = T::WeightInfo::chill()] fn chill(origin) { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; Self::chill_stash(&ledger.stash); @@ -1974,7 +1749,6 @@ decl_module! { /// # #[weight = T::WeightInfo::payout_stakers_alive_staked(T::MaxNominatorRewardedPerValidator::get())] fn payout_stakers(origin, validator_stash: T::AccountId, era: EraIndex) -> DispatchResult { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); ensure_signed(origin)?; Self::do_payout_stakers(validator_stash, era) } @@ -1995,7 +1769,6 @@ decl_module! { /// # #[weight = T::WeightInfo::rebond(MAX_UNLOCKING_CHUNKS as u32)] fn rebond(origin, #[compact] value: BalanceOf) -> DispatchResultWithPostInfo { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; ensure!(!ledger.unlocking.is_empty(), Error::::NoUnlockChunk); @@ -2070,120 +1843,7 @@ decl_module! { T::Currency::remove_lock(STAKING_ID, &stash); } - /// Submit an election result to the chain. If the solution: - /// - /// 1. is valid. - /// 2. has a better score than a potentially existing solution on chain. - /// - /// then, it will be _put_ on chain. - /// - /// A solution consists of two pieces of data: - /// - /// 1. `winners`: a flat vector of all the winners of the round. - /// 2. `assignments`: the compact version of an assignment vector that encodes the edge - /// weights. - /// - /// Both of which may be computed using _phragmen_, or any other algorithm. - /// - /// Additionally, the submitter must provide: - /// - /// - The `score` that they claim their solution has. - /// - /// Both validators and nominators will be represented by indices in the solution. The - /// indices should respect the corresponding types ([`ValidatorIndex`] and - /// [`NominatorIndex`]). Moreover, they should be valid when used to index into - /// [`SnapshotValidators`] and [`SnapshotNominators`]. Any invalid index will cause the - /// solution to be rejected. These two storage items are set during the election window and - /// may be used to determine the indices. - /// - /// A solution is valid if: - /// - /// 0. It is submitted when [`EraElectionStatus`] is `Open`. - /// 1. Its claimed score is equal to the score computed on-chain. - /// 2. Presents the correct number of winners. - /// 3. All indexes must be value according to the snapshot vectors. All edge values must - /// also be correct and should not overflow the granularity of the ratio type (i.e. 256 - /// or billion). - /// 4. For each edge, all targets are actually nominated by the voter. - /// 5. Has correct self-votes. - /// - /// A solutions score is consisted of 3 parameters: - /// - /// 1. `min { support.total }` for each support of a winner. This value should be maximized. - /// 2. `sum { support.total }` for each support of a winner. This value should be minimized. - /// 3. `sum { support.total^2 }` for each support of a winner. This value should be - /// minimized (to ensure less variance) - /// - /// # - /// The transaction is assumed to be the longest path, a better solution. - /// - Initial solution is almost the same. - /// - Worse solution is retraced in pre-dispatch-checks which sets its own weight. - /// # - #[weight = T::WeightInfo::submit_solution_better( - size.validators.into(), - size.nominators.into(), - compact.len() as u32, - winners.len() as u32, - )] - pub fn submit_election_solution( - origin, - winners: Vec, - compact: CompactAssignments, - score: ElectionScore, - era: EraIndex, - size: ElectionSize, - ) -> DispatchResultWithPostInfo { - let _who = ensure_signed(origin)?; - Self::check_and_replace_solution( - winners, - compact, - ElectionCompute::Signed, - score, - era, - size, - ) - } - - /// Unsigned version of `submit_election_solution`. - /// - /// Note that this must pass the [`ValidateUnsigned`] check which only allows transactions - /// from the local node to be included. In other words, only the block author can include a - /// transaction in the block. - /// - /// # - /// See [`submit_election_solution`]. - /// # - #[weight = T::WeightInfo::submit_solution_better( - size.validators.into(), - size.nominators.into(), - compact.len() as u32, - winners.len() as u32, - )] - pub fn submit_election_solution_unsigned( - origin, - winners: Vec, - compact: CompactAssignments, - score: ElectionScore, - era: EraIndex, - size: ElectionSize, - ) -> DispatchResultWithPostInfo { - ensure_none(origin)?; - let adjustments = Self::check_and_replace_solution( - winners, - compact, - ElectionCompute::Unsigned, - score, - era, - size, - ).expect( - "An unsigned solution can only be submitted by validators; A validator should \ - always produce correct solutions, else this block should not be imported, thus \ - effectively depriving the validators from their authoring reward. Hence, this panic - is expected." - ); - - Ok(adjustments) - } + // TODO: removal of calls, bump tx version. } } @@ -2212,56 +1872,7 @@ impl Module { }) } - /// Dump the list of validators and nominators into vectors and keep them on-chain. - /// - /// This data is used to efficiently evaluate election results. returns `true` if the operation - /// is successful. - pub fn create_stakers_snapshot() -> (bool, Weight) { - let mut consumed_weight = 0; - let mut add_db_reads_writes = |reads, writes| { - consumed_weight += T::DbWeight::get().reads_writes(reads, writes); - }; - let validators = >::iter().map(|(v, _)| v).collect::>(); - let mut nominators = >::iter().map(|(n, _)| n).collect::>(); - - let num_validators = validators.len(); - let num_nominators = nominators.len(); - add_db_reads_writes((num_validators + num_nominators) as Weight, 0); - - if - num_validators > MAX_VALIDATORS || - num_nominators.saturating_add(num_validators) > MAX_NOMINATORS - { - log!( - warn, - "💸 Snapshot size too big [{} <> {}][{} <> {}].", - num_validators, - MAX_VALIDATORS, - num_nominators, - MAX_NOMINATORS, - ); - (false, consumed_weight) - } else { - // all validators nominate themselves; - nominators.extend(validators.clone()); - - >::put(validators); - >::put(nominators); - add_db_reads_writes(0, 2); - (true, consumed_weight) - } - } - - /// Clears both snapshots of stakers. - fn kill_stakers_snapshot() { - >::kill(); - >::kill(); - } - - fn do_payout_stakers( - validator_stash: T::AccountId, - era: EraIndex, - ) -> DispatchResult { + fn do_payout_stakers(validator_stash: T::AccountId, era: EraIndex) -> DispatchResult { // Validate input data let current_era = CurrentEra::get().ok_or(Error::::InvalidEraToReward)?; ensure!(era <= current_era, Error::::InvalidEraToReward); @@ -2420,14 +2031,7 @@ impl Module { Forcing::ForceAlways => (), Forcing::NotForcing if era_length >= T::SessionsPerEra::get() => (), _ => { - // Either `ForceNone`, or `NotForcing && era_length < T::SessionsPerEra::get()`. - if era_length + 1 == T::SessionsPerEra::get() { - IsCurrentSessionFinal::put(true); - } else if era_length >= T::SessionsPerEra::get() { - // Should only happen when we are ready to trigger an era but we have ForceNone, - // otherwise previous arm would short circuit. - Self::close_election_window(); - } + // TODO: double check this. return None }, } @@ -2440,216 +2044,6 @@ impl Module { } } - /// Basic and cheap checks that we perform in validate unsigned, and in the execution. - /// - /// State reads: ElectionState, CurrentEr, QueuedScore. - /// - /// This function does weight refund in case of errors, which is based upon the fact that it is - /// called at the very beginning of the call site's function. - pub fn pre_dispatch_checks(score: ElectionScore, era: EraIndex) -> DispatchResultWithPostInfo { - // discard solutions that are not in-time - // check window open - ensure!( - Self::era_election_status().is_open(), - Error::::OffchainElectionEarlySubmission.with_weight(T::DbWeight::get().reads(1)), - ); - - // check current era. - if let Some(current_era) = Self::current_era() { - ensure!( - current_era == era, - Error::::OffchainElectionEarlySubmission.with_weight(T::DbWeight::get().reads(2)), - ) - } - - // assume the given score is valid. Is it better than what we have on-chain, if we have any? - if let Some(queued_score) = Self::queued_score() { - ensure!( - is_score_better(score, queued_score, T::MinSolutionScoreBump::get()), - Error::::OffchainElectionWeakSubmission.with_weight(T::DbWeight::get().reads(3)), - ) - } - - Ok(None.into()) - } - - /// Checks a given solution and if correct and improved, writes it on chain as the queued result - /// of the next round. This may be called by both a signed and an unsigned transaction. - pub fn check_and_replace_solution( - winners: Vec, - compact_assignments: CompactAssignments, - compute: ElectionCompute, - claimed_score: ElectionScore, - era: EraIndex, - election_size: ElectionSize, - ) -> DispatchResultWithPostInfo { - // Do the basic checks. era, claimed score and window open. - let _ = Self::pre_dispatch_checks(claimed_score, era)?; - - // before we read any further state, we check that the unique targets in compact is same as - // compact. is a all in-memory check and easy to do. Moreover, it ensures that the solution - // is not full of bogus edges that can cause lots of reads to SlashingSpans. Thus, we can - // assume that the storage access of this function is always O(|winners|), not - // O(|compact.edge_count()|). - ensure!( - compact_assignments.unique_targets().len() == winners.len(), - Error::::OffchainElectionBogusWinnerCount, - ); - - // Check that the number of presented winners is sane. Most often we have more candidates - // than we need. Then it should be `Self::validator_count()`. Else it should be all the - // candidates. - let snapshot_validators_length = >::decode_len() - .map(|l| l as u32) - .ok_or_else(|| Error::::SnapshotUnavailable)?; - - // size of the solution must be correct. - ensure!( - snapshot_validators_length == u32::from(election_size.validators), - Error::::OffchainElectionBogusElectionSize, - ); - - // check the winner length only here and when we know the length of the snapshot validators - // length. - let desired_winners = Self::validator_count().min(snapshot_validators_length); - ensure!(winners.len() as u32 == desired_winners, Error::::OffchainElectionBogusWinnerCount); - - let snapshot_nominators_len = >::decode_len() - .map(|l| l as u32) - .ok_or_else(|| Error::::SnapshotUnavailable)?; - - // rest of the size of the solution must be correct. - ensure!( - snapshot_nominators_len == election_size.nominators, - Error::::OffchainElectionBogusElectionSize, - ); - - // decode snapshot validators. - let snapshot_validators = Self::snapshot_validators() - .ok_or(Error::::SnapshotUnavailable)?; - - // check if all winners were legit; this is rather cheap. Replace with accountId. - let winners = winners.into_iter().map(|widx| { - // NOTE: at the moment, since staking is explicitly blocking any offence until election - // is closed, we don't check here if the account id at `snapshot_validators[widx]` is - // actually a validator. If this ever changes, this loop needs to also check this. - snapshot_validators.get(widx as usize).cloned().ok_or(Error::::OffchainElectionBogusWinner) - }).collect::, Error>>()?; - - // decode the rest of the snapshot. - let snapshot_nominators = Self::snapshot_nominators() - .ok_or(Error::::SnapshotUnavailable)?; - - // helpers - let nominator_at = |i: NominatorIndex| -> Option { - snapshot_nominators.get(i as usize).cloned() - }; - let validator_at = |i: ValidatorIndex| -> Option { - snapshot_validators.get(i as usize).cloned() - }; - - // un-compact. - let assignments = compact_assignments.into_assignment( - nominator_at, - validator_at, - ).map_err(|e| { - // log the error since it is not propagated into the runtime error. - log!(warn, "💸 un-compacting solution failed due to {:?}", e); - Error::::OffchainElectionBogusCompact - })?; - - // check all nominators actually including the claimed vote. Also check correct self votes. - // Note that we assume all validators and nominators in `assignments` are properly bonded, - // because they are coming from the snapshot via a given index. - for Assignment { who, distribution } in assignments.iter() { - let is_validator = >::contains_key(&who); - let maybe_nomination = Self::nominators(&who); - - if !(maybe_nomination.is_some() ^ is_validator) { - // all of the indices must map to either a validator or a nominator. If this is ever - // not the case, then the locking system of staking is most likely faulty, or we - // have bigger problems. - log!(error, "💸 detected an error in the staking locking and snapshot."); - // abort. - return Err(Error::::OffchainElectionBogusNominator.into()); - } - - if !is_validator { - // a normal vote - let nomination = maybe_nomination.expect( - "exactly one of `maybe_validator` and `maybe_nomination.is_some` is true. \ - is_validator is false; maybe_nomination is some; qed" - ); - - // NOTE: we don't really have to check here if the sum of all edges are the - // nominator correct. Un-compacting assures this by definition. - - for (t, _) in distribution { - // each target in the provided distribution must be actually nominated by the - // nominator after the last non-zero slash. - if nomination.targets.iter().find(|&tt| tt == t).is_none() { - return Err(Error::::OffchainElectionBogusNomination.into()); - } - - if ::SlashingSpans::get(&t).map_or( - false, - |spans| nomination.submitted_in < spans.last_nonzero_slash(), - ) { - return Err(Error::::OffchainElectionSlashedNomination.into()); - } - } - } else { - // a self vote - ensure!(distribution.len() == 1, Error::::OffchainElectionBogusSelfVote); - ensure!(distribution[0].0 == *who, Error::::OffchainElectionBogusSelfVote); - // defensive only. A compact assignment of length one does NOT encode the weight and - // it is always created to be 100%. - ensure!( - distribution[0].1 == OffchainAccuracy::one(), - Error::::OffchainElectionBogusSelfVote, - ); - } - } - - // convert into staked assignments. - let staked_assignments = sp_npos_elections::assignment_ratio_to_staked( - assignments, - Self::slashable_balance_of_fn(), - ); - - // build the support map thereof in order to evaluate. - let supports = build_support_map::( - &winners, - &staked_assignments, - ).map_err(|_| Error::::OffchainElectionBogusEdge)?; - - // Check if the score is the same as the claimed one. - let submitted_score = evaluate_support(&supports); - ensure!(submitted_score == claimed_score, Error::::OffchainElectionBogusScore); - - // At last, alles Ok. Exposures and store the result. - let exposures = Self::collect_exposure(supports); - log!( - info, - "💸 A better solution (with compute {:?} and score {:?}) has been validated and stored on chain.", - compute, - submitted_score, - ); - - // write new results. - >::put(ElectionResult { - elected_stashes: winners, - compute, - exposures, - }); - QueuedScore::put(submitted_score); - - // emit event. - Self::deposit_event(RawEvent::SolutionStored(compute)); - - Ok(None.into()) - } - /// Start a session potentially starting an era. fn start_session(start_session: SessionIndex) { let next_active_era = Self::active_era().map(|e| e.index + 1).unwrap_or(0); @@ -2765,240 +2159,115 @@ impl Module { maybe_new_validators } - /// Remove all the storage items associated with the election. - fn close_election_window() { - // Close window. - >::put(ElectionStatus::Closed); - // Kill snapshots. - Self::kill_stakers_snapshot(); - // Don't track final session. - IsCurrentSessionFinal::put(false); - } + /// Consume a set of [`Supports`] from [`sp_npos_elections`] and collect them into a [`Exposure`] + fn collect_exposure( + supports: frame_election_providers::FlatSupportMap, + ) -> Vec<(T::AccountId, Exposure>)> { + // TODO: maybe this can be abstracted with `From<>` + let total_issuance = T::Currency::total_issuance(); + let to_currency = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); - /// Select the new validator set at the end of the era. - /// - /// Runs [`try_do_phragmen`] and updates the following storage items: - /// - [`EraElectionStatus`]: with `None`. - /// - [`ErasStakers`]: with the new staker set. - /// - [`ErasStakersClipped`]. - /// - [`ErasValidatorPrefs`]. - /// - [`ErasTotalStake`]: with the new total stake. - /// - [`SnapshotValidators`] and [`SnapshotNominators`] are both removed. - /// - /// Internally, [`QueuedElected`], snapshots and [`QueuedScore`] are also consumed. - /// - /// If the election has been successful, It passes the new set upwards. - /// - /// This should only be called at the end of an era. - fn select_and_update_validators(current_era: EraIndex) -> Option> { - if let Some(ElectionResult::> { - elected_stashes, - exposures, - compute, - }) = Self::try_do_election() { - // Totally close the election round and data. - Self::close_election_window(); - - // Populate Stakers and write slot stake. - let mut total_stake: BalanceOf = Zero::zero(); - exposures.into_iter().for_each(|(stash, exposure)| { - total_stake = total_stake.saturating_add(exposure.total); - >::insert(current_era, &stash, &exposure); - - let mut exposure_clipped = exposure; - let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize; - if exposure_clipped.others.len() > clipped_max_len { - exposure_clipped.others.sort_by(|a, b| a.value.cmp(&b.value).reverse()); - exposure_clipped.others.truncate(clipped_max_len); - } - >::insert(¤t_era, &stash, exposure_clipped); - }); + supports + .into_iter() + .map(|(validator, support)| { + // build `struct exposure` from `support` + let mut others = Vec::with_capacity(support.voters.len()); + let mut own: BalanceOf = Zero::zero(); + let mut total: BalanceOf = Zero::zero(); + support + .voters + .into_iter() + .map(|(nominator, weight)| (nominator, to_currency(weight))) + .for_each(|(nominator, stake)| { + if nominator == validator { + own = own.saturating_add(stake); + } else { + others.push(IndividualExposure { + who: nominator, + value: stake, + }); + } + total = total.saturating_add(stake); + }); - // Insert current era staking information - >::insert(¤t_era, total_stake); + let exposure = Exposure { own, others, total }; - // collect the pref of all winners - for stash in &elected_stashes { - let pref = Self::validators(stash); - >::insert(¤t_era, stash, pref); + (validator, exposure) + }) + .collect::)>>() + } + + /// TODO: + /// TODO: use minimum_validator_count() + pub fn process_election( + flat_supports: FlatSupportMap, + current_era: EraIndex, + ) -> Vec { + let exposures = Self::collect_exposure(flat_supports); + let elected_stashes = exposures + .iter() + .cloned() + .map(|(x, _)| x) + .collect::>(); + + // Populate Stakers and write slot stake. + let mut total_stake: BalanceOf = Zero::zero(); + exposures.into_iter().for_each(|(stash, exposure)| { + total_stake = total_stake.saturating_add(exposure.total); + >::insert(current_era, &stash, &exposure); + + let mut exposure_clipped = exposure; + let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize; + if exposure_clipped.others.len() > clipped_max_len { + exposure_clipped + .others + .sort_by(|a, b| a.value.cmp(&b.value).reverse()); + exposure_clipped.others.truncate(clipped_max_len); } + >::insert(¤t_era, &stash, exposure_clipped); + }); - // emit event - Self::deposit_event(RawEvent::StakingElection(compute)); - - log!( - info, - "💸 new validator set of size {:?} has been elected via {:?} for era {:?}", - elected_stashes.len(), - compute, - current_era, - ); + // Insert current era staking information + >::insert(¤t_era, total_stake); - Some(elected_stashes) - } else { - None + // collect the pref of all winners + for stash in &elected_stashes { + let pref = Self::validators(stash); + >::insert(¤t_era, stash, pref); } - } - - /// Select a new validator set from the assembled stakers and their role preferences. It tries - /// first to peek into [`QueuedElected`]. Otherwise, it runs a new on-chain phragmen election. - /// - /// If [`QueuedElected`] and [`QueuedScore`] exists, they are both removed. No further storage - /// is updated. - fn try_do_election() -> Option>> { - // an election result from either a stored submission or locally executed one. - let next_result = >::take().or_else(|| - Self::do_on_chain_phragmen() - ); - - // either way, kill this. We remove it here to make sure it always has the exact same - // lifetime as `QueuedElected`. - QueuedScore::kill(); - next_result - } + // emit event + Self::deposit_event(RawEvent::StakingElection); - /// Execute election and return the new results. The edge weights are processed into support - /// values. - /// - /// This is basically a wrapper around [`do_phragmen`] which translates - /// `PrimitiveElectionResult` into `ElectionResult`. - /// - /// No storage item is updated. - pub fn do_on_chain_phragmen() -> Option>> { - if let Some(phragmen_result) = Self::do_phragmen::(0) { - let elected_stashes = phragmen_result.winners.iter() - .map(|(s, _)| s.clone()) - .collect::>(); - let assignments = phragmen_result.assignments; - - let staked_assignments = sp_npos_elections::assignment_ratio_to_staked( - assignments, - Self::slashable_balance_of_fn(), - ); + log!( + info, + "💸 new validator set of size {:?} has been processed for era {:?}", + elected_stashes.len(), + current_era, + ); - let supports = build_support_map::( - &elected_stashes, - &staked_assignments, - ) - .map_err(|_| - log!( - error, - "💸 on-chain phragmen is failing due to a problem in the result. This must be a bug." - ) - ) - .ok()?; - - // collect exposures - let exposures = Self::collect_exposure(supports); - - // In order to keep the property required by `on_session_ending` that we must return the - // new validator set even if it's the same as the old, as long as any underlying - // economic conditions have changed, we don't attempt to do any optimization where we - // compare against the prior set. - Some(ElectionResult::> { - elected_stashes, - exposures, - compute: ElectionCompute::OnChain, - }) - } else { - // There were not enough candidates for even our minimal level of functionality. This is - // bad. We should probably disable all functionality except for block production and let - // the chain keep producing blocks until we can decide on a sufficiently substantial - // set. TODO: #2494 - None - } + elected_stashes } - /// Execute phragmen election and return the new results. No post-processing is applied and the - /// raw edge weights are returned. - /// - /// Self votes are added and nominations before the most recent slashing span are ignored. - /// - /// No storage item is updated. - pub fn do_phragmen(iterations: usize) - -> Option> - where ExtendedBalance: From> - { - let weight_of = Self::slashable_balance_of_fn(); - let mut all_nominators: Vec<(T::AccountId, VoteWeight, Vec)> = Vec::new(); - let mut all_validators = Vec::new(); - for (validator, _) in >::iter() { - // append self vote - let self_vote = (validator.clone(), weight_of(&validator), vec![validator.clone()]); - all_nominators.push(self_vote); - all_validators.push(validator); - } - - let nominator_votes = >::iter().map(|(nominator, nominations)| { - let Nominations { submitted_in, mut targets, suppressed: _ } = nominations; - - // Filter out nomination targets which were nominated before the most recent - // slashing span. - targets.retain(|stash| { - ::SlashingSpans::get(&stash).map_or( - true, - |spans| submitted_in >= spans.last_nonzero_slash(), - ) - }); - - (nominator, targets) - }); - all_nominators.extend(nominator_votes.map(|(n, ns)| { - let s = weight_of(&n); - (n, s, ns) - })); - - if all_validators.len() < Self::minimum_validator_count().max(1) as usize { - // If we don't have enough candidates, nothing to do. - log!(error, "💸 Chain does not have enough staking candidates to operate. Era {:?}.", Self::current_era()); - None - } else { - seq_phragmen::<_, Accuracy>( + /// TODO: + fn select_and_update_validators(current_era: EraIndex) -> Option> { + if T::ElectionProvider::NEEDS_ELECT_DATA { + // This election will need the real data. + T::ElectionProvider::elect::( Self::validator_count() as usize, - all_validators, - all_nominators, - Some((iterations, 0)), // exactly run `iterations` rounds. + Self::get_npos_targets(), + Self::get_npos_voters(), ) - .map_err(|err| log!(error, "Call to seq-phragmen failed due to {:?}", err)) + .map(|flat_supports| Self::process_election(flat_supports, current_era)) .ok() + } else { + // no need to fetch the params. + T::ElectionProvider::elect::(0, vec![], vec![]) + .map(|flat_supports| Self::process_election(flat_supports, current_era)) + .ok() } } - /// Consume a set of [`Supports`] from [`sp_npos_elections`] and collect them into a [`Exposure`] - fn collect_exposure( - supports: SupportMap, - ) -> Vec<(T::AccountId, Exposure>)> { - let total_issuance = T::Currency::total_issuance(); - let to_currency = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); - - supports.into_iter().map(|(validator, support)| { - // build `struct exposure` from `support` - let mut others = Vec::with_capacity(support.voters.len()); - let mut own: BalanceOf = Zero::zero(); - let mut total: BalanceOf = Zero::zero(); - support.voters - .into_iter() - .map(|(nominator, weight)| (nominator, to_currency(weight))) - .for_each(|(nominator, stake)| { - if nominator == validator { - own = own.saturating_add(stake); - } else { - others.push(IndividualExposure { who: nominator, value: stake }); - } - total = total.saturating_add(stake); - }); - - let exposure = Exposure { - own, - others, - total, - }; - - (validator, exposure) - }).collect::)>>() - } - /// Remove all associated data of a stash account from the staking system. /// /// Assumes storage is upgraded before calling. @@ -3083,21 +2352,58 @@ impl Module { } } - fn will_era_be_forced() -> bool { - match ForceEra::get() { - Forcing::ForceAlways | Forcing::ForceNew => true, - Forcing::ForceNone | Forcing::NotForcing => false, + /// Get all of the voters that are eligible for the npos election. + /// + /// This will inject all validators as well as a self-vote. + /// + /// Note that this is VERY expensive. Use with care. + /// TODO: + pub fn get_npos_voters() -> Vec<(T::AccountId, VoteWeight, Vec)> { + let weight_of = Self::slashable_balance_of_fn(); + let mut all_voters = Vec::new(); + + for (validator, _) in >::iter() { + // append self vote + let self_vote = ( + validator.clone(), + weight_of(&validator), + vec![validator.clone()], + ); + all_voters.push(self_vote); + } + + for (nominator, nominations) in >::iter() { + let Nominations { + submitted_in, + mut targets, + suppressed: _, + } = nominations; + + // Filter out nomination targets which were nominated before the most recent + // slashing span. + targets.retain(|stash| { + Self::slashing_spans(&stash) + .map_or(true, |spans| submitted_in >= spans.last_nonzero_slash()) + }); + + let vote_weight = weight_of(&nominator); + all_voters.push((nominator, vote_weight, targets)) } + + all_voters } - #[cfg(feature = "runtime-benchmarks")] - pub fn add_era_stakers(current_era: EraIndex, controller: T::AccountId, exposure: Exposure>) { - >::insert(¤t_era, &controller, &exposure); + pub fn get_npos_targets() -> Vec { + >::iter().map(|(v, _)| v).collect::>() } #[cfg(feature = "runtime-benchmarks")] - pub fn put_election_status(status: ElectionStatus::) { - >::put(status); + pub fn add_era_stakers( + current_era: EraIndex, + controller: T::AccountId, + exposure: Exposure>, + ) { + >::insert(¤t_era, &controller, &exposure); } #[cfg(feature = "runtime-benchmarks")] @@ -3106,6 +2412,36 @@ impl Module { } } +impl ElectionDataProvider + for Module +{ + type CompactSolution = CompactU16Solution; + + fn desired_targets() -> u32 { + Self::validator_count() + } + + fn next_election_prediction(now: T::BlockNumber) -> T::BlockNumber { + T::NextNewSession::estimate_next_new_session(now).unwrap_or_default() + } + + fn voters() -> Vec<(T::AccountId, VoteWeight, Vec)> { + Self::get_npos_voters() + } + + fn targets() -> Vec { + Self::get_npos_targets() + } + + fn feasibility_check_assignment( + who: &T::AccountId, + distribution: &[(T::AccountId, P)], + ) -> bool { + // TODO + true + } +} + /// In this implementation `new_session(session)` must be called before `end_session(session-1)` /// i.e. the new session must be planned before the ending of the previous session. /// @@ -3195,9 +2531,10 @@ impl Convert> } /// This is intended to be used with `FilterHistoricalOffences`. -impl +impl OnOffenceHandler, Weight> -for Module where + for Module +where T: pallet_session::Trait::AccountId>, T: pallet_session::historical::Trait< FullIdentification = Exposure<::AccountId, BalanceOf>, @@ -3327,7 +2664,8 @@ for Module where } fn can_report() -> bool { - Self::era_election_status().is_closed() + // TODO: now we can get rid of this API, remove it. + true } } @@ -3337,7 +2675,8 @@ pub struct FilterHistoricalOffences { } impl ReportOffence - for FilterHistoricalOffences, R> where + for FilterHistoricalOffences, R> +where T: Trait, R: ReportOffence, O: Offence, @@ -3362,100 +2701,7 @@ impl ReportOffence } } -#[allow(deprecated)] -impl frame_support::unsigned::ValidateUnsigned for Module { - type Call = Call; - fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { - if let Call::submit_election_solution_unsigned( - _, - _, - score, - era, - _, - ) = call { - use offchain_election::DEFAULT_LONGEVITY; - - // discard solution not coming from the local OCW. - match source { - TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } - _ => { - log!(debug, "rejecting unsigned transaction because it is not local/in-block."); - return InvalidTransaction::Call.into(); - } - } - - if let Err(error_with_post_info) = Self::pre_dispatch_checks(*score, *era) { - let invalid = to_invalid(error_with_post_info); - log!( - debug, - "💸 validate unsigned pre dispatch checks failed due to error #{:?}.", - invalid, - ); - return invalid.into(); - } - - log!(debug, "💸 validateUnsigned succeeded for a solution at era {}.", era); - - ValidTransaction::with_tag_prefix("StakingOffchain") - // The higher the score[0], the better a solution is. - .priority(T::UnsignedPriority::get().saturating_add(score[0].saturated_into())) - // Defensive only. A single solution can exist in the pool per era. Each validator - // will run OCW at most once per era, hence there should never exist more than one - // transaction anyhow. - .and_provides(era) - // Note: this can be more accurate in the future. We do something like - // `era_end_block - current_block` but that is not needed now as we eagerly run - // offchain workers now and the above should be same as `T::ElectionLookahead` - // without the need to query more storage in the validation phase. If we randomize - // offchain worker, then we might re-consider this. - .longevity(TryInto::::try_into( - T::ElectionLookahead::get()).unwrap_or(DEFAULT_LONGEVITY) - ) - // We don't propagate this. This can never the validated at a remote node. - .propagate(false) - .build() - } else { - InvalidTransaction::Call.into() - } - } - - fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { - if let Call::submit_election_solution_unsigned( - _, - _, - score, - era, - _, - ) = call { - // IMPORTANT NOTE: These checks are performed in the dispatch call itself, yet we need - // to duplicate them here to prevent a block producer from putting a previously - // validated, yet no longer valid solution on chain. - // OPTIMISATION NOTE: we could skip this in the `submit_election_solution_unsigned` - // since we already do it here. The signed version needs it though. Yer for now we keep - // this duplicate check here so both signed and unsigned can use a singular - // `check_and_replace_solution`. - Self::pre_dispatch_checks(*score, *era) - .map(|_| ()) - .map_err(to_invalid) - .map_err(Into::into) - } else { - Err(InvalidTransaction::Call.into()) - } - } -} - /// Check that list is sorted and has no duplicates. fn is_sorted_and_unique(list: &[u32]) -> bool { list.windows(2).all(|w| w[0] < w[1]) } - -/// convert a DispatchErrorWithPostInfo to a custom InvalidTransaction with the inner code being the -/// error number. -fn to_invalid(error_with_post_info: DispatchErrorWithPostInfo) -> InvalidTransaction { - let error = error_with_post_info.error; - let error_number = match error { - DispatchError::Module { error, ..} => error, - _ => 0, - }; - InvalidTransaction::Custom(error_number) -} diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 055ebb9730805..b17e1d7a4f010 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -314,13 +314,8 @@ impl Trait for Test { type SessionInterface = Self; type RewardCurve = RewardCurve; type NextNewSession = Session; - type ElectionLookahead = ElectionLookahead; - type Call = Call; - type MaxIterations = MaxIterations; - type MinSolutionScoreBump = MinSolutionScoreBump; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; - type UnsignedPriority = UnsignedPriority; - type OffchainSolutionWeightLimit = OffchainSolutionWeightLimit; + type ElectionProvider = frame_election_providers::onchain::OnChainSequentialPhragmen; type WeightInfo = (); } @@ -777,201 +772,203 @@ pub(crate) fn add_slash(who: &AccountId) { ); } -// winners will be chosen by simply their unweighted total backing stake. Nominator stake is -// distributed evenly. -pub(crate) fn horrible_npos_solution( - do_reduce: bool, -) -> (CompactAssignments, Vec, ElectionScore) { - let mut backing_stake_of: BTreeMap = BTreeMap::new(); - - // self stake - >::iter().for_each(|(who, _p)| { - *backing_stake_of.entry(who).or_insert(Zero::zero()) += Staking::slashable_balance_of(&who) - }); - - // add nominator stuff - >::iter().for_each(|(who, nomination)| { - nomination.targets.iter().for_each(|v| { - *backing_stake_of.entry(*v).or_insert(Zero::zero()) += - Staking::slashable_balance_of(&who) - }) - }); - - // elect winners - let mut sorted: Vec = backing_stake_of.keys().cloned().collect(); - sorted.sort_by_key(|x| backing_stake_of.get(x).unwrap()); - let winners: Vec = sorted - .iter() - .cloned() - .take(Staking::validator_count() as usize) - .collect(); - - // create assignments - let mut staked_assignment: Vec> = Vec::new(); - >::iter().for_each(|(who, nomination)| { - let mut dist: Vec<(AccountId, ExtendedBalance)> = Vec::new(); - nomination.targets.iter().for_each(|v| { - if winners.iter().find(|w| *w == v).is_some() { - dist.push((*v, ExtendedBalance::zero())); - } - }); - - if dist.len() == 0 { - return; - } - - // assign real stakes. just split the stake. - let stake = Staking::slashable_balance_of(&who) as ExtendedBalance; - let mut sum: ExtendedBalance = Zero::zero(); - let dist_len = dist.len(); - { - dist.iter_mut().for_each(|(_, w)| { - let partial = stake / (dist_len as ExtendedBalance); - *w = partial; - sum += partial; - }); - } - - // assign the leftover to last. - { - let leftover = stake - sum; - let last = dist.last_mut().unwrap(); - last.1 += leftover; - } - - staked_assignment.push(StakedAssignment { - who, - distribution: dist, - }); - }); - - // Ensure that this result is worse than seq-phragmen. Otherwise, it should not have been used - // for testing. - let score = { - let (_, _, better_score) = prepare_submission_with(true, true, 0, |_| {}); - - let support = build_support_map::(&winners, &staked_assignment).unwrap(); - let score = evaluate_support(&support); - - assert!(sp_npos_elections::is_score_better::( - better_score, - score, - MinSolutionScoreBump::get(), - )); - - score - }; - - if do_reduce { - reduce(&mut staked_assignment); - } - - let snapshot_validators = Staking::snapshot_validators().unwrap(); - let snapshot_nominators = Staking::snapshot_nominators().unwrap(); - let nominator_index = |a: &AccountId| -> Option { - snapshot_nominators.iter().position(|x| x == a).map(|i| i as NominatorIndex) - }; - let validator_index = |a: &AccountId| -> Option { - snapshot_validators.iter().position(|x| x == a).map(|i| i as ValidatorIndex) - }; - - // convert back to ratio assignment. This takes less space. - let assignments_reduced = - sp_npos_elections::assignment_staked_to_ratio::(staked_assignment); - - let compact = - CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index) - .unwrap(); - - // winner ids to index - let winners = winners.into_iter().map(|w| validator_index(&w).unwrap()).collect::>(); - - (compact, winners, score) -} - -/// Note: this should always logically reproduce [`offchain_election::prepare_submission`], yet we -/// cannot do it since we want to have `tweak` injected into the process. -/// -/// If the input is being tweaked in a way that the score cannot be compute accurately, -/// `compute_real_score` can be set to true. In this case a `Default` score is returned. -pub(crate) fn prepare_submission_with( - compute_real_score: bool, - do_reduce: bool, - iterations: usize, - tweak: impl FnOnce(&mut Vec>), -) -> (CompactAssignments, Vec, ElectionScore) { - // run election on the default stuff. - let sp_npos_elections::ElectionResult { - winners, - assignments, - } = Staking::do_phragmen::(iterations).unwrap(); - let winners = sp_npos_elections::to_without_backing(winners); - - let mut staked = sp_npos_elections::assignment_ratio_to_staked( - assignments, - Staking::slashable_balance_of_fn(), - ); - - // apply custom tweaks. awesome for testing. - tweak(&mut staked); - - if do_reduce { - reduce(&mut staked); - } - - // convert back to ratio assignment. This takes less space. - let snapshot_validators = Staking::snapshot_validators().expect("snapshot not created."); - let snapshot_nominators = Staking::snapshot_nominators().expect("snapshot not created."); - let nominator_index = |a: &AccountId| -> Option { - snapshot_nominators - .iter() - .position(|x| x == a) - .map_or_else( - || { println!("unable to find nominator index for {:?}", a); None }, - |i| Some(i as NominatorIndex), - ) - }; - let validator_index = |a: &AccountId| -> Option { - snapshot_validators - .iter() - .position(|x| x == a) - .map_or_else( - || { println!("unable to find validator index for {:?}", a); None }, - |i| Some(i as ValidatorIndex), - ) - }; - - let assignments_reduced = sp_npos_elections::assignment_staked_to_ratio(staked); - - // re-compute score by converting, yet again, into staked type - let score = if compute_real_score { - let staked = sp_npos_elections::assignment_ratio_to_staked( - assignments_reduced.clone(), - Staking::slashable_balance_of_fn(), - ); - - let support_map = build_support_map::( - winners.as_slice(), - staked.as_slice(), - ).unwrap(); - evaluate_support::(&support_map) - } else { - Default::default() - }; - - let compact = - CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index) - .expect("Failed to create compact"); - - // winner ids to index - let winners = winners.into_iter().map(|w| validator_index(&w).unwrap()).collect::>(); - - (compact, winners, score) -} +// // winners will be chosen by simply their unweighted total backing stake. Nominator stake is +// // distributed evenly. +// pub(crate) fn horrible_npos_solution( +// do_reduce: bool, +// ) -> (CompactAssignments, Vec, ElectionScore) { +// let mut backing_stake_of: BTreeMap = BTreeMap::new(); + +// // self stake +// >::iter().for_each(|(who, _p)| { +// *backing_stake_of.entry(who).or_insert(Zero::zero()) += Staking::slashable_balance_of(&who) +// }); + +// // add nominator stuff +// >::iter().for_each(|(who, nomination)| { +// nomination.targets.iter().for_each(|v| { +// *backing_stake_of.entry(*v).or_insert(Zero::zero()) += +// Staking::slashable_balance_of(&who) +// }) +// }); + +// // elect winners +// let mut sorted: Vec = backing_stake_of.keys().cloned().collect(); +// sorted.sort_by_key(|x| backing_stake_of.get(x).unwrap()); +// let winners: Vec = sorted +// .iter() +// .cloned() +// .take(Staking::validator_count() as usize) +// .collect(); + +// // create assignments +// let mut staked_assignment: Vec> = Vec::new(); +// >::iter().for_each(|(who, nomination)| { +// let mut dist: Vec<(AccountId, ExtendedBalance)> = Vec::new(); +// nomination.targets.iter().for_each(|v| { +// if winners.iter().find(|w| *w == v).is_some() { +// dist.push((*v, ExtendedBalance::zero())); +// } +// }); + +// if dist.len() == 0 { +// return; +// } + +// // assign real stakes. just split the stake. +// let stake = Staking::slashable_balance_of(&who) as ExtendedBalance; +// let mut sum: ExtendedBalance = Zero::zero(); +// let dist_len = dist.len(); +// { +// dist.iter_mut().for_each(|(_, w)| { +// let partial = stake / (dist_len as ExtendedBalance); +// *w = partial; +// sum += partial; +// }); +// } + +// // assign the leftover to last. +// { +// let leftover = stake - sum; +// let last = dist.last_mut().unwrap(); +// last.1 += leftover; +// } + +// staked_assignment.push(StakedAssignment { +// who, +// distribution: dist, +// }); +// }); + +// // Ensure that this result is worse than seq-phragmen. Otherwise, it should not have been used +// // for testing. +// let score = { +// let (_, _, better_score) = prepare_submission_with(true, true, 0, |_| {}); + +// let support = build_support_map::(&winners, &staked_assignment).unwrap(); +// let score = evaluate_support(&support); + +// assert!(sp_npos_elections::is_score_better::( +// better_score, +// score, +// MinSolutionScoreBump::get(), +// )); + +// score +// }; + +// if do_reduce { +// reduce(&mut staked_assignment); +// } + +// let snapshot_validators = Staking::snapshot_validators().unwrap(); +// let snapshot_nominators = Staking::snapshot_nominators().unwrap(); +// let nominator_index = |a: &AccountId| -> Option { +// snapshot_nominators.iter().position(|x| x == a).map(|i| i as NominatorIndex) +// }; +// let validator_index = |a: &AccountId| -> Option { +// snapshot_validators.iter().position(|x| x == a).map(|i| i as ValidatorIndex) +// }; + +// // convert back to ratio assignment. This takes less space. +// let assignments_reduced = +// sp_npos_elections::assignment_staked_to_ratio::(staked_assignment); + +// let compact = +// CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index) +// .unwrap(); + +// // winner ids to index +// let winners = winners.into_iter().map(|w| validator_index(&w).unwrap()).collect::>(); + +// (compact, winners, score) +// } + +// /// Note: this should always logically reproduce [`offchain_election::prepare_submission`], yet we +// /// cannot do it since we want to have `tweak` injected into the process. +// /// +// /// If the input is being tweaked in a way that the score cannot be compute accurately, +// /// `compute_real_score` can be set to true. In this case a `Default` score is returned. +// pub(crate) fn prepare_submission_with( +// compute_real_score: bool, +// do_reduce: bool, +// iterations: usize, +// tweak: impl FnOnce(&mut Vec>), +// ) -> (CompactAssignments, Vec, ElectionScore) { +// // run election on the default stuff. +// let sp_npos_elections::ElectionResult { +// winners, +// assignments, +// } = Staking::do_phragmen::(iterations).unwrap(); +// let winners = sp_npos_elections::to_without_backing(winners); + +// let mut staked = sp_npos_elections::assignment_ratio_to_staked( +// assignments, +// Staking::slashable_balance_of_fn(), +// ); + +// // apply custom tweaks. awesome for testing. +// tweak(&mut staked); + +// if do_reduce { +// reduce(&mut staked); +// } + +// // convert back to ratio assignment. This takes less space. +// let snapshot_validators = Staking::snapshot_validators().expect("snapshot not created."); +// let snapshot_nominators = Staking::snapshot_nominators().expect("snapshot not created."); +// let nominator_index = |a: &AccountId| -> Option { +// snapshot_nominators +// .iter() +// .position(|x| x == a) +// .map_or_else( +// || { println!("unable to find nominator index for {:?}", a); None }, +// |i| Some(i as NominatorIndex), +// ) +// }; +// let validator_index = |a: &AccountId| -> Option { +// snapshot_validators +// .iter() +// .position(|x| x == a) +// .map_or_else( +// || { println!("unable to find validator index for {:?}", a); None }, +// |i| Some(i as ValidatorIndex), +// ) +// }; + +// let assignments_reduced = sp_npos_elections::assignment_staked_to_ratio(staked); + +// // re-compute score by converting, yet again, into staked type +// let score = if compute_real_score { +// let staked = sp_npos_elections::assignment_ratio_to_staked( +// assignments_reduced.clone(), +// Staking::slashable_balance_of_fn(), +// ); + +// let support_map = build_support_map::( +// winners.as_slice(), +// staked.as_slice(), +// ).unwrap(); +// evaluate_support::(&support_map) +// } else { +// Default::default() +// }; + +// let compact = +// CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index) +// .expect("Failed to create compact"); + +// // winner ids to index +// let winners = winners.into_iter().map(|w| validator_index(&w).unwrap()).collect::>(); + +// (compact, winners, score) +// } /// Make all validator and nominator request their payment pub(crate) fn make_all_reward_payment(era: EraIndex) { - let validators_with_reward = ErasRewardPoints::::get(era).individual.keys() + let validators_with_reward = ErasRewardPoints::::get(era) + .individual + .keys() .cloned() .collect::>(); diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 57ad95bcf586f..0e8747dc90b59 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -160,185 +160,185 @@ pub fn create_validators_with_nominators_for_era( } -/// Build a _really bad_ but acceptable solution for election. This should always yield a solution -/// which has a less score than the seq-phragmen. -pub fn get_weak_solution( - do_reduce: bool, -) -> (Vec, CompactAssignments, ElectionScore, ElectionSize) { - let mut backing_stake_of: BTreeMap> = BTreeMap::new(); - - // self stake - >::iter().for_each(|(who, _p)| { - *backing_stake_of.entry(who.clone()).or_insert_with(|| Zero::zero()) += - >::slashable_balance_of(&who) - }); - - // elect winners. We chose the.. least backed ones. - let mut sorted: Vec = backing_stake_of.keys().cloned().collect(); - sorted.sort_by_key(|x| backing_stake_of.get(x).unwrap()); - let winners: Vec = sorted - .iter() - .rev() - .cloned() - .take(>::validator_count() as usize) - .collect(); - - let mut staked_assignments: Vec> = Vec::new(); - // you could at this point start adding some of the nominator's stake, but for now we don't. - // This solution must be bad. - - // add self support to winners. - winners.iter().for_each(|w| { - staked_assignments.push(StakedAssignment { - who: w.clone(), - distribution: vec![( - w.clone(), - >::slashable_balance_of_vote_weight( - &w, - T::Currency::total_issuance(), - ).into(), - )], - }) - }); - - if do_reduce { - reduce(&mut staked_assignments); - } - - // helpers for building the compact - let snapshot_validators = >::snapshot_validators().unwrap(); - let snapshot_nominators = >::snapshot_nominators().unwrap(); - - let nominator_index = |a: &T::AccountId| -> Option { - snapshot_nominators - .iter() - .position(|x| x == a) - .and_then(|i| >::try_into(i).ok()) - }; - let validator_index = |a: &T::AccountId| -> Option { - snapshot_validators - .iter() - .position(|x| x == a) - .and_then(|i| >::try_into(i).ok()) - }; - - // convert back to ratio assignment. This takes less space. - let low_accuracy_assignment = assignment_staked_to_ratio_normalized(staked_assignments) - .expect("Failed to normalize"); - - // re-calculate score based on what the chain will decode. - let score = { - let staked = assignment_ratio_to_staked::<_, OffchainAccuracy, _>( - low_accuracy_assignment.clone(), - >::slashable_balance_of_fn(), - ); - - let support_map = build_support_map::( - winners.as_slice(), - staked.as_slice(), - ).unwrap(); - evaluate_support::(&support_map) - }; - - // compact encode the assignment. - let compact = CompactAssignments::from_assignment( - low_accuracy_assignment, - nominator_index, - validator_index, - ) - .unwrap(); - - // winners to index. - let winners = winners - .into_iter() - .map(|w| { - snapshot_validators - .iter() - .position(|v| *v == w) - .unwrap() - .try_into() - .unwrap() - }) - .collect::>(); - - let size = ElectionSize { - validators: snapshot_validators.len() as ValidatorIndex, - nominators: snapshot_nominators.len() as NominatorIndex, - }; - - (winners, compact, score, size) -} - -/// Create a solution for seq-phragmen. This uses the same internal function as used by the offchain -/// worker code. -pub fn get_seq_phragmen_solution( - do_reduce: bool, -) -> ( - Vec, - CompactAssignments, - ElectionScore, - ElectionSize, -) { - let iters = offchain_election::get_balancing_iters::(); - - let sp_npos_elections::ElectionResult { - winners, - assignments, - } = >::do_phragmen::(iters).unwrap(); - - offchain_election::prepare_submission::( - assignments, - winners, - do_reduce, - T::MaximumBlockWeight::get(), - ) - .unwrap() -} - -/// Returns a solution in which only one winner is elected with just a self vote. -pub fn get_single_winner_solution( - winner: T::AccountId, -) -> Result< - ( - Vec, - CompactAssignments, - ElectionScore, - ElectionSize, - ), - &'static str, -> { - let snapshot_validators = >::snapshot_validators().unwrap(); - let snapshot_nominators = >::snapshot_nominators().unwrap(); - - let val_index = snapshot_validators - .iter() - .position(|x| *x == winner) - .ok_or("not a validator")?; - let nom_index = snapshot_nominators - .iter() - .position(|x| *x == winner) - .ok_or("not a nominator")?; - - let stake = >::slashable_balance_of(&winner); - let stake = - ::to_vote(stake, T::Currency::total_issuance()) as ExtendedBalance; - - let val_index = val_index as ValidatorIndex; - let nom_index = nom_index as NominatorIndex; - - let winners = vec![val_index]; - let compact = CompactAssignments { - votes1: vec![(nom_index, val_index)], - ..Default::default() - }; - let score = [stake, stake, stake * stake]; - let size = ElectionSize { - validators: snapshot_validators.len() as ValidatorIndex, - nominators: snapshot_nominators.len() as NominatorIndex, - }; - - Ok((winners, compact, score, size)) -} +// /// Build a _really bad_ but acceptable solution for election. This should always yield a solution +// /// which has a less score than the seq-phragmen. +// pub fn get_weak_solution( +// do_reduce: bool, +// ) -> (Vec, CompactAssignments, ElectionScore, ElectionSize) { +// let mut backing_stake_of: BTreeMap> = BTreeMap::new(); + +// // self stake +// >::iter().for_each(|(who, _p)| { +// *backing_stake_of.entry(who.clone()).or_insert_with(|| Zero::zero()) += +// >::slashable_balance_of(&who) +// }); + +// // elect winners. We chose the.. least backed ones. +// let mut sorted: Vec = backing_stake_of.keys().cloned().collect(); +// sorted.sort_by_key(|x| backing_stake_of.get(x).unwrap()); +// let winners: Vec = sorted +// .iter() +// .rev() +// .cloned() +// .take(>::validator_count() as usize) +// .collect(); + +// let mut staked_assignments: Vec> = Vec::new(); +// // you could at this point start adding some of the nominator's stake, but for now we don't. +// // This solution must be bad. + +// // add self support to winners. +// winners.iter().for_each(|w| { +// staked_assignments.push(StakedAssignment { +// who: w.clone(), +// distribution: vec![( +// w.clone(), +// >::slashable_balance_of_vote_weight( +// &w, +// T::Currency::total_issuance(), +// ).into(), +// )], +// }) +// }); + +// if do_reduce { +// reduce(&mut staked_assignments); +// } + +// // helpers for building the compact +// let snapshot_validators = >::snapshot_validators().unwrap(); +// let snapshot_nominators = >::snapshot_nominators().unwrap(); + +// let nominator_index = |a: &T::AccountId| -> Option { +// snapshot_nominators +// .iter() +// .position(|x| x == a) +// .and_then(|i| >::try_into(i).ok()) +// }; +// let validator_index = |a: &T::AccountId| -> Option { +// snapshot_validators +// .iter() +// .position(|x| x == a) +// .and_then(|i| >::try_into(i).ok()) +// }; + +// // convert back to ratio assignment. This takes less space. +// let low_accuracy_assignment = assignment_staked_to_ratio_normalized(staked_assignments) +// .expect("Failed to normalize"); + +// // re-calculate score based on what the chain will decode. +// let score = { +// let staked = assignment_ratio_to_staked::<_, OffchainAccuracy, _>( +// low_accuracy_assignment.clone(), +// >::slashable_balance_of_fn(), +// ); + +// let support_map = build_support_map::( +// winners.as_slice(), +// staked.as_slice(), +// ).unwrap(); +// evaluate_support::(&support_map) +// }; + +// // compact encode the assignment. +// let compact = CompactAssignments::from_assignment( +// low_accuracy_assignment, +// nominator_index, +// validator_index, +// ) +// .unwrap(); + +// // winners to index. +// let winners = winners +// .into_iter() +// .map(|w| { +// snapshot_validators +// .iter() +// .position(|v| *v == w) +// .unwrap() +// .try_into() +// .unwrap() +// }) +// .collect::>(); + +// let size = ElectionSize { +// validators: snapshot_validators.len() as ValidatorIndex, +// nominators: snapshot_nominators.len() as NominatorIndex, +// }; + +// (winners, compact, score, size) +// } + +// /// Create a solution for seq-phragmen. This uses the same internal function as used by the offchain +// /// worker code. +// pub fn get_seq_phragmen_solution( +// do_reduce: bool, +// ) -> ( +// Vec, +// CompactAssignments, +// ElectionScore, +// ElectionSize, +// ) { +// let iters = offchain_election::get_balancing_iters::(); + +// let sp_npos_elections::ElectionResult { +// winners, +// assignments, +// } = >::do_phragmen::(iters).unwrap(); + +// offchain_election::prepare_submission::( +// assignments, +// winners, +// do_reduce, +// T::MaximumBlockWeight::get(), +// ) +// .unwrap() +// } + +// /// Returns a solution in which only one winner is elected with just a self vote. +// pub fn get_single_winner_solution( +// winner: T::AccountId, +// ) -> Result< +// ( +// Vec, +// CompactAssignments, +// ElectionScore, +// ElectionSize, +// ), +// &'static str, +// > { +// let snapshot_validators = >::snapshot_validators().unwrap(); +// let snapshot_nominators = >::snapshot_nominators().unwrap(); + +// let val_index = snapshot_validators +// .iter() +// .position(|x| *x == winner) +// .ok_or("not a validator")?; +// let nom_index = snapshot_nominators +// .iter() +// .position(|x| *x == winner) +// .ok_or("not a nominator")?; + +// let stake = >::slashable_balance_of(&winner); +// let stake = +// ::to_vote(stake, T::Currency::total_issuance()) as ExtendedBalance; + +// let val_index = val_index as ValidatorIndex; +// let nom_index = nom_index as NominatorIndex; + +// let winners = vec![val_index]; +// let compact = CompactAssignments { +// votes1: vec![(nom_index, val_index)], +// ..Default::default() +// }; +// let score = [stake, stake, stake * stake]; +// let size = ElectionSize { +// validators: snapshot_validators.len() as ValidatorIndex, +// nominators: snapshot_nominators.len() as NominatorIndex, +// }; + +// Ok((winners, compact, score, size)) +// } /// get the active era. pub fn current_era() -> EraIndex { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 2a02d87aa2c57..8e72d17669b3c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1748,16 +1748,19 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election() { assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31])); - // winners should be 21 and 31. Otherwise this election is taking duplicates into account. - let sp_npos_elections::ElectionResult { - winners, - assignments, - } = Staking::do_phragmen::(0).unwrap(); - let winners = sp_npos_elections::to_without_backing(winners); - + // winners should be 21 and 31. Otherwise this election is taking duplicates into + // account. + let election_result = ::ElectionProvider::elect::( + Staking::validator_count() as usize, + Staking::get_npos_targets(), + Staking::get_npos_voters(), + ).unwrap(); + + let winners = election_result.iter().map(|(x, _)| x).cloned().collect::>(); assert_eq!(winners, vec![31, 21]); // only distribution to 21 and 31. - assert_eq!(assignments.iter().find(|a| a.who == 1).unwrap().distribution.len(), 2); + // TODO: + // assert_eq!(assignments.iter().find(|a| a.who == 1).unwrap().distribution.len(), 2); }); } @@ -1796,16 +1799,17 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election_elected() { assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31])); // winners should be 21 and 31. Otherwise this election is taking duplicates into account. + let election_result = ::ElectionProvider::elect::( + Staking::validator_count() as usize, + Staking::get_npos_targets(), + Staking::get_npos_voters(), + ).unwrap(); - let sp_npos_elections::ElectionResult { - winners, - assignments, - } = Staking::do_phragmen::(0).unwrap(); - - let winners = sp_npos_elections::to_without_backing(winners); + let winners = election_result.iter().map(|(x, _)| x).cloned().collect::>(); assert_eq!(winners, vec![21, 11]); // only distribution to 21 and 31. - assert_eq!(assignments.iter().find(|a| a.who == 1).unwrap().distribution.len(), 2); + // TODO: + // assert_eq!(assignments.iter().find(|a| a.who == 1).unwrap().distribution.len(), 2); }); } @@ -2809,1294 +2813,1294 @@ fn remove_multi_deferred() { }) } -mod offchain_election { - use crate::*; - use codec::Encode; - use frame_support::{ - assert_noop, assert_ok, assert_err_with_weight, - dispatch::DispatchResultWithPostInfo, - }; - use sp_runtime::transaction_validity::TransactionSource; - use mock::*; - use parking_lot::RwLock; - use sp_core::offchain::{ - testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, - OffchainExt, TransactionPoolExt, - }; - use sp_io::TestExternalities; - use sp_npos_elections::StakedAssignment; - use frame_support::traits::OffchainWorker; - use std::sync::Arc; - use substrate_test_utils::assert_eq_uvec; - - fn percent(x: u16) -> OffchainAccuracy { - OffchainAccuracy::from_percent(x) - } - - /// setup a new set of validators and nominator storage items independent of the parent mock - /// file. This produces a edge graph that can be reduced. - pub fn build_offchain_election_test_ext() { - for i in (10..=40).step_by(10) { - // Note: we respect the convention of the mock (10, 11 pairs etc.) since these accounts - // have corresponding keys in session which makes everything more ergonomic and - // realistic. - bond_validator(i + 1, i, 100); - } - - let mut voter = 1; - bond_nominator(voter, 1000 + voter, 100, vec![11]); - voter = 2; - bond_nominator(voter, 1000 + voter, 100, vec![11, 11]); - voter = 3; - bond_nominator(voter, 1000 + voter, 100, vec![21, 41]); - voter = 4; - bond_nominator(voter, 1000 + voter, 100, vec![21, 31, 41]); - voter = 5; - bond_nominator(voter, 1000 + voter, 100, vec![21, 31, 41]); - } - - /// convert an externalities to one that can handle offchain worker tests. - fn offchainify(ext: &mut TestExternalities, iterations: u32) -> Arc> { - let (offchain, offchain_state) = TestOffchainExt::new(); - let (pool, pool_state) = TestTransactionPoolExt::new(); - - let mut seed = [0_u8; 32]; - seed[0..4].copy_from_slice(&iterations.to_le_bytes()); - offchain_state.write().seed = seed; - - ext.register_extension(OffchainExt::new(offchain)); - ext.register_extension(TransactionPoolExt::new(pool)); - - pool_state - } - - fn election_size() -> ElectionSize { - ElectionSize { - validators: Staking::snapshot_validators().unwrap().len() as ValidatorIndex, - nominators: Staking::snapshot_nominators().unwrap().len() as NominatorIndex, - } - } - - fn submit_solution( - origin: Origin, - winners: Vec, - compact: CompactAssignments, - score: ElectionScore, - ) -> DispatchResultWithPostInfo { - Staking::submit_election_solution( - origin, - winners, - compact, - score, - current_era(), - election_size(), - ) - } - - #[test] - fn is_current_session_final_works() { - ExtBuilder::default() - .session_per_era(3) - .build() - .execute_with(|| { - mock::start_era(1); - assert_eq!(Session::current_index(), 3); - assert_eq!(Staking::current_era(), Some(1)); - assert_eq!(Staking::is_current_session_final(), false); - - start_session(4); - assert_eq!(Session::current_index(), 4); - assert_eq!(Staking::current_era(), Some(1)); - assert_eq!(Staking::is_current_session_final(), true); - - start_session(5); - assert_eq!(Session::current_index(), 5); - // era changed. - assert_eq!(Staking::current_era(), Some(2)); - assert_eq!(Staking::is_current_session_final(), false); - }) - } - - #[test] - fn offchain_window_is_triggered() { - ExtBuilder::default() - .session_per_era(5) - .session_length(10) - .election_lookahead(3) - .build() - .execute_with(|| { - run_to_block(7); - assert_session_era!(0, 0); - - run_to_block(10); - assert_session_era!(1, 0); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert!(Staking::snapshot_nominators().is_none()); - assert!(Staking::snapshot_validators().is_none()); - - run_to_block(36); - assert_session_era!(3, 0); - - // fist era has session 0, which has 0 blocks length, so we have in total 40 blocks - // in the era. - run_to_block(37); - assert_session_era!(3, 0); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); - assert!(Staking::snapshot_nominators().is_some()); - assert!(Staking::snapshot_validators().is_some()); - - run_to_block(38); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); - - run_to_block(39); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); - - run_to_block(40); - assert_session_era!(4, 0); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert!(Staking::snapshot_nominators().is_none()); - assert!(Staking::snapshot_validators().is_none()); - - run_to_block(86); - assert_session_era!(8, 1); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert!(Staking::snapshot_nominators().is_none()); - assert!(Staking::snapshot_validators().is_none()); - - // second era onwards has 50 blocks per era. - run_to_block(87); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(87)); - assert!(Staking::snapshot_nominators().is_some()); - assert!(Staking::snapshot_validators().is_some()); - - run_to_block(90); - assert_session_era!(9, 1); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert!(Staking::snapshot_nominators().is_none()); - assert!(Staking::snapshot_validators().is_none()); - }) - } - - #[test] - fn offchain_window_is_triggered_when_forcing() { - ExtBuilder::default() - .session_per_era(5) - .session_length(10) - .election_lookahead(3) - .build() - .execute_with(|| { - run_to_block(12); - ForceEra::put(Forcing::ForceNew); - run_to_block(13); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - run_to_block(17); // instead of 47 - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(17)); - - run_to_block(20); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - }) - } - - #[test] - fn offchain_window_is_triggered_when_force_always() { - ExtBuilder::default() - .session_per_era(5) - .session_length(10) - .election_lookahead(3) - .build() - .execute_with(|| { - - ForceEra::put(Forcing::ForceAlways); - run_to_block(16); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - run_to_block(17); // instead of 37 - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(17)); - - run_to_block(20); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - run_to_block(26); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - run_to_block(27); // next one again - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(27)); - }) - } - - #[test] - fn offchain_window_closes_when_forcenone() { - ExtBuilder::default() - .session_per_era(5) - .session_length(10) - .election_lookahead(3) - .build() - .execute_with(|| { - ForceEra::put(Forcing::ForceNone); - - run_to_block(36); - assert_session_era!(3, 0); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - // opens - run_to_block(37); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); - assert!(Staking::is_current_session_final()); - assert!(Staking::snapshot_validators().is_some()); - - // closes normally - run_to_block(40); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert!(!Staking::is_current_session_final()); - assert!(Staking::snapshot_validators().is_none()); - assert_session_era!(4, 0); - - run_to_block(47); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert_session_era!(4, 0); - - run_to_block(57); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert_session_era!(5, 0); - - run_to_block(67); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - // Will not open again as scheduled - run_to_block(87); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert_session_era!(8, 0); - - run_to_block(90); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert_session_era!(9, 0); - }) - } - - #[test] - fn offchain_window_on_chain_fallback_works() { - ExtBuilder::default().build_and_execute(|| { - start_session(1); - start_session(2); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - // some election must have happened by now. - assert_eq!( - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| { - if let MetaEvent::staking(inner) = e { - Some(inner) - } else { - None - } - }) - .last() - .unwrap(), - RawEvent::StakingElection(ElectionCompute::OnChain), - ); - }) - } - - #[test] - #[ignore] - fn offchain_wont_work_if_snapshot_fails() { - ExtBuilder::default() - .offchain_election_ext() - .build() - .execute_with(|| { - run_to_block(12); - assert!(Staking::snapshot_validators().is_some()); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); - - // validate more than the limit - let limit: NominatorIndex = ValidatorIndex::max_value() as NominatorIndex + 1; - let ctrl = 1_000_000; - for i in 0..limit { - bond_validator((1000 + i).into(), (1000 + i + ctrl).into(), 100); - } - - // window stays closed since no snapshot was taken. - run_to_block(27); - assert!(Staking::snapshot_validators().is_none()); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - }) - } - - #[test] - fn staking_is_locked_when_election_window_open() { - ExtBuilder::default() - .offchain_election_ext() - .election_lookahead(3) - .build() - .execute_with(|| { - run_to_block(12); - assert!(Staking::snapshot_validators().is_some()); - // given - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); - - // chill et. al. are now not allowed. - assert_noop!( - Staking::chill(Origin::signed(10)), - Error::::CallNotAllowed, - ); - }) - } - - #[test] - fn signed_result_can_be_submitted() { - // should check that we have a new validator set normally, event says that it comes from - // offchain. - ExtBuilder::default() - .offchain_election_ext() - .build() - .execute_with(|| { - run_to_block(12); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); - assert!(Staking::snapshot_validators().is_some()); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - )); - - let queued_result = Staking::queued_elected().unwrap(); - assert_eq!(queued_result.compute, ElectionCompute::Signed); - assert_eq!( - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| { - if let MetaEvent::staking(inner) = e { - Some(inner) - } else { - None - } - }) - .last() - .unwrap(), - RawEvent::SolutionStored(ElectionCompute::Signed), - ); - - run_to_block(15); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - assert_eq!( - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| { - if let MetaEvent::staking(inner) = e { - Some(inner) - } else { - None - } - }) - .last() - .unwrap(), - RawEvent::StakingElection(ElectionCompute::Signed), - ); - }) - } - - #[test] - fn signed_result_can_be_submitted_later() { - // same as `signed_result_can_be_submitted` but at a later block. - ExtBuilder::default() - .offchain_election_ext() - .build() - .execute_with(|| { - run_to_block(14); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - assert_ok!(submit_solution(Origin::signed(10), winners, compact, score)); - - let queued_result = Staking::queued_elected().unwrap(); - assert_eq!(queued_result.compute, ElectionCompute::Signed); - - run_to_block(15); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - assert_eq!( - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| { - if let MetaEvent::staking(inner) = e { - Some(inner) - } else { - None - } - }) - .last() - .unwrap(), - RawEvent::StakingElection(ElectionCompute::Signed), - ); - }) - } - - #[test] - fn early_solution_submission_is_rejected() { - // should check that we have a new validator set normally, event says that it comes from - // offchain. - ExtBuilder::default() - .offchain_election_ext() - .build() - .execute_with(|| { - run_to_block(11); - // submission is not yet allowed - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - // create all the indices just to build the solution. - Staking::create_stakers_snapshot(); - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - Staking::kill_stakers_snapshot(); - - assert_err_with_weight!( - Staking::submit_election_solution( - Origin::signed(10), - winners.clone(), - compact.clone(), - score, - current_era(), - ElectionSize::default(), - ), - Error::::OffchainElectionEarlySubmission, - Some(::DbWeight::get().reads(1)), - ); - }) - } - - #[test] - fn weak_solution_is_rejected() { - // A solution which is weaker than what we currently have on-chain is rejected. - ExtBuilder::default() - .offchain_election_ext() - .has_stakers(false) - .validator_count(4) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - // a good solution - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - )); - - // a bad solution - let (compact, winners, score) = horrible_npos_solution(false); - assert_err_with_weight!( - submit_solution( - Origin::signed(10), - winners.clone(), - compact.clone(), - score, - ), - Error::::OffchainElectionWeakSubmission, - Some(::DbWeight::get().reads(3)) - ); - }) - } - - #[test] - fn better_solution_is_accepted() { - // A solution which is better than what we currently have on-chain is accepted. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - // a meeeeh solution - let (compact, winners, score) = horrible_npos_solution(false); - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - )); - - // a better solution - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - )); - }) - } - - #[test] - fn offchain_worker_runs_when_window_open() { - // at the end of the first finalized block with ElectionStatus::open(_), it should execute. - let mut ext = ExtBuilder::default() - .offchain_election_ext() - .validator_count(2) - .build(); - let state = offchainify(&mut ext, 0); - ext.execute_with(|| { - run_to_block(12); - - // local key 11 is in the elected set. - assert_eq_uvec!(Session::validators(), vec![11, 21]); - assert_eq!(state.read().transactions.len(), 0); - Staking::offchain_worker(12); - assert_eq!(state.read().transactions.len(), 1); - - let encoded = state.read().transactions[0].clone(); - let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); - - let call = extrinsic.call; - let inner = match call { - mock::Call::Staking(inner) => inner, - }; - - assert_eq!( - ::validate_unsigned( - TransactionSource::Local, - &inner, - ), - TransactionValidity::Ok(ValidTransaction { - priority: UnsignedPriority::get() + 1125, // the proposed slot stake. - requires: vec![], - provides: vec![("StakingOffchain", current_era()).encode()], - longevity: 3, - propagate: false, - }) - ) - }) - } - - #[test] - fn offchain_worker_runs_with_balancing() { - // Offchain worker balances based on the number provided by randomness. See the difference - // in the priority, which comes from the computed score. - let mut ext = ExtBuilder::default() - .offchain_election_ext() - .validator_count(2) - .max_offchain_iterations(2) - .build(); - let state = offchainify(&mut ext, 2); - ext.execute_with(|| { - run_to_block(12); - - // local key 11 is in the elected set. - assert_eq_uvec!(Session::validators(), vec![11, 21]); - assert_eq!(state.read().transactions.len(), 0); - Staking::offchain_worker(12); - assert_eq!(state.read().transactions.len(), 1); - - let encoded = state.read().transactions[0].clone(); - let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); - - let call = extrinsic.call; - let inner = match call { - mock::Call::Staking(inner) => inner, - }; - - assert_eq!( - ::validate_unsigned( - TransactionSource::Local, - &inner, - ), - TransactionValidity::Ok(ValidTransaction { - // the proposed slot stake, with balance_solution. - priority: UnsignedPriority::get() + 1250, - requires: vec![], - provides: vec![("StakingOffchain", active_era()).encode()], - longevity: 3, - propagate: false, - }) - ) - }) - } - - #[test] - fn mediocre_submission_from_authority_is_early_rejected() { - let mut ext = ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .build(); - let state = offchainify(&mut ext, 0); - ext.execute_with(|| { - run_to_block(12); - // put a good solution on-chain - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - ),); - - // now run the offchain worker in the same chain state. - Staking::offchain_worker(12); - assert_eq!(state.read().transactions.len(), 1); - - let encoded = state.read().transactions[0].clone(); - let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); - - let call = extrinsic.call; - let inner = match call { - mock::Call::Staking(inner) => inner, - }; - - // pass this call to ValidateUnsigned - assert_eq!( - ::validate_unsigned( - TransactionSource::Local, - &inner, - ), - TransactionValidity::Err( - InvalidTransaction::Custom(>::OffchainElectionWeakSubmission.as_u8()).into(), - ), - ) - }) - } - - #[test] - fn invalid_election_correct_number_of_winners() { - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - ValidatorCount::put(3); - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - ValidatorCount::put(4); - - assert_eq!(winners.len(), 3); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusWinnerCount, - ); - }) - } - - #[test] - fn invalid_election_solution_size() { - ExtBuilder::default() - .offchain_election_ext() - .build() - .execute_with(|| { - run_to_block(12); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - - assert_noop!( - Staking::submit_election_solution( - Origin::signed(10), - winners, - compact, - score, - current_era(), - ElectionSize::default(), - ), - Error::::OffchainElectionBogusElectionSize, - ); - }) - } - - #[test] - fn invalid_election_correct_number_of_winners_1() { - // if we have too little validators, then the number of candidates is the bound. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(8) // we simply cannot elect 8 - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - ValidatorCount::put(3); - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - ValidatorCount::put(4); - - assert_eq!(winners.len(), 3); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusWinnerCount, - ); - }) - } - - #[test] - fn invalid_election_correct_number_of_winners_2() { - // if we have too little validators, then the number of candidates is the bound. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(8) // we simply cannot elect 8 - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - - assert_eq!(winners.len(), 4); - - // all good. We chose 4 and it works. - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - ),); - }) - } - - #[test] - fn invalid_election_out_of_bound_nominator_index() { - // A nominator index which is simply invalid - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); - assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); - let (mut compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - - // index 9 doesn't exist. - compact.votes1.push((9, 2)); - - // The error type sadly cannot be more specific now. - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusCompact, - ); - }) - } - - #[test] - fn invalid_election_out_of_bound_validator_index() { - // A validator index which is out of bound - ExtBuilder::default() - .offchain_election_ext() - .validator_count(2) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); - assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); - let (mut compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - - // index 4 doesn't exist. - compact.votes1.iter_mut().for_each(|(_, vidx)| if *vidx == 1 { *vidx = 4 }); - - // The error type sadly cannot be more specific now. - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusCompact, - ); - }) - } - - #[test] - fn invalid_election_out_of_bound_winner_index() { - // A winner index which is simply invalid - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); - assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); - let (compact, _, score) = prepare_submission_with(true, true, 2, |_| {}); - - // index 4 doesn't exist. - let winners = vec![0, 1, 2, 4]; - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusWinner, - ); - }) - } - - #[test] - fn invalid_election_non_winner_validator_index() { - // An edge that points to a correct validator index who is NOT a winner. This is very - // similar to the test that raises `OffchainElectionBogusNomination`. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(2) // we select only 2. - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); - assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); - let (compact, winners, score) = prepare_submission_with(false, true, 2, |a| { - // swap all 11 and 41s in the distribution with non-winners. Note that it is - // important that the count of winners and the count of unique targets remain - // valid. - a.iter_mut().for_each(| StakedAssignment { who, distribution } | - distribution.iter_mut().for_each(|(t, _)| { - if *t == 41 { *t = 31 } else { *t = 21 } - // if it is self vote, correct that. - if *who == 41 { *who = 31 } - if *who == 11 { *who = 21 } - }) - ); - }); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusNomination, - ); - }) - } - - #[test] - fn offchain_election_unique_target_count_is_checked() { - // Number of unique targets and and winners.len must match. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(2) // we select only 2. - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); - assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); - - let (compact, winners, score) = prepare_submission_with(false, true, 2, |a| { - a.iter_mut() - .find(|x| x.who == 5) - // just add any new target. - .map(|x| { - // old value. - assert_eq!(x.distribution, vec![(41, 100)]); - // new value. - x.distribution = vec![(21, 50), (41, 50)] - }); - }); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusWinnerCount, - ); - }) - } - - #[test] - fn invalid_election_wrong_self_vote() { - // A self vote for someone else. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |a| { - // mutate a self vote to target someone else. That someone else is still among the - // winners - a.iter_mut().find(|x| x.who == 11).map(|x| { - x.distribution - .iter_mut() - .find(|y| y.0 == 11) - .map(|y| y.0 = 21) - }); - }); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusSelfVote, - ); - }) - } - - #[test] - fn invalid_election_wrong_self_vote_2() { - // A self validator voting for someone else next to self vote. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |a| { - // Remove the self vote. - a.retain(|x| x.who != 11); - // add is as a new double vote - a.push(StakedAssignment { - who: 11, - distribution: vec![(11, 50), (21, 50)], - }); - }); - - // This raises score issue. - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusSelfVote, - ); - }) - } - - #[test] - fn invalid_election_over_stake() { - // Someone's edge ratios sums to more than 100%. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - // Note: we don't reduce here to be able to tweak votes3. votes3 will vanish if you - // reduce. - let (mut compact, winners, score) = prepare_submission_with(true, false, 0, |_| {}); - - if let Some(c) = compact.votes3.iter_mut().find(|x| x.0 == 0) { - // by default it should have been (0, [(2, 33%), (1, 33%)], 0) - // now the sum is above 100% - c.1 = [(2, percent(66)), (1, percent(66))]; - } - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusCompact, - ); - }) - } - - #[test] - fn invalid_election_under_stake() { - // at the time of this writing, we cannot under stake someone. The compact assignment works - // in a way that some of the stakes are presented by the submitter, and the last one is read - // from chain by subtracting the rest from total. Hence, the sum is always correct. - // This test is only here as a demonstration. - } - - #[test] - fn invalid_election_invalid_target_stealing() { - // A valid voter who voted for someone who is a candidate, and is a correct winner, but is - // actually NOT nominated by this nominator. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - let (compact, winners, score) = prepare_submission_with(true, false, 0, |a| { - // 3 only voted for 20 and 40. We add a fake vote to 30. The stake sum is still - // correctly 100. - a.iter_mut() - .find(|x| x.who == 3) - .map(|x| x.distribution = vec![(21, 50), (41, 30), (31, 20)]); - }); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusNomination, - ); - }) - } - - #[test] - fn nomination_slash_filter_is_checked() { - // If a nominator has voted for someone who has been recently slashed, that particular - // nomination should be disabled for the upcoming election. A solution must respect this - // rule. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - - // finalize the round with fallback. This is needed since all nominator submission - // are in era zero and we want this one to pass with no problems. - run_to_block(15); - - // go to the next session to trigger mock::start_era and bump the active era - run_to_block(20); - - // slash 10. This must happen outside of the election window. - let offender_expo = Staking::eras_stakers(Staking::active_era().unwrap().index, 11); - on_offence_now( - &[OffenceDetails { - offender: (11, offender_expo.clone()), - reporters: vec![], - }], - &[Perbill::from_percent(50)], - ); - - // validate 10 again for the next round. But this guy will not have the votes that - // it should have had from 1 and 2. - assert_ok!(Staking::validate( - Origin::signed(10), - Default::default() - )); - - // open the election window and create snapshots. - run_to_block(32); - - // a solution that has been prepared after the slash. - let (compact, winners, score) = prepare_submission_with(true, false, 0, |a| { - // no one is allowed to vote for 10, except for itself. - a.into_iter() - .filter(|s| s.who != 11) - .for_each(|s| - assert!(s.distribution.iter().find(|(t, _)| *t == 11).is_none()) - ); - }); - - // can be submitted. - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - )); - - // a wrong solution. - let (compact, winners, score) = prepare_submission_with(true, false, 0, |a| { - // add back the vote that has been filtered out. - a.push(StakedAssignment { - who: 1, - distribution: vec![(11, 100)] - }); - }); - - // is rejected. - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionSlashedNomination, - ); - }) - } - - #[test] - fn invalid_election_wrong_score() { - // A valid voter who's total distributed stake is more than what they bond - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - let (compact, winners, mut score) = prepare_submission_with(true, true, 2, |_| {}); - score[0] += 1; - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusScore, - ); - }) - } - - #[test] - fn offchain_storage_is_set() { - let mut ext = ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .build(); - let state = offchainify(&mut ext, 0); - - ext.execute_with(|| { - use offchain_election::OFFCHAIN_HEAD_DB; - use sp_runtime::offchain::storage::StorageValueRef; - - run_to_block(12); - - Staking::offchain_worker(12); - // it works - assert_eq!(state.read().transactions.len(), 1); - - // and it is set - let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); - assert_eq!(storage.get::().unwrap().unwrap(), 12); - }) - } - - #[test] - fn offchain_storage_prevents_duplicate() { - let mut ext = ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .build(); - let _ = offchainify(&mut ext, 0); - - ext.execute_with(|| { - use offchain_election::OFFCHAIN_HEAD_DB; - use sp_runtime::offchain::storage::StorageValueRef; - let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); - - run_to_block(12); - - // first run -- ok - assert_eq!( - offchain_election::set_check_offchain_execution_status::(12), - Ok(()), - ); - assert_eq!(storage.get::().unwrap().unwrap(), 12); - - // re-execute after the next. not allowed. - assert_eq!( - offchain_election::set_check_offchain_execution_status::(13), - Err("recently executed."), - ); - - // a fork like situation -- re-execute 10, 11, 12. But it won't go through. - assert_eq!( - offchain_election::set_check_offchain_execution_status::(10), - Err("fork."), - ); - assert_eq!( - offchain_election::set_check_offchain_execution_status::(11), - Err("fork."), - ); - assert_eq!( - offchain_election::set_check_offchain_execution_status::(12), - Err("recently executed."), - ); - }) - } - - #[test] - #[should_panic] - fn offence_is_blocked_when_window_open() { - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - run_to_block(12); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); - - let offender_expo = Staking::eras_stakers(Staking::active_era().unwrap().index, 10); - - // panic from the impl in mock - on_offence_now( - &[OffenceDetails { - offender: (10, offender_expo.clone()), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - ); - }) - } -} +// mod offchain_election { +// use crate::*; +// use codec::Encode; +// use frame_support::{ +// assert_noop, assert_ok, assert_err_with_weight, +// dispatch::DispatchResultWithPostInfo, +// }; +// use sp_runtime::transaction_validity::TransactionSource; +// use mock::*; +// use parking_lot::RwLock; +// use sp_core::offchain::{ +// testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, +// OffchainExt, TransactionPoolExt, +// }; +// use sp_io::TestExternalities; +// use sp_npos_elections::StakedAssignment; +// use frame_support::traits::OffchainWorker; +// use std::sync::Arc; +// use substrate_test_utils::assert_eq_uvec; + +// fn percent(x: u16) -> OffchainAccuracy { +// OffchainAccuracy::from_percent(x) +// } + +// /// setup a new set of validators and nominator storage items independent of the parent mock +// /// file. This produces a edge graph that can be reduced. +// pub fn build_offchain_election_test_ext() { +// for i in (10..=40).step_by(10) { +// // Note: we respect the convention of the mock (10, 11 pairs etc.) since these accounts +// // have corresponding keys in session which makes everything more ergonomic and +// // realistic. +// bond_validator(i + 1, i, 100); +// } + +// let mut voter = 1; +// bond_nominator(voter, 1000 + voter, 100, vec![11]); +// voter = 2; +// bond_nominator(voter, 1000 + voter, 100, vec![11, 11]); +// voter = 3; +// bond_nominator(voter, 1000 + voter, 100, vec![21, 41]); +// voter = 4; +// bond_nominator(voter, 1000 + voter, 100, vec![21, 31, 41]); +// voter = 5; +// bond_nominator(voter, 1000 + voter, 100, vec![21, 31, 41]); +// } + +// /// convert an externalities to one that can handle offchain worker tests. +// fn offchainify(ext: &mut TestExternalities, iterations: u32) -> Arc> { +// let (offchain, offchain_state) = TestOffchainExt::new(); +// let (pool, pool_state) = TestTransactionPoolExt::new(); + +// let mut seed = [0_u8; 32]; +// seed[0..4].copy_from_slice(&iterations.to_le_bytes()); +// offchain_state.write().seed = seed; + +// ext.register_extension(OffchainExt::new(offchain)); +// ext.register_extension(TransactionPoolExt::new(pool)); + +// pool_state +// } + +// fn election_size() -> ElectionSize { +// ElectionSize { +// validators: Staking::snapshot_validators().unwrap().len() as ValidatorIndex, +// nominators: Staking::snapshot_nominators().unwrap().len() as NominatorIndex, +// } +// } + +// fn submit_solution( +// origin: Origin, +// winners: Vec, +// compact: CompactAssignments, +// score: ElectionScore, +// ) -> DispatchResultWithPostInfo { +// Staking::submit_election_solution( +// origin, +// winners, +// compact, +// score, +// current_era(), +// election_size(), +// ) +// } + +// #[test] +// fn is_current_session_final_works() { +// ExtBuilder::default() +// .session_per_era(3) +// .build() +// .execute_with(|| { +// mock::start_era(1); +// assert_eq!(Session::current_index(), 3); +// assert_eq!(Staking::current_era(), Some(1)); +// assert_eq!(Staking::is_current_session_final(), false); + +// start_session(4); +// assert_eq!(Session::current_index(), 4); +// assert_eq!(Staking::current_era(), Some(1)); +// assert_eq!(Staking::is_current_session_final(), true); + +// start_session(5); +// assert_eq!(Session::current_index(), 5); +// // era changed. +// assert_eq!(Staking::current_era(), Some(2)); +// assert_eq!(Staking::is_current_session_final(), false); +// }) +// } + +// #[test] +// fn offchain_window_is_triggered() { +// ExtBuilder::default() +// .session_per_era(5) +// .session_length(10) +// .election_lookahead(3) +// .build() +// .execute_with(|| { +// run_to_block(7); +// assert_session_era!(0, 0); + +// run_to_block(10); +// assert_session_era!(1, 0); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// assert!(Staking::snapshot_nominators().is_none()); +// assert!(Staking::snapshot_validators().is_none()); + +// run_to_block(36); +// assert_session_era!(3, 0); + +// // fist era has session 0, which has 0 blocks length, so we have in total 40 blocks +// // in the era. +// run_to_block(37); +// assert_session_era!(3, 0); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); +// assert!(Staking::snapshot_nominators().is_some()); +// assert!(Staking::snapshot_validators().is_some()); + +// run_to_block(38); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); + +// run_to_block(39); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); + +// run_to_block(40); +// assert_session_era!(4, 0); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// assert!(Staking::snapshot_nominators().is_none()); +// assert!(Staking::snapshot_validators().is_none()); + +// run_to_block(86); +// assert_session_era!(8, 1); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// assert!(Staking::snapshot_nominators().is_none()); +// assert!(Staking::snapshot_validators().is_none()); + +// // second era onwards has 50 blocks per era. +// run_to_block(87); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(87)); +// assert!(Staking::snapshot_nominators().is_some()); +// assert!(Staking::snapshot_validators().is_some()); + +// run_to_block(90); +// assert_session_era!(9, 1); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// assert!(Staking::snapshot_nominators().is_none()); +// assert!(Staking::snapshot_validators().is_none()); +// }) +// } + +// #[test] +// fn offchain_window_is_triggered_when_forcing() { +// ExtBuilder::default() +// .session_per_era(5) +// .session_length(10) +// .election_lookahead(3) +// .build() +// .execute_with(|| { +// run_to_block(12); +// ForceEra::put(Forcing::ForceNew); +// run_to_block(13); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); + +// run_to_block(17); // instead of 47 +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(17)); + +// run_to_block(20); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// }) +// } + +// #[test] +// fn offchain_window_is_triggered_when_force_always() { +// ExtBuilder::default() +// .session_per_era(5) +// .session_length(10) +// .election_lookahead(3) +// .build() +// .execute_with(|| { + +// ForceEra::put(Forcing::ForceAlways); +// run_to_block(16); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); + +// run_to_block(17); // instead of 37 +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(17)); + +// run_to_block(20); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); + +// run_to_block(26); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); + +// run_to_block(27); // next one again +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(27)); +// }) +// } + +// #[test] +// fn offchain_window_closes_when_forcenone() { +// ExtBuilder::default() +// .session_per_era(5) +// .session_length(10) +// .election_lookahead(3) +// .build() +// .execute_with(|| { +// ForceEra::put(Forcing::ForceNone); + +// run_to_block(36); +// assert_session_era!(3, 0); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); + +// // opens +// run_to_block(37); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); +// assert!(Staking::is_current_session_final()); +// assert!(Staking::snapshot_validators().is_some()); + +// // closes normally +// run_to_block(40); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// assert!(!Staking::is_current_session_final()); +// assert!(Staking::snapshot_validators().is_none()); +// assert_session_era!(4, 0); + +// run_to_block(47); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// assert_session_era!(4, 0); + +// run_to_block(57); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// assert_session_era!(5, 0); + +// run_to_block(67); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); + +// // Will not open again as scheduled +// run_to_block(87); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// assert_session_era!(8, 0); + +// run_to_block(90); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// assert_session_era!(9, 0); +// }) +// } + +// #[test] +// fn offchain_window_on_chain_fallback_works() { +// ExtBuilder::default().build_and_execute(|| { +// start_session(1); +// start_session(2); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// // some election must have happened by now. +// assert_eq!( +// System::events() +// .into_iter() +// .map(|r| r.event) +// .filter_map(|e| { +// if let MetaEvent::staking(inner) = e { +// Some(inner) +// } else { +// None +// } +// }) +// .last() +// .unwrap(), +// RawEvent::StakingElection(ElectionCompute::OnChain), +// ); +// }) +// } + +// #[test] +// #[ignore] +// fn offchain_wont_work_if_snapshot_fails() { +// ExtBuilder::default() +// .offchain_election_ext() +// .build() +// .execute_with(|| { +// run_to_block(12); +// assert!(Staking::snapshot_validators().is_some()); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); + +// // validate more than the limit +// let limit: NominatorIndex = ValidatorIndex::max_value() as NominatorIndex + 1; +// let ctrl = 1_000_000; +// for i in 0..limit { +// bond_validator((1000 + i).into(), (1000 + i + ctrl).into(), 100); +// } + +// // window stays closed since no snapshot was taken. +// run_to_block(27); +// assert!(Staking::snapshot_validators().is_none()); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); +// }) +// } + +// #[test] +// fn staking_is_locked_when_election_window_open() { +// ExtBuilder::default() +// .offchain_election_ext() +// .election_lookahead(3) +// .build() +// .execute_with(|| { +// run_to_block(12); +// assert!(Staking::snapshot_validators().is_some()); +// // given +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); + +// // chill et. al. are now not allowed. +// assert_noop!( +// Staking::chill(Origin::signed(10)), +// Error::::CallNotAllowed, +// ); +// }) +// } + +// #[test] +// fn signed_result_can_be_submitted() { +// // should check that we have a new validator set normally, event says that it comes from +// // offchain. +// ExtBuilder::default() +// .offchain_election_ext() +// .build() +// .execute_with(|| { +// run_to_block(12); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); +// assert!(Staking::snapshot_validators().is_some()); + +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); +// assert_ok!(submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// )); + +// let queued_result = Staking::queued_elected().unwrap(); +// assert_eq!(queued_result.compute, ElectionCompute::Signed); +// assert_eq!( +// System::events() +// .into_iter() +// .map(|r| r.event) +// .filter_map(|e| { +// if let MetaEvent::staking(inner) = e { +// Some(inner) +// } else { +// None +// } +// }) +// .last() +// .unwrap(), +// RawEvent::SolutionStored(ElectionCompute::Signed), +// ); + +// run_to_block(15); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); + +// assert_eq!( +// System::events() +// .into_iter() +// .map(|r| r.event) +// .filter_map(|e| { +// if let MetaEvent::staking(inner) = e { +// Some(inner) +// } else { +// None +// } +// }) +// .last() +// .unwrap(), +// RawEvent::StakingElection(ElectionCompute::Signed), +// ); +// }) +// } + +// #[test] +// fn signed_result_can_be_submitted_later() { +// // same as `signed_result_can_be_submitted` but at a later block. +// ExtBuilder::default() +// .offchain_election_ext() +// .build() +// .execute_with(|| { +// run_to_block(14); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); + +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); +// assert_ok!(submit_solution(Origin::signed(10), winners, compact, score)); + +// let queued_result = Staking::queued_elected().unwrap(); +// assert_eq!(queued_result.compute, ElectionCompute::Signed); + +// run_to_block(15); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); + +// assert_eq!( +// System::events() +// .into_iter() +// .map(|r| r.event) +// .filter_map(|e| { +// if let MetaEvent::staking(inner) = e { +// Some(inner) +// } else { +// None +// } +// }) +// .last() +// .unwrap(), +// RawEvent::StakingElection(ElectionCompute::Signed), +// ); +// }) +// } + +// #[test] +// fn early_solution_submission_is_rejected() { +// // should check that we have a new validator set normally, event says that it comes from +// // offchain. +// ExtBuilder::default() +// .offchain_election_ext() +// .build() +// .execute_with(|| { +// run_to_block(11); +// // submission is not yet allowed +// assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); + +// // create all the indices just to build the solution. +// Staking::create_stakers_snapshot(); +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); +// Staking::kill_stakers_snapshot(); + +// assert_err_with_weight!( +// Staking::submit_election_solution( +// Origin::signed(10), +// winners.clone(), +// compact.clone(), +// score, +// current_era(), +// ElectionSize::default(), +// ), +// Error::::OffchainElectionEarlySubmission, +// Some(::DbWeight::get().reads(1)), +// ); +// }) +// } + +// #[test] +// fn weak_solution_is_rejected() { +// // A solution which is weaker than what we currently have on-chain is rejected. +// ExtBuilder::default() +// .offchain_election_ext() +// .has_stakers(false) +// .validator_count(4) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// // a good solution +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); +// assert_ok!(submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// )); + +// // a bad solution +// let (compact, winners, score) = horrible_npos_solution(false); +// assert_err_with_weight!( +// submit_solution( +// Origin::signed(10), +// winners.clone(), +// compact.clone(), +// score, +// ), +// Error::::OffchainElectionWeakSubmission, +// Some(::DbWeight::get().reads(3)) +// ); +// }) +// } + +// #[test] +// fn better_solution_is_accepted() { +// // A solution which is better than what we currently have on-chain is accepted. +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// // a meeeeh solution +// let (compact, winners, score) = horrible_npos_solution(false); +// assert_ok!(submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// )); + +// // a better solution +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); +// assert_ok!(submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// )); +// }) +// } + +// #[test] +// fn offchain_worker_runs_when_window_open() { +// // at the end of the first finalized block with ElectionStatus::open(_), it should execute. +// let mut ext = ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(2) +// .build(); +// let state = offchainify(&mut ext, 0); +// ext.execute_with(|| { +// run_to_block(12); + +// // local key 11 is in the elected set. +// assert_eq_uvec!(Session::validators(), vec![11, 21]); +// assert_eq!(state.read().transactions.len(), 0); +// Staking::offchain_worker(12); +// assert_eq!(state.read().transactions.len(), 1); + +// let encoded = state.read().transactions[0].clone(); +// let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); + +// let call = extrinsic.call; +// let inner = match call { +// mock::Call::Staking(inner) => inner, +// }; + +// assert_eq!( +// ::validate_unsigned( +// TransactionSource::Local, +// &inner, +// ), +// TransactionValidity::Ok(ValidTransaction { +// priority: UnsignedPriority::get() + 1125, // the proposed slot stake. +// requires: vec![], +// provides: vec![("StakingOffchain", current_era()).encode()], +// longevity: 3, +// propagate: false, +// }) +// ) +// }) +// } + +// #[test] +// fn offchain_worker_runs_with_balancing() { +// // Offchain worker balances based on the number provided by randomness. See the difference +// // in the priority, which comes from the computed score. +// let mut ext = ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(2) +// .max_offchain_iterations(2) +// .build(); +// let state = offchainify(&mut ext, 2); +// ext.execute_with(|| { +// run_to_block(12); + +// // local key 11 is in the elected set. +// assert_eq_uvec!(Session::validators(), vec![11, 21]); +// assert_eq!(state.read().transactions.len(), 0); +// Staking::offchain_worker(12); +// assert_eq!(state.read().transactions.len(), 1); + +// let encoded = state.read().transactions[0].clone(); +// let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); + +// let call = extrinsic.call; +// let inner = match call { +// mock::Call::Staking(inner) => inner, +// }; + +// assert_eq!( +// ::validate_unsigned( +// TransactionSource::Local, +// &inner, +// ), +// TransactionValidity::Ok(ValidTransaction { +// // the proposed slot stake, with balance_solution. +// priority: UnsignedPriority::get() + 1250, +// requires: vec![], +// provides: vec![("StakingOffchain", active_era()).encode()], +// longevity: 3, +// propagate: false, +// }) +// ) +// }) +// } + +// #[test] +// fn mediocre_submission_from_authority_is_early_rejected() { +// let mut ext = ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .build(); +// let state = offchainify(&mut ext, 0); +// ext.execute_with(|| { +// run_to_block(12); +// // put a good solution on-chain +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); +// assert_ok!(submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ),); + +// // now run the offchain worker in the same chain state. +// Staking::offchain_worker(12); +// assert_eq!(state.read().transactions.len(), 1); + +// let encoded = state.read().transactions[0].clone(); +// let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); + +// let call = extrinsic.call; +// let inner = match call { +// mock::Call::Staking(inner) => inner, +// }; + +// // pass this call to ValidateUnsigned +// assert_eq!( +// ::validate_unsigned( +// TransactionSource::Local, +// &inner, +// ), +// TransactionValidity::Err( +// InvalidTransaction::Custom(>::OffchainElectionWeakSubmission.as_u8()).into(), +// ), +// ) +// }) +// } + +// #[test] +// fn invalid_election_correct_number_of_winners() { +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// ValidatorCount::put(3); +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); +// ValidatorCount::put(4); + +// assert_eq!(winners.len(), 3); + +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusWinnerCount, +// ); +// }) +// } + +// #[test] +// fn invalid_election_solution_size() { +// ExtBuilder::default() +// .offchain_election_ext() +// .build() +// .execute_with(|| { +// run_to_block(12); + +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); + +// assert_noop!( +// Staking::submit_election_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// current_era(), +// ElectionSize::default(), +// ), +// Error::::OffchainElectionBogusElectionSize, +// ); +// }) +// } + +// #[test] +// fn invalid_election_correct_number_of_winners_1() { +// // if we have too little validators, then the number of candidates is the bound. +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(8) // we simply cannot elect 8 +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// ValidatorCount::put(3); +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); +// ValidatorCount::put(4); + +// assert_eq!(winners.len(), 3); + +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusWinnerCount, +// ); +// }) +// } + +// #[test] +// fn invalid_election_correct_number_of_winners_2() { +// // if we have too little validators, then the number of candidates is the bound. +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(8) // we simply cannot elect 8 +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); + +// assert_eq!(winners.len(), 4); + +// // all good. We chose 4 and it works. +// assert_ok!(submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ),); +// }) +// } + +// #[test] +// fn invalid_election_out_of_bound_nominator_index() { +// // A nominator index which is simply invalid +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); +// assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); +// let (mut compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); + +// // index 9 doesn't exist. +// compact.votes1.push((9, 2)); + +// // The error type sadly cannot be more specific now. +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusCompact, +// ); +// }) +// } + +// #[test] +// fn invalid_election_out_of_bound_validator_index() { +// // A validator index which is out of bound +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(2) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); +// assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); +// let (mut compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); + +// // index 4 doesn't exist. +// compact.votes1.iter_mut().for_each(|(_, vidx)| if *vidx == 1 { *vidx = 4 }); + +// // The error type sadly cannot be more specific now. +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusCompact, +// ); +// }) +// } + +// #[test] +// fn invalid_election_out_of_bound_winner_index() { +// // A winner index which is simply invalid +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); +// assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); +// let (compact, _, score) = prepare_submission_with(true, true, 2, |_| {}); + +// // index 4 doesn't exist. +// let winners = vec![0, 1, 2, 4]; + +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusWinner, +// ); +// }) +// } + +// #[test] +// fn invalid_election_non_winner_validator_index() { +// // An edge that points to a correct validator index who is NOT a winner. This is very +// // similar to the test that raises `OffchainElectionBogusNomination`. +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(2) // we select only 2. +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); +// assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); +// let (compact, winners, score) = prepare_submission_with(false, true, 2, |a| { +// // swap all 11 and 41s in the distribution with non-winners. Note that it is +// // important that the count of winners and the count of unique targets remain +// // valid. +// a.iter_mut().for_each(| StakedAssignment { who, distribution } | +// distribution.iter_mut().for_each(|(t, _)| { +// if *t == 41 { *t = 31 } else { *t = 21 } +// // if it is self vote, correct that. +// if *who == 41 { *who = 31 } +// if *who == 11 { *who = 21 } +// }) +// ); +// }); + +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusNomination, +// ); +// }) +// } + +// #[test] +// fn offchain_election_unique_target_count_is_checked() { +// // Number of unique targets and and winners.len must match. +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(2) // we select only 2. +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); +// assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); + +// let (compact, winners, score) = prepare_submission_with(false, true, 2, |a| { +// a.iter_mut() +// .find(|x| x.who == 5) +// // just add any new target. +// .map(|x| { +// // old value. +// assert_eq!(x.distribution, vec![(41, 100)]); +// // new value. +// x.distribution = vec![(21, 50), (41, 50)] +// }); +// }); + +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusWinnerCount, +// ); +// }) +// } + +// #[test] +// fn invalid_election_wrong_self_vote() { +// // A self vote for someone else. +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |a| { +// // mutate a self vote to target someone else. That someone else is still among the +// // winners +// a.iter_mut().find(|x| x.who == 11).map(|x| { +// x.distribution +// .iter_mut() +// .find(|y| y.0 == 11) +// .map(|y| y.0 = 21) +// }); +// }); + +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusSelfVote, +// ); +// }) +// } + +// #[test] +// fn invalid_election_wrong_self_vote_2() { +// // A self validator voting for someone else next to self vote. +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// let (compact, winners, score) = prepare_submission_with(true, true, 2, |a| { +// // Remove the self vote. +// a.retain(|x| x.who != 11); +// // add is as a new double vote +// a.push(StakedAssignment { +// who: 11, +// distribution: vec![(11, 50), (21, 50)], +// }); +// }); + +// // This raises score issue. +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusSelfVote, +// ); +// }) +// } + +// #[test] +// fn invalid_election_over_stake() { +// // Someone's edge ratios sums to more than 100%. +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// // Note: we don't reduce here to be able to tweak votes3. votes3 will vanish if you +// // reduce. +// let (mut compact, winners, score) = prepare_submission_with(true, false, 0, |_| {}); + +// if let Some(c) = compact.votes3.iter_mut().find(|x| x.0 == 0) { +// // by default it should have been (0, [(2, 33%), (1, 33%)], 0) +// // now the sum is above 100% +// c.1 = [(2, percent(66)), (1, percent(66))]; +// } + +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusCompact, +// ); +// }) +// } + +// #[test] +// fn invalid_election_under_stake() { +// // at the time of this writing, we cannot under stake someone. The compact assignment works +// // in a way that some of the stakes are presented by the submitter, and the last one is read +// // from chain by subtracting the rest from total. Hence, the sum is always correct. +// // This test is only here as a demonstration. +// } + +// #[test] +// fn invalid_election_invalid_target_stealing() { +// // A valid voter who voted for someone who is a candidate, and is a correct winner, but is +// // actually NOT nominated by this nominator. +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// let (compact, winners, score) = prepare_submission_with(true, false, 0, |a| { +// // 3 only voted for 20 and 40. We add a fake vote to 30. The stake sum is still +// // correctly 100. +// a.iter_mut() +// .find(|x| x.who == 3) +// .map(|x| x.distribution = vec![(21, 50), (41, 30), (31, 20)]); +// }); + +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusNomination, +// ); +// }) +// } + +// #[test] +// fn nomination_slash_filter_is_checked() { +// // If a nominator has voted for someone who has been recently slashed, that particular +// // nomination should be disabled for the upcoming election. A solution must respect this +// // rule. +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); + +// // finalize the round with fallback. This is needed since all nominator submission +// // are in era zero and we want this one to pass with no problems. +// run_to_block(15); + +// // go to the next session to trigger mock::start_era and bump the active era +// run_to_block(20); + +// // slash 10. This must happen outside of the election window. +// let offender_expo = Staking::eras_stakers(Staking::active_era().unwrap().index, 11); +// on_offence_now( +// &[OffenceDetails { +// offender: (11, offender_expo.clone()), +// reporters: vec![], +// }], +// &[Perbill::from_percent(50)], +// ); + +// // validate 10 again for the next round. But this guy will not have the votes that +// // it should have had from 1 and 2. +// assert_ok!(Staking::validate( +// Origin::signed(10), +// Default::default() +// )); + +// // open the election window and create snapshots. +// run_to_block(32); + +// // a solution that has been prepared after the slash. +// let (compact, winners, score) = prepare_submission_with(true, false, 0, |a| { +// // no one is allowed to vote for 10, except for itself. +// a.into_iter() +// .filter(|s| s.who != 11) +// .for_each(|s| +// assert!(s.distribution.iter().find(|(t, _)| *t == 11).is_none()) +// ); +// }); + +// // can be submitted. +// assert_ok!(submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// )); + +// // a wrong solution. +// let (compact, winners, score) = prepare_submission_with(true, false, 0, |a| { +// // add back the vote that has been filtered out. +// a.push(StakedAssignment { +// who: 1, +// distribution: vec![(11, 100)] +// }); +// }); + +// // is rejected. +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionSlashedNomination, +// ); +// }) +// } + +// #[test] +// fn invalid_election_wrong_score() { +// // A valid voter who's total distributed stake is more than what they bond +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// build_offchain_election_test_ext(); +// run_to_block(12); + +// let (compact, winners, mut score) = prepare_submission_with(true, true, 2, |_| {}); +// score[0] += 1; + +// assert_noop!( +// submit_solution( +// Origin::signed(10), +// winners, +// compact, +// score, +// ), +// Error::::OffchainElectionBogusScore, +// ); +// }) +// } + +// #[test] +// fn offchain_storage_is_set() { +// let mut ext = ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .build(); +// let state = offchainify(&mut ext, 0); + +// ext.execute_with(|| { +// use offchain_election::OFFCHAIN_HEAD_DB; +// use sp_runtime::offchain::storage::StorageValueRef; + +// run_to_block(12); + +// Staking::offchain_worker(12); +// // it works +// assert_eq!(state.read().transactions.len(), 1); + +// // and it is set +// let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); +// assert_eq!(storage.get::().unwrap().unwrap(), 12); +// }) +// } + +// #[test] +// fn offchain_storage_prevents_duplicate() { +// let mut ext = ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .build(); +// let _ = offchainify(&mut ext, 0); + +// ext.execute_with(|| { +// use offchain_election::OFFCHAIN_HEAD_DB; +// use sp_runtime::offchain::storage::StorageValueRef; +// let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); + +// run_to_block(12); + +// // first run -- ok +// assert_eq!( +// offchain_election::set_check_offchain_execution_status::(12), +// Ok(()), +// ); +// assert_eq!(storage.get::().unwrap().unwrap(), 12); + +// // re-execute after the next. not allowed. +// assert_eq!( +// offchain_election::set_check_offchain_execution_status::(13), +// Err("recently executed."), +// ); + +// // a fork like situation -- re-execute 10, 11, 12. But it won't go through. +// assert_eq!( +// offchain_election::set_check_offchain_execution_status::(10), +// Err("fork."), +// ); +// assert_eq!( +// offchain_election::set_check_offchain_execution_status::(11), +// Err("fork."), +// ); +// assert_eq!( +// offchain_election::set_check_offchain_execution_status::(12), +// Err("recently executed."), +// ); +// }) +// } + +// #[test] +// #[should_panic] +// fn offence_is_blocked_when_window_open() { +// ExtBuilder::default() +// .offchain_election_ext() +// .validator_count(4) +// .has_stakers(false) +// .build() +// .execute_with(|| { +// run_to_block(12); +// assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); + +// let offender_expo = Staking::eras_stakers(Staking::active_era().unwrap().index, 10); + +// // panic from the impl in mock +// on_offence_now( +// &[OffenceDetails { +// offender: (10, offender_expo.clone()), +// reporters: vec![], +// }], +// &[Perbill::from_percent(10)], +// ); +// }) +// } +// } #[test] fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_validator() { @@ -4411,6 +4415,8 @@ fn test_payout_stakers() { bond_nominator(1000 + i, 100 + i, balance + i as Balance, vec![11]); } + dbg!("HERE"); + mock::start_era(1); Staking::reward_by_ids(vec![(11, 1)]); // Compute total payout now for whole duration as other parameter won't change @@ -4608,52 +4614,21 @@ fn offences_weight_calculated_correctly() { }); } -#[test] -fn on_initialize_weight_is_correct() { - ExtBuilder::default().has_stakers(false).build_and_execute(|| { - assert_eq!(Validators::::iter().count(), 0); - assert_eq!(Nominators::::iter().count(), 0); - // When this pallet has nothing, we do 4 reads each block - let base_weight = ::DbWeight::get().reads(4); - assert_eq!(base_weight, Staking::on_initialize(0)); - }); - - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - crate::tests::offchain_election::build_offchain_election_test_ext(); - run_to_block(11); - Staking::on_finalize(System::block_number()); - System::set_block_number((System::block_number() + 1).into()); - Timestamp::set_timestamp(System::block_number() * 1000 + INIT_TIMESTAMP); - Session::on_initialize(System::block_number()); - - assert_eq!(Validators::::iter().count(), 4); - assert_eq!(Nominators::::iter().count(), 5); - // With 4 validators and 5 nominator, we should increase weight by: - // - (4 + 5) reads - // - 3 Writes - let final_weight = ::DbWeight::get().reads_writes(4 + 9, 3); - assert_eq!(final_weight, Staking::on_initialize(System::block_number())); - }); -} - #[test] fn payout_creates_controller() { - ExtBuilder::default().has_stakers(false).build_and_execute(|| { - let balance = 1000; - // Create a validator: - bond_validator(11, 10, balance); - - // Create a stash/controller pair - bond_nominator(1234, 1337, 100, vec![11]); - - // kill controller - assert_ok!(Balances::transfer(Origin::signed(1337), 1234, 100)); - assert_eq!(Balances::free_balance(1337), 0); + ExtBuilder::default() + .has_stakers(false) + .build_and_execute(|| { + let balance = 1000; + // Create a validator: + bond_validator(11, 10, balance); + + // Create a stash/controller pair + bond_nominator(1234, 1337, 100, vec![11]); + + // kill controller + assert_ok!(Balances::transfer(Origin::signed(1337), 1234, 100)); + assert_eq!(Balances::free_balance(1337), 0); mock::start_era(1); Staking::reward_by_ids(vec![(11, 1)]); diff --git a/primitives/npos-elections/src/helpers.rs b/primitives/npos-elections/src/helpers.rs index 8ea14f20b1b39..49f862f7ab97c 100644 --- a/primitives/npos-elections/src/helpers.rs +++ b/primitives/npos-elections/src/helpers.rs @@ -27,13 +27,8 @@ use sp_std::prelude::*; /// Converts a vector of ratio assignments into ones with absolute budget value. /// /// Note that this will NOT attempt at normalizing the result. -<<<<<<< HEAD pub fn assignment_ratio_to_staked( - ratio: Vec>, -======= -pub fn assignment_ratio_to_staked( ratios: Vec>, ->>>>>>> 8a644f5690d6cc4f9d3f9dc7094219cd51f4b54a stake_of: FS, ) -> Vec> where From c3619116e8721f899c55589bffad1dd8667aa280 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 14 Oct 2020 11:45:37 +0200 Subject: [PATCH 10/62] All staking tests work --- frame/election-providers/exapnded.test.rs | 32 ++-- frame/election-providers/expanded.rs | 36 ++--- frame/election-providers/src/lib.rs | 32 ++-- frame/election-providers/src/onchain.rs | 16 +- .../src/two_phase/macros.rs | 14 +- .../election-providers/src/two_phase/mock.rs | 12 +- frame/election-providers/src/two_phase/mod.rs | 22 ++- frame/staking/src/lib.rs | 61 ++++--- frame/staking/src/mock.rs | 54 +------ frame/staking/src/tests.rs | 42 ++--- .../fuzzer/src/phragmen_balancing.rs | 20 ++- .../fuzzer/src/phragmms_balancing.rs | 13 +- .../npos-elections/fuzzer/src/reduce.rs | 9 +- primitives/npos-elections/src/lib.rs | 150 ++++++++++-------- primitives/npos-elections/src/tests.rs | 22 +-- 15 files changed, 261 insertions(+), 274 deletions(-) diff --git a/frame/election-providers/exapnded.test.rs b/frame/election-providers/exapnded.test.rs index 2b811ec618ab9..34f10a2c6bf0b 100644 --- a/frame/election-providers/exapnded.test.rs +++ b/frame/election-providers/exapnded.test.rs @@ -8,7 +8,7 @@ pub mod onchain { use crate::{ElectionProvider, Error}; use sp_arithmetic::PerThing; use sp_npos_elections::{ - ElectionResult, ExtendedBalance, FlatSupportMap, FlattenSupportMap, IdentifierT, VoteWeight, + ElectionResult, ExtendedBalance, FlattenSupportMap, IdentifierT, Supports, VoteWeight, }; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub struct OnChainSequentialPhragmen; @@ -17,7 +17,7 @@ pub mod onchain { to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Error> + ) -> Result, Error> where ExtendedBalance: From<

::Inner>, P: sp_std::ops::Mul, @@ -64,7 +64,7 @@ pub mod two_phase { use frame_system::{ensure_none, ensure_signed}; use sp_npos_elections::{ evaluate_support, generate_solution_type, is_score_better, Assignment, ElectionScore, - ExtendedBalance, FlatSupportMap, FlattenSupportMap, VoteWeight, + ExtendedBalance, FlattenSupportMap, Supports, VoteWeight, }; use sp_runtime::{traits::Zero, PerThing, PerU16, Perbill, RuntimeDebug}; use sp_std::{mem::size_of, prelude::*}; @@ -74,7 +74,7 @@ pub mod two_phase { pub use frame_support::{assert_noop, assert_ok}; use frame_support::{parameter_types, traits::OnInitialize, weights::Weight}; use sp_core::H256; - use sp_npos_elections::FlatSupportMap; + use sp_npos_elections::Supports; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, @@ -5374,7 +5374,7 @@ pub mod two_phase { /// A parsed solution, ready to be enacted. pub struct ReadySolution { winners: Vec, - supports: FlatSupportMap, + supports: Supports, } impl ::core::marker::StructuralPartialEq for ReadySolution {} #[automatically_derived] @@ -5418,7 +5418,7 @@ pub mod two_phase { fn assert_receiver_is_total_eq(&self) -> () { { let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; } } } @@ -5446,8 +5446,8 @@ pub mod two_phase { where Vec: _parity_scale_codec::Encode, Vec: _parity_scale_codec::Encode, - FlatSupportMap: _parity_scale_codec::Encode, - FlatSupportMap: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, { fn encode_to(&self, dest: &mut EncOut) { dest.push(&self.winners); @@ -5458,8 +5458,8 @@ pub mod two_phase { where Vec: _parity_scale_codec::Encode, Vec: _parity_scale_codec::Encode, - FlatSupportMap: _parity_scale_codec::Encode, - FlatSupportMap: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, { } }; @@ -5471,8 +5471,8 @@ pub mod two_phase { where Vec: _parity_scale_codec::Decode, Vec: _parity_scale_codec::Decode, - FlatSupportMap: _parity_scale_codec::Decode, - FlatSupportMap: _parity_scale_codec::Decode, + Supports: _parity_scale_codec::Decode, + Supports: _parity_scale_codec::Decode, { fn decode( input: &mut DecIn, @@ -6983,7 +6983,7 @@ pub mod two_phase { let supports = supports.flatten(); Ok(ReadySolution { winners, supports }) } - fn onchain_fallback() -> Result, crate::Error> { + fn onchain_fallback() -> Result, crate::Error> { let desired_targets = Self::desired_targets() as usize; let voters = Self::snapshot_voters().ok_or(crate::Error::SnapshotUnAvailable)?; let targets = Self::snapshot_targets().ok_or(crate::Error::SnapshotUnAvailable)?; @@ -6999,7 +6999,7 @@ pub mod two_phase { _to_elect: usize, _targets: Vec, _voters: Vec<(T::AccountId, VoteWeight, Vec)>, - ) -> Result, crate::Error> + ) -> Result, crate::Error> where ExtendedBalance: From<

::Inner>, P: sp_std::ops::Mul, @@ -7557,7 +7557,7 @@ pub mod two_phase { use sp_arithmetic::PerThing; #[doc(hidden)] pub use sp_npos_elections::VoteWeight; -use sp_npos_elections::{ExtendedBalance, FlatSupportMap}; +use sp_npos_elections::{ExtendedBalance, Supports}; use sp_runtime::RuntimeDebug; #[doc(hidden)] pub use sp_std::convert::TryInto; @@ -7600,7 +7600,7 @@ pub trait ElectionProvider { to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Error> + ) -> Result, Error> where ExtendedBalance: From<

::Inner>, P: sp_std::ops::Mul; diff --git a/frame/election-providers/expanded.rs b/frame/election-providers/expanded.rs index 161ab56cc7683..76fe0202e2fe8 100644 --- a/frame/election-providers/expanded.rs +++ b/frame/election-providers/expanded.rs @@ -19,7 +19,7 @@ extern crate std; use sp_std::{fmt::Debug, prelude::*}; /// The onchain module. pub mod onchain { - use crate::{ElectionProvider, FlatSupportMap, FlattenSupportMap}; + use crate::{ElectionProvider, FlattenSupportMap, Supports}; use sp_arithmetic::PerThing; use sp_npos_elections::{ ElectionResult, ExtendedBalance, IdentifierT, PerThing128, VoteWeight, @@ -87,7 +87,7 @@ pub mod onchain { to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, { @@ -209,8 +209,8 @@ pub mod two_phase { //! TODO //! use crate::{ - onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, FlatSupportMap, - FlattenSupportMap, + onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, + FlattenSupportMap, Supports, }; use codec::{Decode, Encode, HasCompact}; use frame_support::{ @@ -1070,7 +1070,7 @@ pub mod two_phase { pub struct ReadySolution { /// The final supports of the solution. This is target-major vector, storing each winners, total /// backing, and each individual backer. - supports: FlatSupportMap, + supports: Supports, /// How this election was computed. compute: ElectionCompute, } @@ -1115,7 +1115,7 @@ pub mod two_phase { #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { - let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; let _: ::core::cmp::AssertParamIsEq; } } @@ -1142,8 +1142,8 @@ pub mod two_phase { extern crate codec as _parity_scale_codec; impl _parity_scale_codec::Encode for ReadySolution where - FlatSupportMap: _parity_scale_codec::Encode, - FlatSupportMap: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, { fn encode_to(&self, dest: &mut EncOut) { dest.push(&self.supports); @@ -1152,8 +1152,8 @@ pub mod two_phase { } impl _parity_scale_codec::EncodeLike for ReadySolution where - FlatSupportMap: _parity_scale_codec::Encode, - FlatSupportMap: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, { } }; @@ -1163,8 +1163,8 @@ pub mod two_phase { extern crate codec as _parity_scale_codec; impl _parity_scale_codec::Decode for ReadySolution where - FlatSupportMap: _parity_scale_codec::Decode, - FlatSupportMap: _parity_scale_codec::Decode, + Supports: _parity_scale_codec::Decode, + Supports: _parity_scale_codec::Decode, { fn decode( input: &mut DecIn, @@ -3115,7 +3115,7 @@ pub mod two_phase { Ok(ReadySolution { supports, compute }) } /// On-chain fallback of election. - fn onchain_fallback() -> Result, Error> { + fn onchain_fallback() -> Result, Error> { let desired_targets = Self::desired_targets() as usize; let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; @@ -3137,7 +3137,7 @@ pub mod two_phase { _to_elect: usize, _targets: Vec, _voters: Vec<(T::AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, { @@ -3181,13 +3181,13 @@ pub use sp_std::convert::TryInto; /// A flat variant of [`sp_npos_elections::SupportMap`]. /// /// The main advantage of this is that it is encodable. -pub type FlatSupportMap = Vec<(A, Support)>; +pub type Supports = Vec<(A, Support)>; /// Helper trait to convert from a support map to a flat support vector. pub trait FlattenSupportMap { - fn flatten(self) -> FlatSupportMap; + fn flatten(self) -> Supports; } impl FlattenSupportMap for SupportMap { - fn flatten(self) -> FlatSupportMap { + fn flatten(self) -> Supports { self.into_iter().map(|(k, v)| (k, v)).collect::>() } } @@ -3262,7 +3262,7 @@ pub trait ElectionProvider { to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>; /// Returns true if an election is still ongoing. This can be used by the call site to diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs index 65446e234ad8e..b9e4523248d3b 100644 --- a/frame/election-providers/src/lib.rs +++ b/frame/election-providers/src/lib.rs @@ -39,7 +39,9 @@ pub mod onchain; pub mod two_phase; use sp_arithmetic::PerThing; -use sp_npos_elections::{CompactSolution, ExtendedBalance, PerThing128, Support, SupportMap}; +use sp_npos_elections::{ + CompactSolution, ExtendedBalance, FlattenSupportMap, PerThing128, Support, SupportMap, Supports, +}; // for the helper macros #[doc(hidden)] @@ -47,22 +49,6 @@ pub use sp_npos_elections::VoteWeight; #[doc(hidden)] pub use sp_std::convert::TryInto; -/// A flat variant of [`sp_npos_elections::SupportMap`]. -/// -/// The main advantage of this is that it is encodable. -pub type FlatSupportMap = Vec<(A, Support)>; - -/// Helper trait to convert from a support map to a flat support vector. -pub trait FlattenSupportMap { - fn flatten(self) -> FlatSupportMap; -} - -impl FlattenSupportMap for SupportMap { - fn flatten(self) -> FlatSupportMap { - self.into_iter().map(|(k, v)| (k, v)).collect::>() - } -} - /// Something that can provide the data to something else that implements [`ElectionProvider`], such /// as the [`two_phase`] module. /// @@ -123,7 +109,8 @@ pub trait ElectionDataProvider { /// Something that can compute the result of an election and pass it back to the caller. pub trait ElectionProvider { - /// Indicate weather this election provider needs data when calling [`elect`] or not. + /// Indicate weather this election provider needs data when calling [`elect`] or not. If + /// `false`, then the call site can ignore all parameters of [`elect`] const NEEDS_ELECT_DATA: bool; /// The error type that is returned by the provider. @@ -142,12 +129,13 @@ pub trait ElectionProvider { to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>; - /// Returns true if an election is still ongoing. This can be used by the call site to - /// dynamically check of a long-lasting election (such as [`two_phase`]) is still on-going or - /// not. + /// Returns true if an election is still ongoing. + /// + /// This can be used by the call site to dynamically check of a long-lasting election (such as + /// [`two_phase`]) is still on-going or not. fn ongoing() -> bool; } diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs index 29e366f348698..f84f3582a9c22 100644 --- a/frame/election-providers/src/onchain.rs +++ b/frame/election-providers/src/onchain.rs @@ -1,4 +1,4 @@ -use crate::{ElectionProvider, FlatSupportMap, FlattenSupportMap}; +use crate::{ElectionProvider, FlattenSupportMap, Supports}; use sp_arithmetic::PerThing; use sp_npos_elections::{ElectionResult, ExtendedBalance, IdentifierT, PerThing128, VoteWeight}; use sp_runtime::RuntimeDebug; @@ -17,17 +17,24 @@ impl From for Error { } } +/// A simple on-chian implementation of the election provider trait. +/// +/// This will accept voting data on the fly and produce the results immediately. +/// +/// ### Warning +/// +/// This can be very expensive to run frequently on-chain. Use with care. pub struct OnChainSequentialPhragmen; + impl ElectionProvider for OnChainSequentialPhragmen { type Error = Error; - const NEEDS_ELECT_DATA: bool = true; fn elect( to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, { @@ -52,8 +59,7 @@ impl ElectionProvider for OnChainSequentialPh )?; let winners = sp_npos_elections::to_without_backing(winners); - sp_npos_elections::build_support_map(&winners, &staked) - .map(|s| s.flatten()) + sp_npos_elections::to_supports(&winners, &staked) }) .map_err(From::from) } diff --git a/frame/election-providers/src/two_phase/macros.rs b/frame/election-providers/src/two_phase/macros.rs index b34028155d22f..10fab69afec0f 100644 --- a/frame/election-providers/src/two_phase/macros.rs +++ b/frame/election-providers/src/two_phase/macros.rs @@ -51,16 +51,16 @@ macro_rules! target_index_fn { }; } -// TODO: these can use a cache. +// NOTE: these can use a cache. #[macro_export] macro_rules! stake_of_fn { ($voters:ident, $acc:ty) => { |who: &$acc| -> $crate::VoteWeight { - $voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - } + $voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + } }; } diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 349b89d0172b2..b0a48ea0041b9 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -1,7 +1,9 @@ use super::*; use frame_support::{parameter_types, traits::OnInitialize}; use sp_core::H256; -use sp_npos_elections::CompactSolution; +use sp_npos_elections::{ + seq_phragmen, to_without_backing, CompactSolution, ElectionResult, EvaluateSupport, +}; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, @@ -51,7 +53,6 @@ pub fn raw_solution() -> RawSolution> { let target_index = crate::target_index_fn!(targets, AccountId, Runtime); let stake_of = crate::stake_of_fn!(voters, AccountId); - use sp_npos_elections::{seq_phragmen, to_without_backing, ElectionResult}; let ElectionResult { winners, assignments, @@ -61,10 +62,10 @@ pub fn raw_solution() -> RawSolution> { let winners = to_without_backing(winners); let score = { - // TODO: we really need to clean this process. let staked = sp_npos_elections::assignment_ratio_to_staked(assignments.clone(), &stake_of); - let support = sp_npos_elections::build_support_map(&winners, &staked).unwrap(); - sp_npos_elections::evaluate_support(&support) + sp_npos_elections::to_supports(&winners, &staked) + .unwrap() + .evaluate() }; let compact = >::from_assignment(assignments, &voter_index, &target_index).unwrap(); @@ -185,6 +186,7 @@ impl crate::two_phase::Trait for Runtime { type MaxSignedSubmissions = MaxSignedSubmissions; type SignedRewardBase = SignedRewardBase; type SignedRewardFactor = (); + type SignedRewardMax = (); type SignedDepositBase = SignedDepositBase; type SignedDepositByte = (); type SignedDepositWeight = (); diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index cfba0a68a6c9b..8704fc6b60632 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -105,8 +105,8 @@ //! use crate::{ - onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, FlatSupportMap, - FlattenSupportMap, + onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, FlattenSupportMap, + Supports, }; use codec::{Decode, Encode, HasCompact}; use frame_support::{ @@ -118,8 +118,8 @@ use frame_support::{ }; use frame_system::{ensure_none, ensure_signed}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, build_support_map, evaluate_support, Assignment, - CompactSolution, ElectionScore, ExtendedBalance, PerThing128, VoteWeight, + assignment_ratio_to_staked_normalized, Assignment, CompactSolution, ElectionScore, + EvaluateSupport, ExtendedBalance, PerThing128, VoteWeight, }; use sp_runtime::{traits::Zero, InnerOf, PerThing, Perbill, RuntimeDebug}; use sp_std::prelude::*; @@ -244,7 +244,7 @@ pub struct SignedSubmission { pub struct ReadySolution { /// The final supports of the solution. This is target-major vector, storing each winners, total /// backing, and each individual backer. - supports: FlatSupportMap, + supports: Supports, /// The score of the solution. /// /// This is needed to potentially challenge the solution. @@ -333,6 +333,7 @@ pub trait Trait: frame_system::Trait { // TODO: these need input from the research team type SignedRewardBase: Get>; type SignedRewardFactor: Get; + type SignedRewardMax: Get>>; type SignedDepositBase: Get>; type SignedDepositByte: Get>; type SignedDepositWeight: Get>; @@ -616,14 +617,11 @@ where let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) .map_err::(Into::into)?; // This might fail if one of the voter edges is pointing to a non-winner. - let supports = build_support_map(&winners, &staked_assignments) - .map(FlattenSupportMap::flatten) + let supports = sp_npos_elections::to_supports(&winners, &staked_assignments) .map_err::(Into::into)?; // Finally, check that the claimed score was indeed correct. - // TODO: well, I am not sure if this is now better or not... - let known_score = - evaluate_support::(supports.iter().map(|&(ref x, ref y)| (x, y))); + let known_score = supports.evaluate(); ensure!(known_score == score, FeasibilityError::InvalidScore); // let supports = supports.flatten(); @@ -635,7 +633,7 @@ where } /// On-chain fallback of election. - fn onchain_fallback() -> Result, Error> { + fn onchain_fallback() -> Result, Error> { let desired_targets = Self::desired_targets() as usize; let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; @@ -660,7 +658,7 @@ where _to_elect: usize, _targets: Vec, _voters: Vec<(T::AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, { diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 72d5612cd4f29..7f7b8dec46205 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -282,7 +282,7 @@ pub mod default_weights; pub mod inflation; use codec::{Decode, Encode, HasCompact}; -use frame_election_providers::{ElectionDataProvider, ElectionProvider, FlatSupportMap}; +use frame_election_providers::{ElectionDataProvider, ElectionProvider, Supports}; use frame_support::{ decl_error, decl_event, decl_module, decl_storage, dispatch::{DispatchResult, DispatchResultWithPostInfo}, @@ -2154,16 +2154,15 @@ impl Module { } // Set staking information for new era. - let maybe_new_validators = Self::select_and_update_validators(current_era); + let maybe_new_validators = Self::enact_election(current_era); maybe_new_validators } - /// Consume a set of [`Supports`] from [`sp_npos_elections`] and collect them into a [`Exposure`] + /// Consume a vectors of [`Supports`] ([`Supports`]) and collect them into a [`Exposure`]. fn collect_exposure( - supports: frame_election_providers::FlatSupportMap, + supports: Supports, ) -> Vec<(T::AccountId, Exposure>)> { - // TODO: maybe this can be abstracted with `From<>` let total_issuance = T::Currency::total_issuance(); let to_currency = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); @@ -2197,12 +2196,17 @@ impl Module { .collect::)>>() } - /// TODO: - /// TODO: use minimum_validator_count() + /// Process the output of the election. + /// + /// This ensures enough validators have been elected, converts all supports to exposures and + /// writes them to the associated storage. + /// + /// Returns `Err(())` if less than [`MinimumValidatorCount`] validators have been elected, `Ok` + /// otherwise. pub fn process_election( - flat_supports: FlatSupportMap, + flat_supports: Supports, current_era: EraIndex, - ) -> Vec { + ) -> Result, ()> { let exposures = Self::collect_exposure(flat_supports); let elected_stashes = exposures .iter() @@ -2210,6 +2214,15 @@ impl Module { .map(|(x, _)| x) .collect::>(); + if (elected_stashes.len() as u32) <= Self::minimum_validator_count() { + log!( + error, + "💸 Chain does not have enough staking candidates to operate for era {:?}", + current_era, + ); + return Err(()); + } + // Populate Stakers and write slot stake. let mut total_stake: BalanceOf = Zero::zero(); exposures.into_iter().for_each(|(stash, exposure)| { @@ -2246,11 +2259,13 @@ impl Module { current_era, ); - elected_stashes + Ok(elected_stashes) } - /// TODO: - fn select_and_update_validators(current_era: EraIndex) -> Option> { + /// Enact and process the election using the `ElectionProvider` type. + /// + /// This will also process the election, as noted in [`process_election`]. + fn enact_election(current_era: EraIndex) -> Option> { if T::ElectionProvider::NEEDS_ELECT_DATA { // This election will need the real data. T::ElectionProvider::elect::( @@ -2258,12 +2273,14 @@ impl Module { Self::get_npos_targets(), Self::get_npos_voters(), ) - .map(|flat_supports| Self::process_election(flat_supports, current_era)) + .map_err(|_| ()) + .and_then(|flat_supports| Self::process_election(flat_supports, current_era)) .ok() } else { // no need to fetch the params. T::ElectionProvider::elect::(0, vec![], vec![]) - .map(|flat_supports| Self::process_election(flat_supports, current_era)) + .map_err(|_| ()) + .and_then(|flat_supports| Self::process_election(flat_supports, current_era)) .ok() } } @@ -2354,10 +2371,14 @@ impl Module { /// Get all of the voters that are eligible for the npos election. /// - /// This will inject all validators as well as a self-vote. + /// This will use all on-chain nominators, and all the validators will inject a self vote. + /// + /// ### Slashing + /// + /// All nominations that have been submitted before the last non-zero slash of the validator are + /// auto-chilled. /// /// Note that this is VERY expensive. Use with care. - /// TODO: pub fn get_npos_voters() -> Vec<(T::AccountId, VoteWeight, Vec)> { let weight_of = Self::slashable_balance_of_fn(); let mut all_voters = Vec::new(); @@ -2412,9 +2433,7 @@ impl Module { } } -impl ElectionDataProvider - for Module -{ +impl ElectionDataProvider for Module { type CompactSolution = CompactU16Solution; fn desired_targets() -> u32 { @@ -2434,8 +2453,8 @@ impl ElectionDataProvider } fn feasibility_check_assignment( - who: &T::AccountId, - distribution: &[(T::AccountId, P)], + _who: &T::AccountId, + _distribution: &[(T::AccountId, P)], ) -> bool { // TODO true diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index b17e1d7a4f010..774c73ed4d05c 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -26,13 +26,10 @@ use frame_support::{ }; use sp_core::H256; use sp_io; -use sp_npos_elections::{ - build_support_map, evaluate_support, reduce, ExtendedBalance, StakedAssignment, ElectionScore, -}; use sp_runtime::{ curve::PiecewiseLinear, testing::{Header, TestXt, UintAuthorityId}, - traits::{IdentityLookup, Zero}, + traits::IdentityLookup, }; use sp_staking::offence::{OffenceDetails, OnOffenceHandler}; use std::{cell::RefCell, collections::HashSet}; @@ -50,9 +47,7 @@ thread_local! { static SESSION_PER_ERA: RefCell = RefCell::new(3); static EXISTENTIAL_DEPOSIT: RefCell = RefCell::new(0); static SLASH_DEFER_DURATION: RefCell = RefCell::new(0); - static ELECTION_LOOKAHEAD: RefCell = RefCell::new(0); static PERIOD: RefCell = RefCell::new(1); - static MAX_ITERATIONS: RefCell = RefCell::new(0); } /// Another session handler struct to test on_disabled. @@ -111,13 +106,6 @@ impl Get for SessionsPerEra { } } -pub struct ElectionLookahead; -impl Get for ElectionLookahead { - fn get() -> BlockNumber { - ELECTION_LOOKAHEAD.with(|v| *v.borrow()) - } -} - pub struct Period; impl Get for Period { fn get() -> BlockNumber { @@ -132,13 +120,6 @@ impl Get for SlashDeferDuration { } } -pub struct MaxIterations; -impl Get for MaxIterations { - fn get() -> u32 { - MAX_ITERATIONS.with(|v| *v.borrow()) - } -} - impl_outer_origin! { pub enum Origin for Test where system = frame_system {} } @@ -331,7 +312,6 @@ pub type Extrinsic = TestXt; pub struct ExtBuilder { session_length: BlockNumber, - election_lookahead: BlockNumber, session_per_era: SessionIndex, existential_deposit: Balance, validator_pool: bool, @@ -343,14 +323,12 @@ pub struct ExtBuilder { num_validators: Option, invulnerables: Vec, has_stakers: bool, - max_offchain_iterations: u32, } impl Default for ExtBuilder { fn default() -> Self { Self { session_length: 1, - election_lookahead: 0, session_per_era: 3, existential_deposit: 1, validator_pool: false, @@ -362,7 +340,6 @@ impl Default for ExtBuilder { num_validators: None, invulnerables: vec![], has_stakers: true, - max_offchain_iterations: 0, } } } @@ -404,14 +381,12 @@ impl ExtBuilder { self.invulnerables = invulnerables; self } + #[allow(dead_code)] pub fn session_per_era(mut self, length: SessionIndex) -> Self { self.session_per_era = length; self } - pub fn election_lookahead(mut self, look: BlockNumber) -> Self { - self.election_lookahead = look; - self - } + #[allow(dead_code)] pub fn session_length(mut self, length: BlockNumber) -> Self { self.session_length = length; self @@ -420,22 +395,11 @@ impl ExtBuilder { self.has_stakers = has; self } - pub fn max_offchain_iterations(mut self, iterations: u32) -> Self { - self.max_offchain_iterations = iterations; - self - } - pub fn offchain_election_ext(self) -> Self { - self.session_per_era(4) - .session_length(5) - .election_lookahead(3) - } pub fn set_associated_constants(&self) { EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit); SLASH_DEFER_DURATION.with(|v| *v.borrow_mut() = self.slash_defer_duration); SESSION_PER_ERA.with(|v| *v.borrow_mut() = self.session_per_era); - ELECTION_LOOKAHEAD.with(|v| *v.borrow_mut() = self.election_lookahead); PERIOD.with(|v| *v.borrow_mut() = self.session_length); - MAX_ITERATIONS.with(|v| *v.borrow_mut() = self.max_offchain_iterations); } pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); @@ -659,18 +623,6 @@ pub(crate) fn bond_nominator( assert_ok!(Staking::nominate(Origin::signed(ctrl), target)); } -pub(crate) fn run_to_block(n: BlockNumber) { - Staking::on_finalize(System::block_number()); - for b in System::block_number() + 1..=n { - System::set_block_number(b); - Session::on_initialize(b); - Staking::on_initialize(b); - if b != n { - Staking::on_finalize(System::block_number()); - } - } -} - pub(crate) fn advance_session() { let current_index = Session::current_index(); start_session(current_index + 1); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 8e72d17669b3c..c51da32abf3a3 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -18,16 +18,16 @@ //! Tests for the module. use super::*; -use mock::*; -use sp_runtime::{ - assert_eq_error_rate, traits::BadOrigin, -}; -use sp_staking::offence::OffenceDetails; use frame_support::{ - assert_ok, assert_noop, StorageMap, - traits::{Currency, ReservableCurrency, OnInitialize, OnFinalize}, + assert_noop, assert_ok, + traits::{Currency, OnInitialize, ReservableCurrency}, + StorageMap, }; +use mock::*; use pallet_balances::Error as BalancesError; +use sp_npos_elections::Support; +use sp_runtime::{assert_eq_error_rate, traits::BadOrigin}; +use sp_staking::offence::OffenceDetails; use substrate_test_utils::assert_eq_uvec; #[test] @@ -1723,6 +1723,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election() { .minimum_validator_count(1) .build() .execute_with(|| { + // disable the nominator assert_ok!(Staking::chill(Origin::signed(100))); // make stakes equal. @@ -1743,6 +1744,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election() { } assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); + // 11 should not be elected. All of these count as ONE vote. assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 11, 11, 21, 31,])); assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); @@ -1756,11 +1758,13 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election() { Staking::get_npos_voters(), ).unwrap(); - let winners = election_result.iter().map(|(x, _)| x).cloned().collect::>(); - assert_eq!(winners, vec![31, 21]); - // only distribution to 21 and 31. - // TODO: - // assert_eq!(assignments.iter().find(|a| a.who == 1).unwrap().distribution.len(), 2); + assert_eq_uvec!( + election_result, + vec![ + (21, Support:: { total: 1800, voters: vec![(21, 1000), (3, 400), (1, 400)] }), + (31, Support:: { total: 2200, voters: vec![(31, 1000), (3, 600), (1, 600)] }), + ] + ); }); } @@ -1805,11 +1809,13 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election_elected() { Staking::get_npos_voters(), ).unwrap(); - let winners = election_result.iter().map(|(x, _)| x).cloned().collect::>(); - assert_eq!(winners, vec![21, 11]); - // only distribution to 21 and 31. - // TODO: - // assert_eq!(assignments.iter().find(|a| a.who == 1).unwrap().distribution.len(), 2); + assert_eq_uvec!( + election_result, + vec![ + (21, Support:: { total: 2500, voters: vec![(21, 1000), (3, 1000), (1, 500)] }), + (11, Support:: { total: 1500, voters: vec![(11, 1000), (1, 500)] }), + ] + ); }); } @@ -1943,7 +1949,7 @@ fn reward_from_authorship_event_handler_works() { fn add_reward_points_fns_works() { ExtBuilder::default().build_and_execute(|| { // Not mandatory but must be coherent with rewards - assert_eq!(Session::validators(), vec![21, 11]); + assert_eq_uvec!(Session::validators(), vec![21, 11]); >::reward_by_ids(vec![ (21, 1), diff --git a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs index 67cc7ba3c9a9a..fbe16e2675941 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs @@ -21,12 +21,12 @@ mod common; use common::*; use honggfuzz::fuzz; +use rand::{self, SeedableRng}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, build_support_map, to_without_backing, VoteWeight, - evaluate_support, is_score_better, seq_phragmen, + assignment_ratio_to_staked_normalized, is_score_better, seq_phragmen, to_support_map, + to_without_backing, EvaluateSupport, VoteWeight, }; use sp_runtime::Perbill; -use rand::{self, SeedableRng}; fn main() { loop { @@ -66,11 +66,16 @@ fn main() { }; let unbalanced_score = { - let staked = assignment_ratio_to_staked_normalized(unbalanced.assignments.clone(), &stake_of).unwrap(); + let staked = assignment_ratio_to_staked_normalized( + unbalanced.assignments.clone(), + &stake_of, + ) + .unwrap(); let winners = to_without_backing(unbalanced.winners.clone()); - let support = build_support_map(winners.as_ref(), staked.as_ref()).unwrap(); + let score = to_support_map(winners.as_ref(), staked.as_ref()) + .unwrap() + .evaluate(); - let score = evaluate_support(&support); if score[0] == 0 { // such cases cannot be improved by balancing. return; @@ -89,9 +94,8 @@ fn main() { let balanced_score = { let staked = assignment_ratio_to_staked_normalized(balanced.assignments.clone(), &stake_of).unwrap(); let winners = to_without_backing(balanced.winners); - let support = build_support_map(winners.as_ref(), staked.as_ref()).unwrap(); + to_support_map(winners.as_ref(), staked.as_ref()).unwrap().evaluate() - evaluate_support(&support) }; let enhance = is_score_better(balanced_score, unbalanced_score, Perbill::zero()); diff --git a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs index f22eadb66b9d7..34acc8cf51d95 100644 --- a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs @@ -21,12 +21,12 @@ mod common; use common::*; use honggfuzz::fuzz; +use rand::{self, SeedableRng}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, build_support_map, to_without_backing, VoteWeight, - evaluate_support, is_score_better, phragmms, + assignment_ratio_to_staked_normalized, is_score_better, phragmms, to_support_map, + to_without_backing, EvaluateSupport, VoteWeight, }; use sp_runtime::Perbill; -use rand::{self, SeedableRng}; fn main() { loop { @@ -72,9 +72,8 @@ fn main() { ) .unwrap(); let winners = to_without_backing(unbalanced.winners.clone()); - let support = build_support_map(&winners, &staked).unwrap(); + let score = to_support_map(&winners, &staked).unwrap().evaluate(); - let score = evaluate_support(&support); if score[0] == 0 { // such cases cannot be improved by balancing. return; @@ -92,9 +91,7 @@ fn main() { let balanced_score = { let staked = assignment_ratio_to_staked_normalized(balanced.assignments.clone(), &stake_of).unwrap(); let winners = to_without_backing(balanced.winners); - let support = build_support_map(winners.as_ref(), staked.as_ref()).unwrap(); - - evaluate_support(&support) + let support = to_support_map(winners.as_ref(), staked.as_ref()).unwrap().evaluate() }; let enhance = is_score_better(balanced_score, unbalanced_score, Perbill::zero()); diff --git a/primitives/npos-elections/fuzzer/src/reduce.rs b/primitives/npos-elections/fuzzer/src/reduce.rs index 0f0d9893e048e..597a952db5145 100644 --- a/primitives/npos-elections/fuzzer/src/reduce.rs +++ b/primitives/npos-elections/fuzzer/src/reduce.rs @@ -34,8 +34,8 @@ use honggfuzz::fuzz; mod common; use common::to_range; -use sp_npos_elections::{StakedAssignment, ExtendedBalance, build_support_map, reduce}; -use rand::{self, Rng, SeedableRng, RngCore}; +use rand::{self, Rng, RngCore, SeedableRng}; +use sp_npos_elections::{reduce, to_support_map, ExtendedBalance, StakedAssignment}; type Balance = u128; type AccountId = u64; @@ -109,9 +109,8 @@ fn assert_assignments_equal( ass1: &Vec>, ass2: &Vec>, ) { - - let support_1 = build_support_map::(winners, ass1).unwrap(); - let support_2 = build_support_map::(winners, ass2).unwrap(); + let support_1 = to_support_map::(winners, ass1).unwrap(); + let support_2 = to_support_map::(winners, ass2).unwrap(); for (who, support) in support_1.iter() { assert_eq!(support.total, support_2.get(who).unwrap().total); diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 84c36ca88c6f9..7305d74638c09 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -541,52 +541,39 @@ pub struct Support { pub voters: Vec<(AccountId, ExtendedBalance)>, } -/// A linkage from a candidate and its [`Support`]. +/// A flat variant of [`SupportMap`]. +/// +/// The main advantage of this is that it is encodable. +pub type Supports = Vec<(A, Support)>; + +/// Linkage from a winner to their [`Support`]. pub type SupportMap = BTreeMap>; -/// Build the support map from the given election result. It maps a flat structure like -/// -/// ```nocompile -/// assignments: vec![ -/// voter1, vec![(candidate1, w11), (candidate2, w12)], -/// voter2, vec![(candidate1, w21), (candidate2, w22)] -/// ] -/// ``` -/// -/// into a mapping of candidates and their respective support: -/// -/// ```nocompile -/// SupportMap { -/// candidate1: Support { -/// own:0, -/// total: w11 + w21, -/// others: vec![(candidate1, w11), (candidate2, w21)] -/// }, -/// candidate2: Support { -/// own:0, -/// total: w12 + w22, -/// others: vec![(candidate1, w12), (candidate2, w22)] -/// }, -/// } -/// ``` -/// -/// The second returned flag indicates the number of edges who didn't corresponded to an actual -/// winner from the given winner set. A value in this place larger than 0 indicates a potentially -/// faulty assignment. +/// Helper trait to convert from a support map to a flat support vector. +pub trait FlattenSupportMap { + /// Flatten the support. + fn flatten(self) -> Supports; +} + +impl FlattenSupportMap for SupportMap { + fn flatten(self) -> Supports { + self.into_iter().map(|(k, v)| (k, v)).collect::>() + } +} + +/// Build the support map from the winners and assignments. /// -/// `O(E)` where `E` is the total number of edges. -pub fn build_support_map( - winners: &[AccountId], - assignments: &[StakedAssignment], -) -> Result, Error> -where - AccountId: IdentifierT, -{ +/// The list of winners is basically a redundancy; It basically ensures that all the targets pointed +/// to by the `assignments` are present in the `winners`. +pub fn to_support_map( + winners: &[A], + assignments: &[StakedAssignment], +) -> Result, Error> { // Initialize the support of each candidate. - let mut supports = >::new(); - winners - .iter() - .for_each(|e| { supports.insert(e.clone(), Default::default()); }); + let mut supports = >::new(); + winners.iter().for_each(|e| { + supports.insert(e.clone(), Default::default()); + }); // build support struct. for StakedAssignment { who, distribution } in assignments.iter() { @@ -602,34 +589,61 @@ where Ok(supports) } -/// Evaluate a support map. The returned tuple contains: -/// -/// - Minimum support. This value must be **maximized**. -/// - Sum of all supports. This value must be **maximized**. -/// - Sum of all supports squared. This value must be **minimized**. -/// -/// `O(E)` where `E` is the total number of edges. -pub fn evaluate_support< - 'a, - AccountId: 'a, - I: IntoIterator)>, ->( - support: I, -) -> ElectionScore { - let mut min_support = ExtendedBalance::max_value(); - let mut sum: ExtendedBalance = Zero::zero(); - // NOTE: The third element might saturate but fine for now since this will run on-chain and need - // to be fast. - let mut sum_squared: ExtendedBalance = Zero::zero(); - for (_, ref support) in support.into_iter() { - sum = sum.saturating_add(support.total); - let squared = support.total.saturating_mul(support.total); - sum_squared = sum_squared.saturating_add(squared); - if support.total < min_support { - min_support = support.total; +/// Same as [`to_support_map`] except it calls `FlattenSupportMap` on top of the result to return a +/// flat vector. +pub fn to_supports( + winners: &[A], + assignments: &[StakedAssignment], +) -> Result, Error> { + to_support_map(winners, assignments).map(FlattenSupportMap::flatten) +} + +/// Extension trait for evaluating a support map or vector. +pub trait EvaluateSupport { + /// Evaluate a support map. The returned tuple contains: + /// + /// - Minimum support. This value must be **maximized**. + /// - Sum of all supports. This value must be **maximized**. + /// - Sum of all supports squared. This value must be **minimized**. + fn evaluate(&self) -> ElectionScore; +} + +impl EvaluateSupport for SupportMap { + fn evaluate(&self) -> ElectionScore { + let mut min_support = ExtendedBalance::max_value(); + let mut sum: ExtendedBalance = Zero::zero(); + // NOTE: The third element might saturate but fine for now since this will run on-chain and + // need to be fast. + let mut sum_squared: ExtendedBalance = Zero::zero(); + for (_, ref support) in self.into_iter() { + sum = sum.saturating_add(support.total); + let squared = support.total.saturating_mul(support.total); + sum_squared = sum_squared.saturating_add(squared); + if support.total < min_support { + min_support = support.total; + } + } + [min_support, sum, sum_squared] + } +} + +impl EvaluateSupport for Supports { + fn evaluate(&self) -> ElectionScore { + let mut min_support = ExtendedBalance::max_value(); + let mut sum: ExtendedBalance = Zero::zero(); + // NOTE: The third element might saturate but fine for now since this will run on-chain and + // need to be fast. + let mut sum_squared: ExtendedBalance = Zero::zero(); + for (_, ref support) in self.into_iter() { + sum = sum.saturating_add(support.total); + let squared = support.total.saturating_mul(support.total); + sum_squared = sum_squared.saturating_add(squared); + if support.total < min_support { + min_support = support.total; + } } + [min_support, sum, sum_squared] } - [min_support, sum, sum_squared] } /// Compares two sets of election scores based on desirability and returns true if `this` is better diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index af42b11de41a3..c70c5ff579ee0 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -17,14 +17,12 @@ //! Tests for npos-elections. -use crate::mock::*; use crate::{ - seq_phragmen, balancing, build_support_map, is_score_better, helpers::*, - Support, StakedAssignment, Assignment, ElectionResult, ExtendedBalance, setup_inputs, - seq_phragmen_core, Voter, + balancing, helpers::*, is_score_better, mock::*, seq_phragmen, seq_phragmen_core, setup_inputs, + to_support_map, Assignment, ElectionResult, ExtendedBalance, StakedAssignment, Support, Voter, }; +use sp_arithmetic::{PerU16, Perbill, Percent, Permill}; use substrate_test_utils::assert_eq_uvec; -use sp_arithmetic::{Perbill, Permill, Percent, PerU16}; #[test] fn float_phragmen_poc_works() { @@ -49,11 +47,15 @@ fn float_phragmen_poc_works() { ] ); - let mut support_map = build_support_map_float(&mut phragmen_result, &stake_of); + let mut support_map = to_support_map_float(&mut phragmen_result, &stake_of); assert_eq!( support_map.get(&2).unwrap(), - &_Support { own: 0.0, total: 25.0, others: vec![(10u64, 10.0), (30u64, 15.0)]} + &_Support { + own: 0.0, + total: 25.0, + others: vec![(10u64, 10.0), (30u64, 15.0)] + } ); assert_eq!( support_map.get(&3).unwrap(), @@ -260,7 +262,7 @@ fn phragmen_poc_works() { let staked = assignment_ratio_to_staked(assignments, &stake_of); let winners = to_without_backing(winners); - let support_map = build_support_map::(&winners, &staked).unwrap(); + let support_map = to_support_map::(&winners, &staked).unwrap(); assert_eq_uvec!( staked, @@ -334,7 +336,7 @@ fn phragmen_poc_works_with_balancing() { let staked = assignment_ratio_to_staked(assignments, &stake_of); let winners = to_without_backing(winners); - let support_map = build_support_map::(&winners, &staked).unwrap(); + let support_map = to_support_map::(&winners, &staked).unwrap(); assert_eq_uvec!( staked, @@ -726,7 +728,7 @@ fn phragmen_self_votes_should_be_kept() { let staked_assignments = assignment_ratio_to_staked(result.assignments, &stake_of); let winners = to_without_backing(result.winners); - let supports = build_support_map::(&winners, &staked_assignments).unwrap(); + let supports = to_support_map::(&winners, &staked_assignments).unwrap(); assert_eq!(supports.get(&5u64), None); assert_eq!( From 218db10e544c6ef6d0719067fa8320b28c418727 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 15 Oct 2020 16:26:32 +0200 Subject: [PATCH 11/62] Unsigned almost done, primitive crate added. --- Cargo.lock | 12 + Cargo.toml | 1 + frame/election-providers/Cargo.toml | 3 + frame/election-providers/src/lib.rs | 106 +-- frame/election-providers/src/onchain.rs | 6 +- .../src/two_phase/benchmarking.rs | 0 .../src/two_phase/macros.rs | 53 +- .../election-providers/src/two_phase/mock.rs | 82 +- frame/election-providers/src/two_phase/mod.rs | 128 +-- .../src/two_phase/unsigned.rs | 746 +++++++++++++++++- frame/staking/src/tests.rs | 22 +- primitives/election-providers/Cargo.toml | 28 + primitives/election-providers/src/lib.rs | 120 +++ primitives/npos-elections/src/lib.rs | 43 +- primitives/npos-elections/src/mock.rs | 11 +- primitives/npos-elections/src/tests.rs | 2 +- 16 files changed, 1136 insertions(+), 227 deletions(-) create mode 100644 frame/election-providers/src/two_phase/benchmarking.rs create mode 100644 primitives/election-providers/Cargo.toml create mode 100644 primitives/election-providers/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 6944d21e40946..f38d5118eccd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1557,10 +1557,12 @@ dependencies = [ "hex-literal", "pallet-balances", "parity-scale-codec", + "parking_lot 0.11.0", "paste 1.0.1", "serde", "sp-arithmetic", "sp-core", + "sp-election-providers", "sp-io", "sp-npos-elections", "sp-runtime", @@ -8130,6 +8132,16 @@ dependencies = [ "syn", ] +[[package]] +name = "sp-election-providers" +version = "2.0.0" +dependencies = [ + "parity-scale-codec", + "sp-arithmetic", + "sp-npos-elections", + "sp-std", +] + [[package]] name = "sp-externalities" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index 075ae31b1e7bd..476d56bc8996c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -133,6 +133,7 @@ members = [ "primitives/database", "primitives/debug-derive", "primitives/storage", + "primitives/election-providers", "primitives/externalities", "primitives/finality-tracker", "primitives/finality-grandpa", diff --git a/frame/election-providers/Cargo.toml b/frame/election-providers/Cargo.toml index b7be30e133f9e..deb28743e9273 100644 --- a/frame/election-providers/Cargo.toml +++ b/frame/election-providers/Cargo.toml @@ -25,6 +25,7 @@ frame-system = { version = "2.0.0-rc6", default-features = false, path = "../sys sp-npos-elections = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/npos-elections" } sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } sp-arithmetic = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/arithmetic" } +sp-election-providers = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/election-providers" } [dev-dependencies] sp-io = { version = "2.0.0", path = "../../primitives/io" } @@ -33,6 +34,7 @@ pallet-balances = { version = "2.0.0", path = "../balances" } sp-core = { version = "2.0.0", path = "../../primitives/core" } paste = "1.0.1" substrate-test-utils = { version = "2.0.0", path = "../../test-utils" } +parking_lot = "0.11.0" [features] default = ["std"] @@ -44,4 +46,5 @@ std = [ "sp-npos-elections/std", "frame-system/std", "sp-std/std", + "sp-election-providers/std" ] diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs index b9e4523248d3b..cd81ef5b3d59a 100644 --- a/frame/election-providers/src/lib.rs +++ b/frame/election-providers/src/lib.rs @@ -15,11 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Reusable Election Providers. -//! -//! The core functionality of this crate is around [`ElectionProvider`]. An election provider is a -//! struct, module, or anything else that implements [`ElectionProvider`]. Such types can then be -//! passed around to other crates and pallets that need election functionality. +//! Various implementation for `ElectionProvider`. //! //! Two main election providers are implemented in this crate. //! @@ -31,111 +27,17 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_std::{fmt::Debug, prelude::*}; - /// The onchain module. pub mod onchain; /// The two-phase module. pub mod two_phase; -use sp_arithmetic::PerThing; -use sp_npos_elections::{ - CompactSolution, ExtendedBalance, FlattenSupportMap, PerThing128, Support, SupportMap, Supports, -}; +const LOG_TARGET: &'static str = "election-provider"; // for the helper macros #[doc(hidden)] pub use sp_npos_elections::VoteWeight; #[doc(hidden)] +use sp_runtime::traits::UniqueSaturatedInto; +#[doc(hidden)] pub use sp_std::convert::TryInto; - -/// Something that can provide the data to something else that implements [`ElectionProvider`], such -/// as the [`two_phase`] module. -/// -/// The underlying purpose of this is to provide auxillary data to long-lasting election providers. -/// For example, the [`two_phase`] election provider needs to know the voters/targets list well in -/// advance and before a call to [`ElectionProvider::elect`]. -/// -/// For example, if pallet A wants to use the two-phase election: -/// -/// ```rust,ignore -/// pub trait TraitA { -/// type ElectionProvider: ElectionProvider<_, _>; -/// } -/// -/// // these function will be called by `Self::ElectionProvider` whenever needed. -/// impl ElectionDataProvider for PalletA { /* .. */ } -/// -/// impl Module { -/// fn do_election() { -/// // finalize the election. -/// T::ElectionProvider::elect( /* .. */ ); -/// } -/// } -/// ``` -pub trait ElectionDataProvider { - /// The compact solution type. - /// - /// This should encode the entire solution with the least possible space usage. - type CompactSolution: codec::Codec + Default + PartialEq + Eq + Clone + Debug + CompactSolution; - - /// All possible targets for the election, i.e. the candidates. - fn targets() -> Vec; - - /// All possible voters for the election. - /// - /// Note that if a notion of self-vote exists, it should be represented here. - fn voters() -> Vec<(AccountId, VoteWeight, Vec)>; - - /// The number of targets to elect. - fn desired_targets() -> u32; - - /// Check the feasibility of a single assignment for the underlying `ElectionProvider`. In other - /// words, check if `who` having a weight distribution described as `distribution` is correct or - /// not. - /// - /// This might be called by the [`ElectionProvider`] upon processing solutions. - fn feasibility_check_assignment( - who: &AccountId, - distribution: &[(AccountId, P)], - ) -> bool; - - /// Provide a best effort prediction about when the next election is about to happen. - /// - /// In essence, `Self` should predict with this function when it will trigger the - /// `ElectionDataProvider::elect`. - fn next_election_prediction(now: B) -> B; -} - -/// Something that can compute the result of an election and pass it back to the caller. -pub trait ElectionProvider { - /// Indicate weather this election provider needs data when calling [`elect`] or not. If - /// `false`, then the call site can ignore all parameters of [`elect`] - const NEEDS_ELECT_DATA: bool; - - /// The error type that is returned by the provider. - type Error; - - /// Elect a new set of winners. - /// - /// The result is returned in a target major format, namely as a support map. - /// - /// Note that based on the logic of the type that will implement this trait, the input data may - /// or may not be used. To hint about this to the call site, [`NEEDS_ELECT_DATA`] should be - /// properly set. - /// - /// The implementation should, if possible, use the accuracy `P` to compute the election result. - fn elect( - to_elect: usize, - targets: Vec, - voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>; - - /// Returns true if an election is still ongoing. - /// - /// This can be used by the call site to dynamically check of a long-lasting election (such as - /// [`two_phase`]) is still on-going or not. - fn ongoing() -> bool; -} diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs index f84f3582a9c22..a7391652d7e6e 100644 --- a/frame/election-providers/src/onchain.rs +++ b/frame/election-providers/src/onchain.rs @@ -1,6 +1,8 @@ -use crate::{ElectionProvider, FlattenSupportMap, Supports}; use sp_arithmetic::PerThing; -use sp_npos_elections::{ElectionResult, ExtendedBalance, IdentifierT, PerThing128, VoteWeight}; +use sp_election_providers::ElectionProvider; +use sp_npos_elections::{ + ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Supports, VoteWeight, +}; use sp_runtime::RuntimeDebug; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/frame/election-providers/src/two_phase/macros.rs b/frame/election-providers/src/two_phase/macros.rs index 10fab69afec0f..e6daafcb99e60 100644 --- a/frame/election-providers/src/two_phase/macros.rs +++ b/frame/election-providers/src/two_phase/macros.rs @@ -30,12 +30,12 @@ macro_rules! log { #[macro_export] macro_rules! voter_index_fn { ($voters:ident, $acc:ty, $t:ident) => { - |who: &$acc| -> Option<$crate::two_phase::CompactVoterIndexOf<$t>> { - $voters - .iter() - .position(|(x, _, _)| x == who) - .and_then(|i| >>::try_into(i).ok()) - } + |who: &$acc| -> Option<$crate::two_phase::CompactVoterIndexOf<$t>> { + $voters + .iter() + .position(|(x, _, _)| x == who) + .and_then(|i| >>::try_into(i).ok()) + } }; } @@ -51,16 +51,45 @@ macro_rules! target_index_fn { }; } +#[macro_export] +macro_rules! voter_at_fn { + ($snap:ident, $acc:ty, $t:ident) => { + |i: $crate::two_phase::CompactVoterIndexOf<$t>| -> Option<$acc> { + <$crate::two_phase::CompactVoterIndexOf<$t> as $crate::TryInto>::try_into(i) + .ok() + .and_then(|i| $snap + .get(i) + .map(|(x, _, _)| x) + .cloned() + ) + } + }; +} + +#[macro_export] +macro_rules! target_at_fn { + ($snap:ident, $acc:ty, $t:ident) => { + |i: $crate::two_phase::CompactTargetIndexOf<$t>| -> Option<$acc> { + <$crate::two_phase::CompactTargetIndexOf<$t> as $crate::TryInto>::try_into(i) + .ok() + .and_then(|i| $snap + .get(i) + .cloned() + ) + }; + }; +} + // NOTE: these can use a cache. #[macro_export] macro_rules! stake_of_fn { ($voters:ident, $acc:ty) => { |who: &$acc| -> $crate::VoteWeight { - $voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - } + $voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + } }; } diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index b0a48ea0041b9..cc6d021f788d2 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -1,6 +1,14 @@ use super::*; use frame_support::{parameter_types, traits::OnInitialize}; -use sp_core::H256; +use parking_lot::RwLock; +use sp_core::{ + offchain::{ + testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, + OffchainExt, TransactionPoolExt, + }, + H256, +}; +use sp_election_providers::ElectionDataProvider; use sp_npos_elections::{ seq_phragmen, to_without_backing, CompactSolution, ElectionResult, EvaluateSupport, }; @@ -9,7 +17,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, PerU16, }; -use std::cell::RefCell; +use std::{cell::RefCell}; pub use frame_support::{assert_noop, assert_ok}; @@ -73,6 +81,12 @@ pub fn raw_solution() -> RawSolution> { RawSolution { compact, score } } +frame_support::impl_outer_dispatch! { + pub enum OuterCall for Runtime where origin: Origin { + two_phase::TwoPhase, + } +} + frame_support::impl_outer_origin! { pub enum Origin for Runtime where system = frame_system {} } @@ -82,7 +96,7 @@ impl frame_system::Trait for Runtime { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = (); + type Call = OuterCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = AccountId; @@ -176,6 +190,9 @@ parameter_types_thread_local! { static DESIRED_TARGETS: u32 = 2; static SIGNED_DEPOSIT_BASE: Balance = 5; static SIGNED_REWARD_BASE: Balance = 7; + static MAX_UNSIGNED_ITERATIONS: u32 = 5; + static UNSIGNED_PRIORITY: u64 = 100; + static SOLUTION_IMPROVEMENT_THRESHOLD: Perbill = Perbill::zero(); } impl crate::two_phase::Trait for Runtime { @@ -190,28 +207,26 @@ impl crate::two_phase::Trait for Runtime { type SignedDepositBase = SignedDepositBase; type SignedDepositByte = (); type SignedDepositWeight = (); - type SolutionImprovementThreshold = (); + type SolutionImprovementThreshold = SolutionImprovementThreshold; type SlashHandler = (); type RewardHandler = (); + type UnsignedMaxIterations = MaxUnsignedIterations; + type UnsignedCall = (); + type UnsignedPriority = UnsignedPriority; type ElectionDataProvider = StakingMock; type WeightInfo = (); } -pub struct ExtBuilder { - max_signed_submissions: u32, -} +pub struct ExtBuilder {} impl Default for ExtBuilder { fn default() -> Self { - Self { - max_signed_submissions: MaxSignedSubmissions::get(), - } + Self {} } } pub struct StakingMock; - -impl crate::ElectionDataProvider for StakingMock { +impl ElectionDataProvider for StakingMock { type CompactSolution = TestCompact; fn targets() -> Vec { @@ -232,15 +247,27 @@ impl crate::ElectionDataProvider for StakingMock { } impl ExtBuilder { - fn set_constants(&self) { - MAX_SIGNED_SUBMISSIONS.with(|v| *v.borrow_mut() = self.max_signed_submissions) + pub fn max_signed_submission(self, count: u32) -> Self { + MAX_SIGNED_SUBMISSIONS.with(|v| *v.borrow_mut() = count); + self } - pub(crate) fn max_signed_submission(mut self, count: u32) -> Self { - self.max_signed_submissions = count; + pub fn unsigned_priority(self, p: u64) -> Self { + UNSIGNED_PRIORITY.with(|v| *v.borrow_mut() = p); self } - pub fn build_and_execute(self, test: impl FnOnce() -> ()) { - self.set_constants(); + pub fn solution_improvement_threshold(self, p: Perbill) -> Self { + SOLUTION_IMPROVEMENT_THRESHOLD.with(|v| *v.borrow_mut() = p); + self + } + pub fn desired_targets(self, t: u32) -> Self { + DESIRED_TARGETS.with(|v| *v.borrow_mut() = t); + self + } + pub fn add_voter(self, who: AccountId, stake: Balance, targets: Vec) -> Self { + VOTERS.with(|v| v.borrow_mut().push((who, stake, targets))); + self + } + pub fn build(self) -> sp_io::TestExternalities { let mut storage = frame_system::GenesisConfig::default() .build_storage::() .unwrap(); @@ -255,6 +282,23 @@ impl ExtBuilder { } .assimilate_storage(&mut storage); - sp_io::TestExternalities::from(storage).execute_with(test) + sp_io::TestExternalities::from(storage) + } + pub fn build_offchainify(self, iters: u32) -> sp_io::TestExternalities { + let mut ext = self.build(); + let (offchain, offchain_state) = TestOffchainExt::new(); + let (pool, _pool_state) = TestTransactionPoolExt::new(); + + let mut seed = [0_u8; 32]; + seed[0..4].copy_from_slice(&iters.to_le_bytes()); + offchain_state.write().seed = seed; + + ext.register_extension(OffchainExt::new(offchain)); + ext.register_extension(TransactionPoolExt::new(pool)); + + ext + } + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(test) } } diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 8704fc6b60632..33bd6cc1f9b78 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -104,24 +104,25 @@ //! TODO //! -use crate::{ - onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, FlattenSupportMap, - Supports, -}; +use crate::onchain::OnChainSequentialPhragmen; use codec::{Decode, Encode, HasCompact}; use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, - dispatch::DispatchResultWithPostInfo, + decl_event, decl_module, decl_storage, + dispatch::{DispatchResultWithPostInfo, Dispatchable}, ensure, traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, weights::Weight, }; use frame_system::{ensure_none, ensure_signed}; +use sp_election_providers::{ElectionDataProvider, ElectionProvider}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, Assignment, CompactSolution, ElectionScore, - EvaluateSupport, ExtendedBalance, PerThing128, VoteWeight, + assignment_ratio_to_staked_normalized, is_score_better, Assignment, CompactSolution, + ElectionScore, EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, +}; +use sp_runtime::{ + traits::Zero, transaction_validity::TransactionPriority, InnerOf, PerThing, Perbill, + RuntimeDebug, }; -use sp_runtime::{traits::Zero, InnerOf, PerThing, Perbill, RuntimeDebug}; use sp_std::prelude::*; #[cfg(test)] @@ -154,26 +155,24 @@ type PositiveImbalanceOf = type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; -const LOG_TARGET: &'static str = "two-phase-submission"; - /// Current phase of the pallet. #[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] -pub enum Phase { +pub enum Phase { /// Nothing, the election is not happening. Off, /// Signed phase is open. Signed, /// Unsigned phase is open. - Unsigned(bool), + Unsigned((bool, Bn)), } -impl Default for Phase { +impl Default for Phase { fn default() -> Self { Phase::Off } } -impl Phase { +impl Phase { /// Weather the phase is signed or not. pub fn is_signed(&self) -> bool { matches!(self, Phase::Signed) @@ -184,9 +183,14 @@ impl Phase { matches!(self, Phase::Unsigned(_)) } + /// Weather the phase is unsigned and open or not, with specific start. + pub fn is_unsigned_open_at(&self, at: Bn) -> bool { + matches!(self, Phase::Unsigned((true, real)) if *real == at) + } + /// Weather the phase is unsigned and open or not. pub fn is_unsigned_open(&self) -> bool { - matches!(self, Phase::Unsigned(true)) + matches!(self, Phase::Unsigned((true, _))) } /// Weather the phase is off or not. @@ -260,6 +264,8 @@ pub enum Error { Feasibility(FeasibilityError), /// An error in the on-chain fallback. OnChainFallback(crate::onchain::Error), + /// An internal error in the NPoS elections crate. + NposElections(sp_npos_elections::Error), /// Snapshot data was unavailable unexpectedly. SnapshotUnAvailable, } @@ -270,6 +276,12 @@ impl From for Error { } } +impl From for Error { + fn from(e: sp_npos_elections::Error) -> Self { + Error::NposElections(e) + } +} + /// Errors that can happen in the feasibility check. #[derive(RuntimeDebug, Eq, PartialEq)] pub enum FeasibilityError { @@ -341,6 +353,11 @@ pub trait Trait: frame_system::Trait { /// The minimum amount of improvement to the solution score that defines a solution as "better". type SolutionImprovementThreshold: Get; + type UnsignedMaxIterations: Get; + // TODO: + type UnsignedCall: Dispatchable + Clone; + type UnsignedPriority: Get; + /// Handler for the slashed deposits. type SlashHandler: OnUnbalanced>; /// Handler for the rewards. @@ -356,7 +373,7 @@ pub trait Trait: frame_system::Trait { decl_storage! { trait Store for Module as TwoPhaseElectionProvider where ExtendedBalance: From>> { /// Current phase. - pub CurrentPhase get(fn current_phase): Phase = Phase::Off; + pub CurrentPhase get(fn current_phase): Phase = Phase::Off; /// Sorted (worse -> best) list of unchecked, signed solutions. pub SignedSubmissions get(fn signed_submissions): Vec, CompactOf>>; @@ -430,13 +447,15 @@ decl_module! { match Self::current_phase() { Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { // check only for the signed phase. - CurrentPhase::put(Phase::Signed); + >::put(Phase::Signed); Self::start_signed_phase(); + log!(info, "Starting signed phase at #{}", now); }, Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { // check the unsigned phase. let found_solution = Self::finalize_signed_phase(); - CurrentPhase::put(Phase::Unsigned(!found_solution)); + >::put(Phase::Unsigned((!found_solution, now))); + log!(info, "Starting unsigned phase at #{}", now); }, _ => { // Nothing. We wait in the unsigned phase until we receive the call to `elect`. @@ -446,7 +465,17 @@ decl_module! { Default::default() } - fn offchain_worker(n: T::BlockNumber) {} + fn offchain_worker(n: T::BlockNumber) { + // We only run the OCW in the fist block of the unsigned phase. + if + Self::set_check_offchain_execution_status(n).is_ok() && + Self::current_phase().is_unsigned_open_at(n) + { + let _ = Self::mine_and_submit().map_err(|e| { + log!(error, "error while submitting transaction in OCW: {:?}", e) + }); + } + } /// Submit a solution for the signed phase. /// @@ -500,23 +529,10 @@ decl_module! { fn submit_unsigned(origin, solution: RawSolution>) { ensure_none(origin)?; - // ensure solution is timely. Don't panic yet. This is a cheap check. - ensure!(Self::current_phase().is_signed(), "EarlySubmission"); - - use sp_npos_elections::is_score_better; - // ensure score is being improved. Panic henceforth. - assert!( - Self::queued_solution().map_or( - true, - |q: ReadySolution<_>| - is_score_better::( - solution.score, - q.score, - T::SolutionImprovementThreshold::get() - ) - ), - "WeakSolution" - ); + // check phase and score. + // TODO: since we do this in pre-dispatch, we can just ignore it + // here. + let _ = Self::pre_dispatch_checks(&solution)?; let ready = Self::feasibility_check(solution, ElectionCompute::Unsigned) @@ -566,16 +582,8 @@ where let snapshot_targets = Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - use sp_runtime::traits::UniqueSaturatedInto; - let voter_at = |i: CompactVoterIndexOf| -> Option { - snapshot_voters - .get(i.unique_saturated_into()) - .map(|(x, _, _)| x) - .cloned() - }; - let target_at = |i: CompactTargetIndexOf| -> Option { - snapshot_targets.get(i.unique_saturated_into()).cloned() - }; + let voter_at = crate::voter_at_fn!(snapshot_voters, T::AccountId, T); + let target_at = crate::target_at_fn!(snapshot_targets, T::AccountId, T); // first, make sure that all the winners are sane. let winners = winners @@ -646,13 +654,12 @@ where } } -impl crate::ElectionProvider for Module +impl ElectionProvider for Module where ExtendedBalance: From>>, { - type Error = Error; - const NEEDS_ELECT_DATA: bool = false; + type Error = Error; fn elect( _to_elect: usize, @@ -673,16 +680,18 @@ where ) .map(|(supports, compute)| { // reset phase. - CurrentPhase::put(Phase::Off); + >::put(Phase::Off); // clear snapshots. >::kill(); >::kill(); Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); + log!(info, "Finalized election round with compute {:?}.", compute); supports }) .map_err(|err| { Self::deposit_event(RawEvent::ElectionFinalized(None)); + log!(error, "Failed to finalize election round. Error = {:?}", err); err }) } @@ -695,7 +704,7 @@ where #[cfg(test)] mod tests { use super::{mock::*, *}; - use crate::ElectionProvider; + use sp_election_providers::ElectionProvider; use sp_npos_elections::Support; #[test] @@ -721,20 +730,20 @@ mod tests { assert!(TwoPhase::snapshot_voters().is_some()); roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned(true)); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); assert!(TwoPhase::snapshot_voters().is_some()); roll_to(19); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned(true)); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); assert!(TwoPhase::snapshot_voters().is_some()); roll_to(20); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned(true)); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); assert!(TwoPhase::snapshot_voters().is_some()); // we close when upstream tells us to elect. roll_to(21); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned(true)); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); assert!(TwoPhase::snapshot_voters().is_some()); TwoPhase::elect::(2, Default::default(), Default::default()) @@ -751,7 +760,7 @@ mod tests { assert_eq!(TwoPhase::current_phase(), Phase::Signed); roll_to(20); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned(true)); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); // zilch solutions thus far. let supports = @@ -778,9 +787,4 @@ mod tests { ) }) } - - #[test] - fn can_only_submit_threshold_better() { - unimplemented!() - } } diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 2fae4c043cbb2..66fd8fc6d0e3e 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -18,14 +18,750 @@ //! The unsigned phase implementation. use crate::two_phase::*; -use codec::Encode; -use sp_arithmetic::traits::SaturatedConversion; -use sp_npos_elections::is_score_better; -use sp_runtime::Perbill; +use frame_support::{dispatch::DispatchResult, unsigned::ValidateUnsigned}; +use sp_npos_elections::{seq_phragmen, CompactSolution, ElectionResult}; +use sp_runtime::{ + traits::TrailingZeroInput, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, + ValidTransaction, + }, + PerU16, SaturatedConversion, +}; +use sp_std::cmp::Ordering; -impl Module where ExtendedBalance: From>> {} +/// Witness data about the size of the election. +/// +/// This is needed for proper weight calculation. +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, Default)] +pub struct WitnessData { + /// Number of all voters. + /// + /// This must match the on-chain snapshot. + #[codec(compact)] + voters: u32, + /// Number of all targets. + /// + /// This must match the on-chain snapshot. + #[codec(compact)] + target: u32, +} + +/// Storage key used to store the persistent offchain worker status. +pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; +/// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice +/// within a window of 5 blocks. +pub(crate) const OFFCHAIN_REPEAT: u32 = 5; +/// Default number of blocks for which the unsigned transaction should stay in the pool +pub(crate) const DEFAULT_LONGEVITY: u64 = 25; + +impl Module +where + ExtendedBalance: From>>, +{ + /// Min a new npos solution. + pub fn mine_solution(iters: usize) -> Result>, Error> { + let desired_targets = Self::desired_targets() as usize; + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + + seq_phragmen::<_, CompactAccuracyOf>(desired_targets, targets, voters, Some((iters, 0))) + .map_err(Into::into) + .and_then(Self::prepare_election_result) + } + + /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which + /// is ready to be submitted to the chain. + /// + /// Will always reduce the solution as well. + pub fn prepare_election_result( + election_result: ElectionResult>, + ) -> Result>, Error> { + // storage items. + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + + // closures. + let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); + let target_index = crate::target_index_fn!(targets, T::AccountId, T); + let voter_at = crate::voter_at_fn!(voters, T::AccountId, T); + let target_at = crate::target_at_fn!(targets, T::AccountId, T); + let stake_of = crate::stake_of_fn!(voters, T::AccountId); + + let ElectionResult { + assignments, + winners, + } = election_result; + + // convert to staked and reduce. + let mut staked = + sp_npos_elections::assignment_ratio_to_staked_normalized(assignments, &stake_of) + .map_err::(Into::into)?; + sp_npos_elections::reduce(&mut staked); + + // convert back to ration and make compact. + let ratio = sp_npos_elections::assignment_staked_to_ratio_normalized(staked)?; + let compact = >::from_assignment(ratio, &voter_index, &target_index)?; + + // TODO + let maximum_allowed_voters = + Self::maximum_compact_len::(0, Default::default(), 0); + let compact = Self::trim_compact(compact.len() as u32, compact, &voter_index)?; + + // re-calc score. + let winners = sp_npos_elections::to_without_backing(winners); + let score = compact + .clone() + .score(&winners, stake_of, voter_at, target_at)?; + + Ok(RawSolution { compact, score }) + } + + /// Get a random number of iterations to run the balancing in the OCW. + /// + /// Uses the offchain seed to generate a random number, maxed with `T::UnsignedMaxIterations`. + pub fn get_balancing_iters() -> usize { + match T::UnsignedMaxIterations::get() { + 0 => 0, + max @ _ => { + let seed = sp_io::offchain::random_seed(); + let random = ::decode(&mut TrailingZeroInput::new(seed.as_ref())) + .expect("input is padded with zeroes; qed") + % max.saturating_add(1); + random as usize + } + } + } + + /// Greedily reduce the size of the a solution to fit into the block, w.r.t. weight. + /// + /// The weight of the solution is foremost a function of the number of voters (i.e. + /// `compact.len()`). Aside from this, the other components of the weight are invariant. The + /// number of winners shall not be changed (otherwise the solution is invalid) and the + /// `ElectionSize` is merely a representation of the total number of stakers. + /// + /// Thus, we reside to stripping away some voters. This means only changing the `compact` + /// struct. + /// + /// Note that the solution is already computed, and the winners are elected based on the merit + /// of teh entire stake in the system. Nonetheless, some of the voters will be removed further + /// down the line. + /// + /// Indeed, the score must be computed **after** this step. If this step reduces the score too + /// much, then the solution will be discarded. + pub fn trim_compact( + maximum_allowed_voters: u32, + mut compact: CompactOf, + nominator_index: FN, + ) -> Result, Error> + where + for<'r> FN: Fn(&'r T::AccountId) -> Option>, + { + match compact.len().checked_sub(maximum_allowed_voters as usize) { + Some(to_remove) if to_remove > 0 => { + // grab all voters and sort them by least stake. + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let mut voters_sorted = voters + .into_iter() + .map(|(who, stake, _)| (who.clone(), stake)) + .collect::>(); + voters_sorted.sort_by_key(|(_, y)| *y); + + // start removing from the least stake. Iterate until we know enough have been + // removed. + let mut removed = 0; + for (maybe_index, _stake) in voters_sorted + .iter() + .map(|(who, stake)| (nominator_index(&who), stake)) + { + let index = maybe_index.ok_or(Error::SnapshotUnAvailable)?; + if compact.remove_voter(index) { + removed += 1 + } + + if removed >= to_remove { + break; + } + } + + Ok(compact) + } + _ => { + // nada, return as-is + Ok(compact) + } + } + } + + /// Find the maximum `len` that a compact can have in order to fit into the block weight. + /// + /// This only returns a value between zero and `size.nominators`. + pub fn maximum_compact_len( + _winners_len: u32, + witness: WitnessData, + max_weight: Weight, + ) -> u32 { + if witness.voters < 1 { + return witness.voters; + } + + let max_voters = witness.voters.max(1); + let mut voters = max_voters; + + // helper closures. + let weight_with = |_voters: u32| -> Weight { W::submit_unsigned() }; + + let next_voters = |current_weight: Weight, voters: u32, step: u32| -> Result { + match current_weight.cmp(&max_weight) { + Ordering::Less => { + let next_voters = voters.checked_add(step); + match next_voters { + Some(voters) if voters < max_voters => Ok(voters), + _ => Err(()), + } + } + Ordering::Greater => voters.checked_sub(step).ok_or(()), + Ordering::Equal => Ok(voters), + } + }; + + // First binary-search the right amount of voters + let mut step = voters / 2; + let mut current_weight = weight_with(voters); + while step > 0 { + match next_voters(current_weight, voters, step) { + // proceed with the binary search + Ok(next) if next != voters => { + voters = next; + } + // we are out of bounds, break out of the loop. + Err(()) => { + break; + } + // we found the right value - early exit the function. + Ok(next) => return next, + } + step = step / 2; + current_weight = weight_with(voters); + } + + // Time to finish. We might have reduced less than expected due to rounding error. Increase + // one last time if we have any room left, the reduce until we are sure we are below limit. + while voters + 1 <= max_voters && weight_with(voters + 1) < max_weight { + voters += 1; + } + while voters.checked_sub(1).is_some() && weight_with(voters) > max_weight { + voters -= 1; + } + + debug_assert!( + weight_with(voters.min(witness.voters)) <= max_weight, + "weight_with({}) <= {}", + voters.min(witness.voters), + max_weight, + ); + voters.min(witness.voters) + } + + /// Checks if an execution of the offchain worker is permitted at the given block number, or not. + /// + /// This essentially makes sure that we don't run on previous blocks in case of a re-org, and we + /// don't run twice within a window of length [`OFFCHAIN_REPEAT`]. + /// + /// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise. + pub(crate) fn set_check_offchain_execution_status( + now: T::BlockNumber, + ) -> Result<(), &'static str> { + let storage = sp_runtime::offchain::storage::StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); + let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); + + let mutate_stat = + storage.mutate::<_, &'static str, _>(|maybe_head: Option>| { + match maybe_head { + Some(Some(head)) if now < head => Err("fork."), + Some(Some(head)) if now >= head && now <= head + threshold => { + Err("recently executed.") + } + Some(Some(head)) if now > head + threshold => { + // we can run again now. Write the new head. + Ok(now) + } + _ => { + // value doesn't exists. Probably this node just booted up. Write, and run + Ok(now) + } + } + }); + + match mutate_stat { + // all good + Ok(Ok(_)) => Ok(()), + // failed to write. + Ok(Err(_)) => Err("failed to write to offchain db."), + // fork etc. + Err(why) => Err(why), + } + } + + /// Mine a new solution, and submit it back to the chian as an unsigned transaction. + pub(crate) fn mine_and_submit() -> Result<(), Error> { + let balancing = Self::get_balancing_iters(); + Self::mine_solution(balancing).map(|raw_solution| { + // submit the raw solution to the pool. + () + }) + } + + pub(crate) fn pre_dispatch_checks(solution: &RawSolution>) -> DispatchResult { + // ensure solution is timely. Don't panic yet. This is a cheap check. + ensure!( + Self::current_phase().is_unsigned_open(), + "UnsignedPhaseClosed" + ); + + // ensure score is being improved. Panic henceforth. + ensure!( + Self::queued_solution().map_or(true, |q: ReadySolution<_>| is_score_better::( + solution.score, + q.score, + T::SolutionImprovementThreshold::get() + )), + "WeakSolution" + ); + + Ok(()) + } +} + +#[allow(deprecated)] +impl ValidateUnsigned for Module +where + ExtendedBalance: From>>, +{ + type Call = Call; + fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { + if let Call::submit_unsigned(solution) = call { + // discard solution not coming from the local OCW. + match source { + TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } + _ => { + return InvalidTransaction::Call.into(); + } + } + + if let Err(_why) = Self::pre_dispatch_checks(solution) { + return InvalidTransaction::Custom(99).into(); // TODO + } + + ValidTransaction::with_tag_prefix("OffchainElection") + // The higher the score[0], the better a solution is. + .priority( + T::UnsignedPriority::get().saturating_add(solution.score[0].saturated_into()), + ) + // TODO: need some provides to de-duplicate. + // TODO: we can do this better. + .longevity(DEFAULT_LONGEVITY) + // We don't propagate this. This can never the validated at a remote node. + .propagate(false) + .build() + } else { + InvalidTransaction::Call.into() + } + } + + fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { + if let Call::submit_unsigned(solution) = call { + Self::pre_dispatch_checks(solution).map_err(|_| InvalidTransaction::Custom(99).into()) + } else { + Err(InvalidTransaction::Call.into()) + } + } +} + +// #[cfg(test)] +// mod test { +// #![allow(unused_variables)] +// use super::*; +// use crate::ElectionSize; + +// struct Staking; + +// impl crate::WeightInfo for Staking { +// fn bond() -> Weight { +// unimplemented!() +// } +// fn bond_extra() -> Weight { +// unimplemented!() +// } +// fn unbond() -> Weight { +// unimplemented!() +// } +// fn withdraw_unbonded_update(s: u32) -> Weight { +// unimplemented!() +// } +// fn withdraw_unbonded_kill(s: u32) -> Weight { +// unimplemented!() +// } +// fn validate() -> Weight { +// unimplemented!() +// } +// fn nominate(n: u32) -> Weight { +// unimplemented!() +// } +// fn chill() -> Weight { +// unimplemented!() +// } +// fn set_payee() -> Weight { +// unimplemented!() +// } +// fn set_controller() -> Weight { +// unimplemented!() +// } +// fn set_validator_count() -> Weight { +// unimplemented!() +// } +// fn force_no_eras() -> Weight { +// unimplemented!() +// } +// fn force_new_era() -> Weight { +// unimplemented!() +// } +// fn force_new_era_always() -> Weight { +// unimplemented!() +// } +// fn set_invulnerables(v: u32) -> Weight { +// unimplemented!() +// } +// fn force_unstake(s: u32) -> Weight { +// unimplemented!() +// } +// fn cancel_deferred_slash(s: u32) -> Weight { +// unimplemented!() +// } +// fn payout_stakers_dead_controller(n: u32) -> Weight { +// unimplemented!() +// } +// fn payout_stakers_alive_staked(n: u32) -> Weight { +// unimplemented!() +// } +// fn rebond(l: u32) -> Weight { +// unimplemented!() +// } +// fn set_history_depth(e: u32) -> Weight { +// unimplemented!() +// } +// fn reap_stash(s: u32) -> Weight { +// unimplemented!() +// } +// fn new_era(v: u32, n: u32) -> Weight { +// unimplemented!() +// } +// fn submit_solution_better(v: u32, n: u32, a: u32, w: u32) -> Weight { +// (0 * v + 0 * n + 1000 * a + 0 * w) as Weight +// } +// } + +// #[test] +// fn find_max_voter_binary_search_works() { +// let size = ElectionSize { +// validators: 0, +// nominators: 10, +// }; + +// assert_eq!(maximum_compact_len::(0, size, 0), 0); +// assert_eq!(maximum_compact_len::(0, size, 1), 0); +// assert_eq!(maximum_compact_len::(0, size, 999), 0); +// assert_eq!(maximum_compact_len::(0, size, 1000), 1); +// assert_eq!(maximum_compact_len::(0, size, 1001), 1); +// assert_eq!(maximum_compact_len::(0, size, 1990), 1); +// assert_eq!(maximum_compact_len::(0, size, 1999), 1); +// assert_eq!(maximum_compact_len::(0, size, 2000), 2); +// assert_eq!(maximum_compact_len::(0, size, 2001), 2); +// assert_eq!(maximum_compact_len::(0, size, 2010), 2); +// assert_eq!(maximum_compact_len::(0, size, 2990), 2); +// assert_eq!(maximum_compact_len::(0, size, 2999), 2); +// assert_eq!(maximum_compact_len::(0, size, 3000), 3); +// assert_eq!(maximum_compact_len::(0, size, 3333), 3); +// assert_eq!(maximum_compact_len::(0, size, 5500), 5); +// assert_eq!(maximum_compact_len::(0, size, 7777), 7); +// assert_eq!(maximum_compact_len::(0, size, 9999), 9); +// assert_eq!(maximum_compact_len::(0, size, 10_000), 10); +// assert_eq!(maximum_compact_len::(0, size, 10_999), 10); +// assert_eq!(maximum_compact_len::(0, size, 11_000), 10); +// assert_eq!(maximum_compact_len::(0, size, 22_000), 10); + +// let size = ElectionSize { +// validators: 0, +// nominators: 1, +// }; + +// assert_eq!(maximum_compact_len::(0, size, 0), 0); +// assert_eq!(maximum_compact_len::(0, size, 1), 0); +// assert_eq!(maximum_compact_len::(0, size, 999), 0); +// assert_eq!(maximum_compact_len::(0, size, 1000), 1); +// assert_eq!(maximum_compact_len::(0, size, 1001), 1); +// assert_eq!(maximum_compact_len::(0, size, 1990), 1); +// assert_eq!(maximum_compact_len::(0, size, 1999), 1); +// assert_eq!(maximum_compact_len::(0, size, 2000), 1); +// assert_eq!(maximum_compact_len::(0, size, 2001), 1); +// assert_eq!(maximum_compact_len::(0, size, 2010), 1); +// assert_eq!(maximum_compact_len::(0, size, 3333), 1); + +// let size = ElectionSize { +// validators: 0, +// nominators: 2, +// }; + +// assert_eq!(maximum_compact_len::(0, size, 0), 0); +// assert_eq!(maximum_compact_len::(0, size, 1), 0); +// assert_eq!(maximum_compact_len::(0, size, 999), 0); +// assert_eq!(maximum_compact_len::(0, size, 1000), 1); +// assert_eq!(maximum_compact_len::(0, size, 1001), 1); +// assert_eq!(maximum_compact_len::(0, size, 1999), 1); +// assert_eq!(maximum_compact_len::(0, size, 2000), 2); +// assert_eq!(maximum_compact_len::(0, size, 2001), 2); +// assert_eq!(maximum_compact_len::(0, size, 2010), 2); +// assert_eq!(maximum_compact_len::(0, size, 3333), 2); +// } +// } #[cfg(test)] mod tests { use super::{mock::*, *}; + + #[test] + fn validate_unsigned_retracts_wrong_phase() { + ExtBuilder::default().build_and_execute(|| { + let solution = RawSolution:: { + score: [5, 0, 0], + ..Default::default() + }; + let call = Call::submit_unsigned(solution.clone()); + + // initial + assert_eq!(TwoPhase::current_phase(), Phase::Off); + matches!( + ::validate_unsigned(TransactionSource::Local, &call) + .unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) + ); + matches!( + ::pre_dispatch(&call).unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) + ); + + // signed + roll_to(5); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + matches!( + ::validate_unsigned(TransactionSource::Local, &call) + .unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) + ); + matches!( + ::pre_dispatch(&call).unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) + ); + + // unsigned + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + + assert!(::validate_unsigned( + TransactionSource::Local, + &call + ) + .is_ok()); + assert!(::pre_dispatch(&call).is_ok()); + }) + } + + #[test] + fn validate_unsigned_retracts_low_score() { + ExtBuilder::default().build_and_execute(|| { + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + + let solution = RawSolution:: { + score: [5, 0, 0], + ..Default::default() + }; + let call = Call::submit_unsigned(solution.clone()); + + // initial + assert!(::validate_unsigned( + TransactionSource::Local, + &call + ) + .is_ok()); + assert!(::pre_dispatch(&call).is_ok()); + + // set a better score + let ready = ReadySolution { + score: [10, 0, 0], + ..Default::default() + }; + >::put(ready); + + // won't work anymore. + matches!( + ::validate_unsigned(TransactionSource::Local, &call) + .unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) + ); + matches!( + ::pre_dispatch(&call).unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) + ); + }) + } + + #[test] + fn priority_is_set() { + ExtBuilder::default() + .unsigned_priority(20) + .build_and_execute(|| { + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + + let solution = RawSolution:: { + score: [5, 0, 0], + ..Default::default() + }; + let call = Call::submit_unsigned(solution.clone()); + + // initial + assert_eq!( + ::validate_unsigned( + TransactionSource::Local, + &call + ) + .unwrap() + .priority, + 25 + ); + }) + } + + #[test] + #[should_panic( + expected = "Invalid unsigned submission must produce invalid block and deprive \ + validator from their authoring reward.: FeasibilityError::WrongWinnerCount" + )] + fn invalid_solution_panics() { + ExtBuilder::default().build_and_execute(|| { + use frame_support::dispatch::Dispatchable; + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + + // This is in itself an invalid BS solution.. + let solution = RawSolution:: { + score: [5, 0, 0], + ..Default::default() + }; + let call = Call::submit_unsigned(solution.clone()); + let outer_call: OuterCall = call.into(); + let _ = outer_call.dispatch(Origin::none()); + }) + } + + #[test] + fn miner_works() { + ExtBuilder::default().build_and_execute(|| { + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + + // ensure we have snapshots in place. + assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot_targets().is_some()); + assert_eq!(TwoPhase::desired_targets(), 2); + + // mine seq_phragmen solution with 2 iters. + let solution = TwoPhase::mine_solution(2).unwrap(); + + // ensure this solution is valid. + assert!(TwoPhase::queued_solution().is_none()); + assert_ok!(TwoPhase::submit_unsigned(Origin::none(), solution)); + assert!(TwoPhase::queued_solution().is_some()); + }) + } + + #[test] + fn can_only_submit_threshold_better() { + ExtBuilder::default() + .desired_targets(1) + .add_voter(7, 2, vec![10]) + .add_voter(8, 5, vec![10]) + .solution_improvement_threshold(Perbill::from_percent(50)) + .build_and_execute(|| { + use sp_npos_elections::{Assignment, ElectionResult}; + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + assert_eq!(TwoPhase::desired_targets(), 1); + + // an initial solution + let result = ElectionResult { + // note: This second element of backing stake is not important here. + winners: vec![(10, 10)], + assignments: vec![Assignment { + who: 10, + distribution: vec![(10, PerU16::one())], + }], + }; + assert_ok!(TwoPhase::submit_unsigned( + Origin::none(), + TwoPhase::prepare_election_result(result).unwrap(), + )); + assert_eq!(TwoPhase::queued_solution().unwrap().score[0], 10); + + // trial 1: a solution who's score is only 2, i.e. 20% better in the first element. + let result = ElectionResult { + winners: vec![(10, 12)], + assignments: vec![ + Assignment { + who: 10, + distribution: vec![(10, PerU16::one())], + }, + Assignment { + who: 7, + // note: this percent doesn't even matter, in compact it is 100%. + distribution: vec![(10, PerU16::one())], + }, + ], + }; + let solution = TwoPhase::prepare_election_result(result).unwrap(); + // 12 is not 50% more than 10 + assert_eq!(solution.score[0], 12); + + assert_noop!( + TwoPhase::submit_unsigned(Origin::none(), solution), + "WeakSolution" + ); + + // trial 2: a solution who's score is only 7, i.e. 70% better in the first element. + let result = ElectionResult { + winners: vec![(10, 12)], + assignments: vec![ + Assignment { + who: 10, + distribution: vec![(10, PerU16::one())], + }, + Assignment { + who: 7, + distribution: vec![(10, PerU16::one())], + }, + Assignment { + who: 8, + // note: this percent doesn't even matter, in compact it is 100%. + distribution: vec![(10, PerU16::one())], + }, + ], + }; + let solution = TwoPhase::prepare_election_result(result).unwrap(); + assert_eq!(solution.score[0], 17); + + // and it is fine + assert_ok!(TwoPhase::submit_unsigned(Origin::none(), solution)); + }) + } } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index c51da32abf3a3..aadfe5185ac47 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2865,20 +2865,20 @@ fn remove_multi_deferred() { // bond_nominator(voter, 1000 + voter, 100, vec![21, 31, 41]); // } -// /// convert an externalities to one that can handle offchain worker tests. -// fn offchainify(ext: &mut TestExternalities, iterations: u32) -> Arc> { -// let (offchain, offchain_state) = TestOffchainExt::new(); -// let (pool, pool_state) = TestTransactionPoolExt::new(); +/// convert an externalities to one that can handle offchain worker tests. +// fn offchainify(ext: &mut TestExternalities, iterations: u32) -> Arc> { +// let (offchain, offchain_state) = TestOffchainExt::new(); +// let (pool, pool_state) = TestTransactionPoolExt::new(); -// let mut seed = [0_u8; 32]; -// seed[0..4].copy_from_slice(&iterations.to_le_bytes()); -// offchain_state.write().seed = seed; +// let mut seed = [0_u8; 32]; +// seed[0..4].copy_from_slice(&iterations.to_le_bytes()); +// offchain_state.write().seed = seed; -// ext.register_extension(OffchainExt::new(offchain)); -// ext.register_extension(TransactionPoolExt::new(pool)); +// ext.register_extension(OffchainExt::new(offchain)); +// ext.register_extension(TransactionPoolExt::new(pool)); -// pool_state -// } +// pool_state +// } // fn election_size() -> ElectionSize { // ElectionSize { diff --git a/primitives/election-providers/Cargo.toml b/primitives/election-providers/Cargo.toml new file mode 100644 index 0000000000000..bd889360776fa --- /dev/null +++ b/primitives/election-providers/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "sp-election-providers" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "Primitive election providers" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] } +sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } +sp-arithmetic = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/arithmetic" } +sp-npos-elections = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/npos-elections" } + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-std/std", + "sp-npos-elections/std", + "sp-arithmetic/std", +] diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs new file mode 100644 index 0000000000000..433291d14511f --- /dev/null +++ b/primitives/election-providers/src/lib.rs @@ -0,0 +1,120 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Primitive traits for providing election functionality. +//! +//! This crate provides two traits that could potentially be implemented by two struct. The struct +//! receiving the functionality election could potentially implement [`ElectionDataProvider`] and +//! the struct providing the election functionality implements [`ElectionProvider`]. + +#![cfg_attr(not(feature = "std"), no_std)] + +use sp_std::{fmt::Debug, prelude::*}; + +use sp_arithmetic::PerThing; +use sp_npos_elections::{CompactSolution, ExtendedBalance, PerThing128, Supports, VoteWeight}; + +/// Something that can provide the data to something else that implements [`ElectionProvider`], such +/// as the [`two_phase`] module. +/// +/// The underlying purpose of this is to provide auxillary data to long-lasting election providers. +/// For example, the [`two_phase`] election provider needs to know the voters/targets list well in +/// advance and before a call to [`ElectionProvider::elect`]. +/// +/// For example, if pallet A wants to use the two-phase election: +/// +/// ```rust,ignore +/// pub trait TraitA { +/// type ElectionProvider: ElectionProvider<_, _>; +/// } +/// +/// // these function will be called by `Self::ElectionProvider` whenever needed. +/// impl ElectionDataProvider for PalletA { /* .. */ } +/// +/// impl Module { +/// fn do_election() { +/// // finalize the election. +/// T::ElectionProvider::elect( /* .. */ ); +/// } +/// } +/// ``` +pub trait ElectionDataProvider { + /// The compact solution type. + /// + /// This should encode the entire solution with the least possible space usage. + type CompactSolution: codec::Codec + Default + PartialEq + Eq + Clone + Debug + CompactSolution; + + /// All possible targets for the election, i.e. the candidates. + fn targets() -> Vec; + + /// All possible voters for the election. + /// + /// Note that if a notion of self-vote exists, it should be represented here. + fn voters() -> Vec<(AccountId, VoteWeight, Vec)>; + + /// The number of targets to elect. + fn desired_targets() -> u32; + + /// Check the feasibility of a single assignment for the underlying `ElectionProvider`. In other + /// words, check if `who` having a weight distribution described as `distribution` is correct or + /// not. + /// + /// This might be called by the [`ElectionProvider`] upon processing solutions. + fn feasibility_check_assignment( + who: &AccountId, + distribution: &[(AccountId, P)], + ) -> bool; + + /// Provide a best effort prediction about when the next election is about to happen. + /// + /// In essence, `Self` should predict with this function when it will trigger the + /// `ElectionDataProvider::elect`. + fn next_election_prediction(now: B) -> B; +} + +/// Something that can compute the result of an election and pass it back to the caller. +pub trait ElectionProvider { + /// Indicate weather this election provider needs data when calling [`elect`] or not. If + /// `false`, then the call site can ignore all parameters of [`elect`] + const NEEDS_ELECT_DATA: bool; + + /// The error type that is returned by the provider. + type Error; + + /// Elect a new set of winners. + /// + /// The result is returned in a target major format, namely as a support map. + /// + /// Note that based on the logic of the type that will implement this trait, the input data may + /// or may not be used. To hint about this to the call site, [`NEEDS_ELECT_DATA`] should be + /// properly set. + /// + /// The implementation should, if possible, use the accuracy `P` to compute the election result. + fn elect( + to_elect: usize, + targets: Vec, + voters: Vec<(AccountId, VoteWeight, Vec)>, + ) -> Result, Self::Error> + where + ExtendedBalance: From<

::Inner>; + + /// Returns true if an election is still ongoing. + /// + /// This can be used by the call site to dynamically check of a long-lasting election (such as + /// [`two_phase`]) is still on-going or not. + fn ongoing() -> bool; +} diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 7305d74638c09..0071d2a56bcc5 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -75,12 +75,18 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_arithmetic::{ - traits::{Bounded, Zero}, + traits::{Bounded, UniqueSaturatedInto, Zero}, InnerOf, Normalizable, PerThing, Rational128, ThresholdOrd, }; use sp_std::{ - cell::RefCell, cmp::Ordering, collections::btree_map::BTreeMap, fmt::Debug, ops::Mul, - prelude::*, rc::Rc, + cell::RefCell, + cmp::Ordering, + collections::btree_map::BTreeMap, + convert::{TryFrom, TryInto}, + fmt::Debug, + ops::Mul, + prelude::*, + rc::Rc, }; #[cfg(feature = "std")] @@ -131,8 +137,8 @@ impl __OrInvalidIndex for Option { /// See [`compact`] for more info. pub trait CompactSolution: Sized { const LIMIT: usize; - type Voter: sp_arithmetic::traits::UniqueSaturatedInto; - type Target: sp_arithmetic::traits::UniqueSaturatedInto; + type Voter: UniqueSaturatedInto + TryInto + TryFrom; + type Target: UniqueSaturatedInto + TryInto + TryFrom; type VoteWeight: PerThing128; fn from_assignment( @@ -181,6 +187,25 @@ pub trait CompactSolution: Sized { /// In other words, if this return true, exactly one element must have been removed from /// `self.len()`. fn remove_voter(&mut self, to_remove: Self::Voter) -> bool; + + /// Compute the score of this compact solution type. + fn score( + self, + winners: &[A], + stake_of: FS, + voter_at: impl Fn(Self::Voter) -> Option, + target_at: impl Fn(Self::Target) -> Option, + ) -> Result + where + for<'r> FS: Fn(&'r A) -> VoteWeight, + A: IdentifierT, + ExtendedBalance: From>, + { + let ratio = self.into_assignment(voter_at, target_at)?; + let staked = helpers::assignment_ratio_to_staked_normalized(ratio, stake_of)?; + let support = to_supports(winners, &staked)?; + Ok(support.evaluate()) + } } // re-export the compact solution type. @@ -659,10 +684,10 @@ where { match this .iter() - .enumerate() - .map(|(i, e)| ( - e.ge(&that[i]), - e.tcmp(&that[i], epsilon.mul_ceil(that[i])), + .zip(that.iter()) + .map(|(thi, tha)| ( + thi.ge(&tha), + thi.tcmp(&tha, epsilon.mul_ceil(*tha)), )) .collect::>() .as_slice() diff --git a/primitives/npos-elections/src/mock.rs b/primitives/npos-elections/src/mock.rs index 33278da8f028e..72f917d0bee01 100644 --- a/primitives/npos-elections/src/mock.rs +++ b/primitives/npos-elections/src/mock.rs @@ -19,10 +19,13 @@ #![cfg(test)] -use crate::{seq_phragmen, ElectionResult, Assignment, VoteWeight, ExtendedBalance}; -use sp_arithmetic::{PerThing, InnerOf, traits::{SaturatedConversion, Zero, One}}; -use sp_std::collections::btree_map::BTreeMap; +use crate::*; +use sp_arithmetic::{ + traits::{One, SaturatedConversion, Zero}, + InnerOf, PerThing, +}; use sp_runtime::assert_eq_error_rate; +use sp_std::collections::btree_map::BTreeMap; #[derive(Default, Debug)] pub(crate) struct _Candidate { @@ -313,7 +316,7 @@ pub fn check_assignments_sum(assignments: Vec( +pub(crate) fn run_and_compare( candidates: Vec, voters: Vec<(AccountId, Vec)>, stake_of: &Box VoteWeight>, diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index c70c5ff579ee0..928781fbdd8a0 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -47,7 +47,7 @@ fn float_phragmen_poc_works() { ] ); - let mut support_map = to_support_map_float(&mut phragmen_result, &stake_of); + let mut support_map = build_support_map_float(&mut phragmen_result, &stake_of); assert_eq!( support_map.get(&2).unwrap(), From 25c1bc3f916d14efb10771772cd55552888087be Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 15 Oct 2020 19:13:16 +0200 Subject: [PATCH 12/62] Use decl_error --- frame/election-providers/expanded.rs | 7203 +++++++++-------- frame/election-providers/src/lib.rs | 2 +- frame/election-providers/src/two_phase/mod.rs | 28 +- .../src/two_phase/signed.rs | 2 +- .../src/two_phase/unsigned.rs | 8 +- 5 files changed, 3975 insertions(+), 3268 deletions(-) diff --git a/frame/election-providers/expanded.rs b/frame/election-providers/expanded.rs index 76fe0202e2fe8..53cbfe81ef2d8 100644 --- a/frame/election-providers/expanded.rs +++ b/frame/election-providers/expanded.rs @@ -1,9 +1,5 @@ #![feature(prelude_import)] -//! Reusable Election Providers. -//! -//! The core functionality of this crate is around [`ElectionProvider`]. An election provider is a -//! struct, module, or anything else that implements [`ElectionProvider`]. Such types can then be -//! passed around to other crates and pallets that need election functionality. +//! Various implementation for `ElectionProvider`. //! //! Two main election providers are implemented in this crate. //! @@ -16,3257 +12,3966 @@ use std::prelude::v1::*; #[macro_use] extern crate std; -use sp_std::{fmt::Debug, prelude::*}; /// The onchain module. pub mod onchain { - use crate::{ElectionProvider, FlattenSupportMap, Supports}; - use sp_arithmetic::PerThing; - use sp_npos_elections::{ - ElectionResult, ExtendedBalance, IdentifierT, PerThing128, VoteWeight, - }; - use sp_runtime::RuntimeDebug; - use sp_std::{collections::btree_map::BTreeMap, prelude::*}; - /// Errors of the on-chain election. - pub enum Error { - /// An internal error in the NPoS elections crate. - NposElections(sp_npos_elections::Error), - } - impl core::fmt::Debug for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::NposElections(ref a0) => { - fmt.debug_tuple("Error::NposElections").field(a0).finish() - } - _ => Ok(()), - } - } - } - impl ::core::marker::StructuralEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Error { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - } - } - } - impl ::core::marker::StructuralPartialEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Error { - #[inline] - fn eq(&self, other: &Error) -> bool { - match (&*self, &*other) { - (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - } - } - #[inline] - fn ne(&self, other: &Error) -> bool { - match (&*self, &*other) { - (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - } - } - } - impl From for Error { - fn from(e: sp_npos_elections::Error) -> Self { - Error::NposElections(e) - } - } - pub struct OnChainSequentialPhragmen; - impl ElectionProvider for OnChainSequentialPhragmen { - type Error = Error; - const NEEDS_ELECT_DATA: bool = true; - fn elect( - to_elect: usize, - targets: Vec, - voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>, - { - let mut stake_map: BTreeMap = BTreeMap::new(); - voters.iter().for_each(|(v, s, _)| { - stake_map.insert(v.clone(), *s); - }); - let stake_of = Box::new(|w: &AccountId| -> VoteWeight { - stake_map.get(w).cloned().unwrap_or_default() - }); - sp_npos_elections::seq_phragmen::<_, P>(to_elect, targets, voters, None) - .and_then(|e| { - let ElectionResult { - winners, - assignments, - } = e; - let staked = sp_npos_elections::assignment_ratio_to_staked_normalized( - assignments, - &stake_of, - )?; - let winners = sp_npos_elections::to_without_backing(winners); - sp_npos_elections::build_support_map(&winners, &staked).map(|s| s.flatten()) - }) - .map_err(From::from) - } - fn ongoing() -> bool { - false - } - } + use sp_arithmetic::PerThing; + use sp_election_providers::ElectionProvider; + use sp_npos_elections::{ + ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Supports, VoteWeight, + }; + use sp_runtime::RuntimeDebug; + use sp_std::{collections::btree_map::BTreeMap, prelude::*}; + /// Errors of the on-chain election. + pub enum Error { + /// An internal error in the NPoS elections crate. + NposElections(sp_npos_elections::Error), + } + impl core::fmt::Debug for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::NposElections(ref a0) => { + fmt.debug_tuple("Error::NposElections").field(a0).finish() + } + _ => Ok(()), + } + } + } + impl ::core::marker::StructuralEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } + impl ::core::marker::StructuralPartialEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + match (&*self, &*other) { + (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + } + } + #[inline] + fn ne(&self, other: &Error) -> bool { + match (&*self, &*other) { + (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + } + } + } + impl From for Error { + fn from(e: sp_npos_elections::Error) -> Self { + Error::NposElections(e) + } + } + /// A simple on-chian implementation of the election provider trait. + /// + /// This will accept voting data on the fly and produce the results immediately. + /// + /// ### Warning + /// + /// This can be very expensive to run frequently on-chain. Use with care. + pub struct OnChainSequentialPhragmen; + impl ElectionProvider for OnChainSequentialPhragmen { + type Error = Error; + const NEEDS_ELECT_DATA: bool = true; + fn elect( + to_elect: usize, + targets: Vec, + voters: Vec<(AccountId, VoteWeight, Vec)>, + ) -> Result, Self::Error> + where + ExtendedBalance: From<

::Inner>, + { + let mut stake_map: BTreeMap = BTreeMap::new(); + voters.iter().for_each(|(v, s, _)| { + stake_map.insert(v.clone(), *s); + }); + let stake_of = Box::new(|w: &AccountId| -> VoteWeight { + stake_map.get(w).cloned().unwrap_or_default() + }); + sp_npos_elections::seq_phragmen::<_, P>(to_elect, targets, voters, None) + .and_then(|e| { + let ElectionResult { + winners, + assignments, + } = e; + let staked = sp_npos_elections::assignment_ratio_to_staked_normalized( + assignments, + &stake_of, + )?; + let winners = sp_npos_elections::to_without_backing(winners); + sp_npos_elections::to_supports(&winners, &staked) + }) + .map_err(From::from) + } + fn ongoing() -> bool { + false + } + } } /// The two-phase module. pub mod two_phase { - //! # Two phase election provider pallet. - //! - //! As the name suggests, this election provider has two distinct phases (see [`Phase`]), signed and - //! unsigned. - //! - //! ## Phases - //! - //! The timeline of pallet is as follows. At each block, - //! [`ElectionDataProvider::next_election_prediction`] is used to estimate the time remaining to the - //! next call to `elect`. Based on this, a phase is chosen. The timeline is as follows. - //! - //! ```ignore - //! elect() - //! + <--T::SignedPhase--> + <--T::UnsignedPhase--> + - //! +-------------------------------------------------------------------+ - //! Phase::Off + Phase::Signed + Phase::Unsigned + - //! - //! Note that the unsigned phase starts `T::UnsignedPhase` blocks before the - //! `next_election_prediction`, but only ends when a call to `ElectionProvider::elect` happens. - //! - //! ``` - //! ### Signed Phase - //! - //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A - //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution - //! on-chain for a number of blocks. A maximum of [`Trait::MaxSignedSubmissions`] solutions are - //! stored. The queue is always sorted based on score (worse -> best). - //! - //! Upon arrival of a new solution: - //! - //! 1. If the queue is not full, it is stored. - //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the - //! worse solution is discarded (TODO: what to do with the bond?) and the new solution is stored - //! in the correct index. - //! 3. If the queue is full and the solution is not an improvement compared to any of the queued - //! ones, it is instantly rejected and no additional bond is reserved. - //! - //! A signed solution cannot be reversed, taken back, updated, or retracted. In other words, the - //! origin can not bail out in any way. - //! - //! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed - //! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure - //! the score claimed by this score was correct, among other checks. At each step, if the current - //! best solution is passes the feasibility check, it is considered to be the best one. The sender - //! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without - //! being checked. - //! - //! The following example covers all of the cases at the end of the signed phase: - //! - //! ```ignore - //! Queue - //! +-------------------------------+ - //! |Solution(score=20, valid=false)| +--> Slashed - //! +-------------------------------+ - //! |Solution(score=15, valid=true )| +--> Rewarded - //! +-------------------------------+ - //! |Solution(score=10, valid=true )| +--> Discarded - //! +-------------------------------+ - //! |Solution(score=05, valid=false)| +--> Discarded - //! +-------------------------------+ - //! | None | - //! +-------------------------------+ - //! ``` - //! - //! Note that both of the bottom solutions end up being discarded and get their deposit back, - //! despite one of them being invalid. - //! - //! ## Unsigned Phase - //! - //! If signed phase ends with a good solution, then the unsigned phase will be `active` - //! ([`Phase::Unsigned(true)`]), else the unsigned phase will be `passive`. - //! - //! TODO - //! - //! ### Fallback - //! - //! If we reach the end of both phases (i.e. call to `ElectionProvider::elect` happens) and no good - //! solution is queued, then we fallback to an on-chain election. The on-chain election is slow, and - //! contains to balancing or reduction post-processing. - //! - //! ## Correct Submission - //! - //! TODO - //! - //! ## Accuracy - //! - //! TODO - //! - use crate::{ - onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, - FlattenSupportMap, Supports, - }; - use codec::{Decode, Encode, HasCompact}; - use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, - dispatch::DispatchResultWithPostInfo, - ensure, - traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, - weights::Weight, - }; - use frame_system::{ensure_none, ensure_signed}; - use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, build_support_map, evaluate_support, Assignment, - CompactSolution, ElectionScore, ExtendedBalance, PerThing128, VoteWeight, - }; - use sp_runtime::{traits::Zero, InnerOf, PerThing, Perbill, RuntimeDebug}; - use sp_std::prelude::*; - #[macro_use] - pub(crate) mod macros { - //! Some helper macros for this crate. - } - pub mod signed { - //! The signed phase implementation. - use crate::two_phase::*; - use codec::Encode; - use sp_arithmetic::traits::SaturatedConversion; - use sp_npos_elections::is_score_better; - use sp_runtime::Perbill; - impl Module - where - ExtendedBalance: From>>, - { - /// Start the signed phase. - /// - /// Upon calling this, auxillary data for election is stored and signed solutions will be - /// accepted. - /// - /// The signed phase must always start before the unsigned phase. - pub fn start_signed_phase() { - let targets = T::ElectionDataProvider::targets(); - let voters = T::ElectionDataProvider::voters(); - let desired_targets = T::ElectionDataProvider::desired_targets(); - >::put(targets); - >::put(voters); - DesiredTargets::put(desired_targets); - } - /// Finish the singed phase. Process the signed submissions from best to worse until a valid one - /// is found, rewarding the best oen and slashing the invalid ones along the way. - /// - /// Returns true if we have a good solution in the signed phase. - /// - /// This drains the [`SignedSubmissions`], potentially storing the best valid one in - /// [`QueuedSolution`]. - pub fn finalize_signed_phase() -> bool { - let mut all_submission: Vec> = - >::take(); - let mut found_solution = false; - while let Some(best) = all_submission.pop() { - let SignedSubmission { - solution, - who, - deposit, - reward, - } = best; - match Self::feasibility_check(solution, ElectionCompute::Signed) { - Ok(ready_solution) => { - >::put(ready_solution); - let _remaining = T::Currency::unreserve(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic( - "assertion failed: _remaining.is_zero()", - ) - } - }; - }; - let positive_imbalance = T::Currency::deposit_creating(&who, reward); - T::RewardHandler::on_unbalanced(positive_imbalance); - found_solution = true; - break; - } - Err(_) => { - let (negative_imbalance, _remaining) = - T::Currency::slash_reserved(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic( - "assertion failed: _remaining.is_zero()", - ) - } - }; - }; - T::SlashHandler::on_unbalanced(negative_imbalance); - } - } - } - all_submission.into_iter().for_each(|not_processed| { - let SignedSubmission { who, deposit, .. } = not_processed; - let _remaining = T::Currency::unreserve(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic("assertion failed: _remaining.is_zero()") - } - }; - }; - }); - found_solution - } - /// Find a proper position in the queue for the signed queue, whilst maintaining the order of - /// solution quality. - /// - /// The length of the queue will always be kept less than or equal to `T::MaxSignedSubmissions`. - pub fn insert_submission( - who: &T::AccountId, - queue: &mut Vec, CompactOf>>, - solution: RawSolution>, - ) -> Option { - let outcome = queue - .iter() - .enumerate() - .rev() - .find_map(|(i, s)| { - if is_score_better::( - solution.score, - s.solution.score, - T::SolutionImprovementThreshold::get(), - ) { - Some(i + 1) - } else { - None - } - }) - .or(Some(0)) - .and_then(|at| { - if at == 0 && queue.len() as u32 >= T::MaxSignedSubmissions::get() { - None - } else { - let reward = Self::reward_for(&solution); - let deposit = Self::deposit_for(&solution); - let submission = SignedSubmission { - who: who.clone(), - deposit, - reward, - solution, - }; - queue.insert(at, submission); - if queue.len() as u32 > T::MaxSignedSubmissions::get() { - queue.remove(0); - Some(at - 1) - } else { - Some(at) - } - } - }); - if true { - if !(queue.len() as u32 <= T::MaxSignedSubmissions::get()) { - { - :: std :: rt :: begin_panic ( "assertion failed: queue.len() as u32 <= T::MaxSignedSubmissions::get()" ) - } - }; - }; - outcome - } - /// Collect sufficient deposit to store this solution this chain. - /// - /// The deposit is composed of 3 main elements: - /// - /// 1. base deposit, fixed for all submissions. - /// 2. a per-byte deposit, for renting the state usage. - /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize - pub fn deposit_for(solution: &RawSolution>) -> BalanceOf { - let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); - let feasibility_weight = T::WeightInfo::feasibility_check(); - let len_deposit = T::SignedDepositByte::get() * encoded_len; - let weight_deposit = - T::SignedDepositWeight::get() * feasibility_weight.saturated_into(); - T::SignedDepositBase::get() + len_deposit + weight_deposit - } - /// The reward for this solution, if successfully chosen as the best one at the end of the - /// signed phase. - pub fn reward_for(solution: &RawSolution>) -> BalanceOf { - T::SignedRewardBase::get() - + T::SignedRewardFactor::get() - * solution.score[0].saturated_into::>() - } - } - } - pub mod unsigned { - //! The unsigned phase implementation. - use crate::two_phase::*; - use codec::Encode; - use sp_arithmetic::traits::SaturatedConversion; - use sp_npos_elections::is_score_better; - use sp_runtime::Perbill; - impl Module where ExtendedBalance: From>> {} - } - /// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] - /// implementer. - pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< - ::AccountId, - ::BlockNumber, - >>::CompactSolution; - /// The voter index. Derived from [`CompactOf`]. - pub type CompactVoterIndexOf = as CompactSolution>::Voter; - /// The target index. Derived from [`CompactOf`]. - pub type CompactTargetIndexOf = as CompactSolution>::Target; - /// The accuracy of the election. Derived from [`CompactOf`]. - pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; - type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - type PositiveImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::PositiveImbalance; - type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::NegativeImbalance; - const LOG_TARGET: &'static str = "two-phase-submission"; - /// Current phase of the pallet. - pub enum Phase { - /// Nothing, the election is not happening. - Off, - /// Signed phase is open. - Signed, - /// Unsigned phase is open. - Unsigned(bool), - } - impl ::core::marker::StructuralPartialEq for Phase {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Phase { - #[inline] - fn eq(&self, other: &Phase) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &Phase) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - _ => false, - } - } else { - true - } - } - } - } - impl ::core::marker::StructuralEq for Phase {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Phase { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Phase { - #[inline] - fn clone(&self) -> Phase { - { - let _: ::core::clone::AssertParamIsClone; - *self - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for Phase {} - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Phase { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - Phase::Off => { - dest.push_byte(0usize as u8); - } - Phase::Signed => { - dest.push_byte(1usize as u8); - } - Phase::Unsigned(ref aa) => { - dest.push_byte(2usize as u8); - dest.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for Phase {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Phase { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(Phase::Off), - x if x == 1usize as u8 => Ok(Phase::Signed), - x if x == 2usize as u8 => Ok(Phase::Unsigned({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field Phase :: Unsigned.0".into()), - Ok(a) => a, - } - })), - x => Err("No such variant in enum Phase".into()), - } - } - } - }; - impl core::fmt::Debug for Phase { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::Off => fmt.debug_tuple("Phase::Off").finish(), - Self::Signed => fmt.debug_tuple("Phase::Signed").finish(), - Self::Unsigned(ref a0) => fmt.debug_tuple("Phase::Unsigned").field(a0).finish(), - _ => Ok(()), - } - } - } - impl Default for Phase { - fn default() -> Self { - Phase::Off - } - } - impl Phase { - /// Weather the phase is signed or not. - pub fn is_signed(&self) -> bool { - match self { - Phase::Signed => true, - _ => false, - } - } - /// Weather the phase is unsigned or not. - pub fn is_unsigned(&self) -> bool { - match self { - Phase::Unsigned(_) => true, - _ => false, - } - } - /// Weather the phase is unsigned and open or not. - pub fn is_unsigned_open(&self) -> bool { - match self { - Phase::Unsigned(true) => true, - _ => false, - } - } - /// Weather the phase is off or not. - pub fn is_off(&self) -> bool { - match self { - Phase::Off => true, - _ => false, - } - } - } - /// The type of `Computation` that provided this election data. - pub enum ElectionCompute { - /// Election was computed on-chain. - OnChain, - /// Election was computed with a signed submission. - Signed, - /// Election was computed with an unsigned submission. - Unsigned, - } - impl ::core::marker::StructuralPartialEq for ElectionCompute {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for ElectionCompute { - #[inline] - fn eq(&self, other: &ElectionCompute) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - _ => true, - } - } else { - false - } - } - } - } - impl ::core::marker::StructuralEq for ElectionCompute {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for ElectionCompute { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - {} - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for ElectionCompute { - #[inline] - fn clone(&self) -> ElectionCompute { - { - *self - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for ElectionCompute {} - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for ElectionCompute { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - ElectionCompute::OnChain => { - dest.push_byte(0usize as u8); - } - ElectionCompute::Signed => { - dest.push_byte(1usize as u8); - } - ElectionCompute::Unsigned => { - dest.push_byte(2usize as u8); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for ElectionCompute {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for ElectionCompute { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(ElectionCompute::OnChain), - x if x == 1usize as u8 => Ok(ElectionCompute::Signed), - x if x == 2usize as u8 => Ok(ElectionCompute::Unsigned), - x => Err("No such variant in enum ElectionCompute".into()), - } - } - } - }; - impl core::fmt::Debug for ElectionCompute { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::OnChain => fmt.debug_tuple("ElectionCompute::OnChain").finish(), - Self::Signed => fmt.debug_tuple("ElectionCompute::Signed").finish(), - Self::Unsigned => fmt.debug_tuple("ElectionCompute::Unsigned").finish(), - _ => Ok(()), - } - } - } - impl Default for ElectionCompute { - fn default() -> Self { - ElectionCompute::OnChain - } - } - /// A raw, unchecked solution. - /// - /// Such a solution should never become effective in anyway before being checked by the - /// [`Module::feasibility_check`] - pub struct RawSolution { - /// Compact election edges. - compact: C, - /// The _claimed_ score of the solution. - score: ElectionScore, - } - impl ::core::marker::StructuralPartialEq for RawSolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for RawSolution { - #[inline] - fn eq(&self, other: &RawSolution) -> bool { - match *other { - RawSolution { - compact: ref __self_1_0, - score: ref __self_1_1, - } => match *self { - RawSolution { - compact: ref __self_0_0, - score: ref __self_0_1, - } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), - }, - } - } - #[inline] - fn ne(&self, other: &RawSolution) -> bool { - match *other { - RawSolution { - compact: ref __self_1_0, - score: ref __self_1_1, - } => match *self { - RawSolution { - compact: ref __self_0_0, - score: ref __self_0_1, - } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), - }, - } - } - } - impl ::core::marker::StructuralEq for RawSolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for RawSolution { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for RawSolution { - #[inline] - fn clone(&self) -> RawSolution { - match *self { - RawSolution { - compact: ref __self_0_0, - score: ref __self_0_1, - } => RawSolution { - compact: ::core::clone::Clone::clone(&(*__self_0_0)), - score: ::core::clone::Clone::clone(&(*__self_0_1)), - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for RawSolution - where - C: _parity_scale_codec::Encode, - C: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.compact); - dest.push(&self.score); - } - } - impl _parity_scale_codec::EncodeLike for RawSolution - where - C: _parity_scale_codec::Encode, - C: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for RawSolution - where - C: _parity_scale_codec::Decode, - C: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(RawSolution { - compact: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field RawSolution.compact".into()), - Ok(a) => a, - } - }, - score: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field RawSolution.score".into()), - Ok(a) => a, - } - }, - }) - } - } - }; - impl core::fmt::Debug for RawSolution - where - C: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("RawSolution") - .field("compact", &self.compact) - .field("score", &self.score) - .finish() - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for RawSolution { - #[inline] - fn default() -> RawSolution { - RawSolution { - compact: ::core::default::Default::default(), - score: ::core::default::Default::default(), - } - } - } - /// A raw, unchecked signed submission. - /// - /// This is just a wrapper around [`RawSolution`] and some additional info. - pub struct SignedSubmission { - /// Who submitted this solution. - who: A, - /// The deposit reserved for storing this solution. - deposit: B, - /// The reward that should be given to this solution, if chosen the as the final one. - reward: B, - /// The raw solution itself. - solution: RawSolution, - } - impl ::core::marker::StructuralPartialEq for SignedSubmission {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl< - A: ::core::cmp::PartialEq, - B: ::core::cmp::PartialEq + HasCompact, - C: ::core::cmp::PartialEq, - > ::core::cmp::PartialEq for SignedSubmission - { - #[inline] - fn eq(&self, other: &SignedSubmission) -> bool { - match *other { - SignedSubmission { - who: ref __self_1_0, - deposit: ref __self_1_1, - reward: ref __self_1_2, - solution: ref __self_1_3, - } => match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - && (*__self_0_3) == (*__self_1_3) - } - }, - } - } - #[inline] - fn ne(&self, other: &SignedSubmission) -> bool { - match *other { - SignedSubmission { - who: ref __self_1_0, - deposit: ref __self_1_1, - reward: ref __self_1_2, - solution: ref __self_1_3, - } => match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) - || (*__self_0_2) != (*__self_1_2) - || (*__self_0_3) != (*__self_1_3) - } - }, - } - } - } - impl ::core::marker::StructuralEq for SignedSubmission {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq - for SignedSubmission - { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq>; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl< - A: ::core::clone::Clone, - B: ::core::clone::Clone + HasCompact, - C: ::core::clone::Clone, - > ::core::clone::Clone for SignedSubmission - { - #[inline] - fn clone(&self) -> SignedSubmission { - match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => SignedSubmission { - who: ::core::clone::Clone::clone(&(*__self_0_0)), - deposit: ::core::clone::Clone::clone(&(*__self_0_1)), - reward: ::core::clone::Clone::clone(&(*__self_0_2)), - solution: ::core::clone::Clone::clone(&(*__self_0_3)), - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for SignedSubmission - where - A: _parity_scale_codec::Encode, - A: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.who); - dest.push(&self.deposit); - dest.push(&self.reward); - dest.push(&self.solution); - } - } - impl _parity_scale_codec::EncodeLike for SignedSubmission - where - A: _parity_scale_codec::Encode, - A: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for SignedSubmission - where - A: _parity_scale_codec::Decode, - A: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - RawSolution: _parity_scale_codec::Decode, - RawSolution: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(SignedSubmission { - who: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.who".into()) - } - Ok(a) => a, - } - }, - deposit: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.deposit".into()) - } - Ok(a) => a, - } - }, - reward: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.reward".into()) - } - Ok(a) => a, - } - }, - solution: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.solution".into()) - } - Ok(a) => a, - } - }, - }) - } - } - }; - impl core::fmt::Debug for SignedSubmission - where - A: core::fmt::Debug, - B: core::fmt::Debug, - C: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("SignedSubmission") - .field("who", &self.who) - .field("deposit", &self.deposit) - .field("reward", &self.reward) - .field("solution", &self.solution) - .finish() - } - } - /// A checked and parsed solution, ready to be enacted. - pub struct ReadySolution { - /// The final supports of the solution. This is target-major vector, storing each winners, total - /// backing, and each individual backer. - supports: Supports, - /// How this election was computed. - compute: ElectionCompute, - } - impl ::core::marker::StructuralPartialEq for ReadySolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for ReadySolution { - #[inline] - fn eq(&self, other: &ReadySolution) -> bool { - match *other { - ReadySolution { - supports: ref __self_1_0, - compute: ref __self_1_1, - } => match *self { - ReadySolution { - supports: ref __self_0_0, - compute: ref __self_0_1, - } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), - }, - } - } - #[inline] - fn ne(&self, other: &ReadySolution) -> bool { - match *other { - ReadySolution { - supports: ref __self_1_0, - compute: ref __self_1_1, - } => match *self { - ReadySolution { - supports: ref __self_0_0, - compute: ref __self_0_1, - } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), - }, - } - } - } - impl ::core::marker::StructuralEq for ReadySolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for ReadySolution { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for ReadySolution { - #[inline] - fn clone(&self) -> ReadySolution { - match *self { - ReadySolution { - supports: ref __self_0_0, - compute: ref __self_0_1, - } => ReadySolution { - supports: ::core::clone::Clone::clone(&(*__self_0_0)), - compute: ::core::clone::Clone::clone(&(*__self_0_1)), - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for ReadySolution - where - Supports: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.supports); - dest.push(&self.compute); - } - } - impl _parity_scale_codec::EncodeLike for ReadySolution - where - Supports: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for ReadySolution - where - Supports: _parity_scale_codec::Decode, - Supports: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(ReadySolution { - supports: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field ReadySolution.supports".into()) - } - Ok(a) => a, - } - }, - compute: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field ReadySolution.compute".into()) - } - Ok(a) => a, - } - }, - }) - } - } - }; - impl core::fmt::Debug for ReadySolution - where - A: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("ReadySolution") - .field("supports", &self.supports) - .field("compute", &self.compute) - .finish() - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for ReadySolution { - #[inline] - fn default() -> ReadySolution { - ReadySolution { - supports: ::core::default::Default::default(), - compute: ::core::default::Default::default(), - } - } - } - /// The crate errors. Note that this is different from the [`PalletError`]. - pub enum Error { - /// A feasibility error. - Feasibility(FeasibilityError), - /// An error in the on-chain fallback. - OnChainFallback(crate::onchain::Error), - /// Snapshot data was unavailable unexpectedly. - SnapshotUnAvailable, - } - impl core::fmt::Debug for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::Feasibility(ref a0) => { - fmt.debug_tuple("Error::Feasibility").field(a0).finish() - } - Self::OnChainFallback(ref a0) => { - fmt.debug_tuple("Error::OnChainFallback").field(a0).finish() - } - Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), - _ => Ok(()), - } - } - } - impl ::core::marker::StructuralEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Error { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - impl ::core::marker::StructuralPartialEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Error { - #[inline] - fn eq(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - ( - &Error::OnChainFallback(ref __self_0), - &Error::OnChainFallback(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - ( - &Error::OnChainFallback(ref __self_0), - &Error::OnChainFallback(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - _ => false, - } - } else { - true - } - } - } - } - impl From for Error { - fn from(e: crate::onchain::Error) -> Self { - Error::OnChainFallback(e) - } - } - /// Errors that can happen in the feasibility check. - pub enum FeasibilityError { - /// Wrong number of winners presented. - WrongWinnerCount, - /// The snapshot is not available. - /// - /// This must be an internal error of the chain. - SnapshotUnavailable, - /// Internal error from the election crate. - NposElectionError(sp_npos_elections::Error), - /// A vote is invalid. - InvalidVote, - /// A voter is invalid. - InvalidVoter, - /// A winner is invalid. - InvalidWinner, - /// The given score was invalid. - InvalidScore, - } - impl core::fmt::Debug for FeasibilityError { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::WrongWinnerCount => fmt - .debug_tuple("FeasibilityError::WrongWinnerCount") - .finish(), - Self::SnapshotUnavailable => fmt - .debug_tuple("FeasibilityError::SnapshotUnavailable") - .finish(), - Self::NposElectionError(ref a0) => fmt - .debug_tuple("FeasibilityError::NposElectionError") - .field(a0) - .finish(), - Self::InvalidVote => fmt.debug_tuple("FeasibilityError::InvalidVote").finish(), - Self::InvalidVoter => fmt.debug_tuple("FeasibilityError::InvalidVoter").finish(), - Self::InvalidWinner => fmt.debug_tuple("FeasibilityError::InvalidWinner").finish(), - Self::InvalidScore => fmt.debug_tuple("FeasibilityError::InvalidScore").finish(), - _ => Ok(()), - } - } - } - impl ::core::marker::StructuralEq for FeasibilityError {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for FeasibilityError { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - } - } - } - impl ::core::marker::StructuralPartialEq for FeasibilityError {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for FeasibilityError { - #[inline] - fn eq(&self, other: &FeasibilityError) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &FeasibilityError::NposElectionError(ref __self_0), - &FeasibilityError::NposElectionError(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &FeasibilityError) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &FeasibilityError::NposElectionError(ref __self_0), - &FeasibilityError::NposElectionError(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - _ => false, - } - } else { - true - } - } - } - } - impl From for FeasibilityError { - fn from(e: sp_npos_elections::Error) -> Self { - FeasibilityError::NposElectionError(e) - } - } - /// The weights for this pallet. - pub trait WeightInfo { - fn feasibility_check() -> Weight; - fn submit() -> Weight; - fn submit_unsigned() -> Weight; - } - impl WeightInfo for () { - fn feasibility_check() -> Weight { - Default::default() - } - fn submit() -> Weight { - Default::default() - } - fn submit_unsigned() -> Weight { - Default::default() - } - } - pub trait Trait: frame_system::Trait { - /// Event type. - type Event: From> + Into<::Event>; - /// Currency type. - type Currency: ReservableCurrency + Currency; - /// Duration of the signed phase. - type SignedPhase: Get; - /// Duration of the unsigned phase. - type UnsignedPhase: Get; - /// Maximum number of singed submissions that can be queued. - type MaxSignedSubmissions: Get; - type SignedRewardBase: Get>; - type SignedRewardFactor: Get; - type SignedDepositBase: Get>; - type SignedDepositByte: Get>; - type SignedDepositWeight: Get>; - /// The minimum amount of improvement to the solution score that defines a solution as "better". - type SolutionImprovementThreshold: Get; - /// Handler for the slashed deposits. - type SlashHandler: OnUnbalanced>; - /// Handler for the rewards. - type RewardHandler: OnUnbalanced>; - /// Something that will provide the election data. - type ElectionDataProvider: ElectionDataProvider; - /// The weight of the pallet. - type WeightInfo: WeightInfo; - } - use self::sp_api_hidden_includes_decl_storage::hidden_include::{ - IterableStorageDoubleMap as _, IterableStorageMap as _, StorageDoubleMap as _, - StorageMap as _, StoragePrefixedMap as _, StorageValue as _, - }; - #[doc(hidden)] - mod sp_api_hidden_includes_decl_storage { - pub extern crate frame_support as hidden_include; - } - trait Store { - type CurrentPhase; - type SignedSubmissions; - type QueuedSolution; - type SnapshotTargets; - type SnapshotVoters; - type DesiredTargets; - } - impl Store for Module - where - ExtendedBalance: From>>, - { - type CurrentPhase = CurrentPhase; - type SignedSubmissions = SignedSubmissions; - type QueuedSolution = QueuedSolution; - type SnapshotTargets = SnapshotTargets; - type SnapshotVoters = SnapshotVoters; - type DesiredTargets = DesiredTargets; - } - impl Module - where - ExtendedBalance: From>>, - { - /// Current phase. - pub fn current_phase() -> Phase { - < CurrentPhase < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase > > :: get ( ) - } - /// Sorted (worse -> best) list of unchecked, signed solutions. - pub fn signed_submissions( - ) -> Vec, CompactOf>> { - < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > > > :: get ( ) - } - /// Current best solution, signed or unsigned. - pub fn queued_solution() -> Option> { - < QueuedSolution < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < ReadySolution < T :: AccountId > > > :: get ( ) - } - /// Snapshot of all Voters. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn snapshot_targets() -> Option> { - < SnapshotTargets < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < T :: AccountId > > > :: get ( ) - } - /// Snapshot of all targets. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn snapshot_voters() -> Option)>> { - < SnapshotVoters < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < ( T :: AccountId , VoteWeight , Vec < T :: AccountId > ) > > > :: get ( ) - } - /// Desired number of targets to elect. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn desired_targets() -> u32 { - < DesiredTargets < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) - } - } - #[doc(hidden)] - pub struct __GetByteStructCurrentPhase( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_CurrentPhase: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructCurrentPhase - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_CurrentPhase - .get_or_init(|| { - let def_val: Phase = Phase::Off; - ::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructCurrentPhase where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructCurrentPhase where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructSignedSubmissions( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_SignedSubmissions: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructSignedSubmissions - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SignedSubmissions . get_or_init ( | | { let def_val : Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > = Default :: default ( ) ; < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > as Encode > :: encode ( & def_val ) } ) . clone ( ) - } - } - unsafe impl Send for __GetByteStructSignedSubmissions where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructSignedSubmissions where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructQueuedSolution( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_QueuedSolution: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructQueuedSolution - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_QueuedSolution - .get_or_init(|| { - let def_val: Option> = Default::default(); - > as Encode>::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructQueuedSolution where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructQueuedSolution where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructSnapshotTargets( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_SnapshotTargets: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructSnapshotTargets - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SnapshotTargets - .get_or_init(|| { - let def_val: Option> = Default::default(); - > as Encode>::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructSnapshotTargets where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructSnapshotTargets where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructSnapshotVoters( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_SnapshotVoters: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructSnapshotVoters - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SnapshotVoters - .get_or_init(|| { - let def_val: Option)>> = - Default::default(); - )>> as Encode>::encode( - &def_val, - ) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructSnapshotVoters where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructSnapshotVoters where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructDesiredTargets( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_DesiredTargets: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructDesiredTargets - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_DesiredTargets - .get_or_init(|| { - let def_val: u32 = Default::default(); - ::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructDesiredTargets where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructDesiredTargets where - ExtendedBalance: From>> - { - } - impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - pub fn storage_metadata( - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::StorageMetadata { - self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec, CompactOf>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted (worse -> best) list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current best solution, signed or unsigned." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } ] [ .. ] ) , } - } - } - /// Hidden instance generated to be internally used when module is used without - /// instance. - #[doc(hidden)] - pub struct __InherentHiddenInstance; - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for __InherentHiddenInstance { - #[inline] - fn clone(&self) -> __InherentHiddenInstance { - match *self { - __InherentHiddenInstance => __InherentHiddenInstance, - } - } - } - impl ::core::marker::StructuralEq for __InherentHiddenInstance {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for __InherentHiddenInstance { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - {} - } - } - impl ::core::marker::StructuralPartialEq for __InherentHiddenInstance {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for __InherentHiddenInstance { - #[inline] - fn eq(&self, other: &__InherentHiddenInstance) -> bool { - match *other { - __InherentHiddenInstance => match *self { - __InherentHiddenInstance => true, - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for __InherentHiddenInstance { - fn encode_to(&self, dest: &mut EncOut) {} - } - impl _parity_scale_codec::EncodeLike for __InherentHiddenInstance {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for __InherentHiddenInstance { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(__InherentHiddenInstance) - } - } - }; - impl core::fmt::Debug for __InherentHiddenInstance { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_tuple("__InherentHiddenInstance").finish() - } - } - impl self::sp_api_hidden_includes_decl_storage::hidden_include::traits::Instance - for __InherentHiddenInstance - { - const PREFIX: &'static str = "TwoPhaseElectionProvider"; - } - /// Current phase. - pub struct CurrentPhase( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, - ); - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Phase, - > for CurrentPhase - { - type Query = Phase; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"CurrentPhase" - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - v.unwrap_or_else(|| Phase::Off) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - Some(v) - } - } - /// Sorted (worse -> best) list of unchecked, signed solutions. - pub struct SignedSubmissions( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec, CompactOf>>, - > for SignedSubmissions - where - ExtendedBalance: From>>, - { - type Query = Vec, CompactOf>>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"SignedSubmissions" - } - fn from_optional_value_to_query( - v: Option, CompactOf>>>, - ) -> Self::Query { - v.unwrap_or_else(|| Default::default()) - } - fn from_query_to_optional_value( - v: Self::Query, - ) -> Option, CompactOf>>> { - Some(v) - } - } - /// Current best solution, signed or unsigned. - pub struct QueuedSolution( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - ReadySolution, - > for QueuedSolution - where - ExtendedBalance: From>>, - { - type Query = Option>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"QueuedSolution" - } - fn from_optional_value_to_query(v: Option>) -> Self::Query { - v.or_else(|| Default::default()) - } - fn from_query_to_optional_value(v: Self::Query) -> Option> { - v - } - } - /// Snapshot of all Voters. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub struct SnapshotTargets( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec, - > for SnapshotTargets - where - ExtendedBalance: From>>, - { - type Query = Option>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"SnapshotTargets" - } - fn from_optional_value_to_query(v: Option>) -> Self::Query { - v.or_else(|| Default::default()) - } - fn from_query_to_optional_value(v: Self::Query) -> Option> { - v - } - } - /// Snapshot of all targets. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub struct SnapshotVoters( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec<(T::AccountId, VoteWeight, Vec)>, - > for SnapshotVoters - where - ExtendedBalance: From>>, - { - type Query = Option)>>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"SnapshotVoters" - } - fn from_optional_value_to_query( - v: Option)>>, - ) -> Self::Query { - v.or_else(|| Default::default()) - } - fn from_query_to_optional_value( - v: Self::Query, - ) -> Option)>> { - v - } - } - /// Desired number of targets to elect. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub struct DesiredTargets( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, - ); - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - u32, - > for DesiredTargets - { - type Query = u32; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"DesiredTargets" - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - v.unwrap_or_else(|| Default::default()) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - Some(v) - } - } - /// [`RawEvent`] specialized for the configuration [`Trait`] - /// - /// [`RawEvent`]: enum.RawEvent.html - /// [`Trait`]: trait.Trait.html - pub type Event = RawEvent<::AccountId>; - /// Events for this module. - /// - pub enum RawEvent { - /// A solution was stored with the given compute. - /// - /// If the solution is signed, this means that it hasn't yet been processed. If the solution - /// is unsigned, this means that it has also been processed. - SolutionStored(ElectionCompute), - /// The election has been finalized, with `Some` of the given computation, or else if the - /// election failed, `None`. - ElectionFinalized(Option), - /// An account has been rewarded for their signed submission being finalized. - Rewarded(AccountId), - /// An account has been slashed for submitting an invalid signed submission. - Slashed(AccountId), - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for RawEvent { - #[inline] - fn clone(&self) -> RawEvent { - match (&*self,) { - (&RawEvent::SolutionStored(ref __self_0),) => { - RawEvent::SolutionStored(::core::clone::Clone::clone(&(*__self_0))) - } - (&RawEvent::ElectionFinalized(ref __self_0),) => { - RawEvent::ElectionFinalized(::core::clone::Clone::clone(&(*__self_0))) - } - (&RawEvent::Rewarded(ref __self_0),) => { - RawEvent::Rewarded(::core::clone::Clone::clone(&(*__self_0))) - } - (&RawEvent::Slashed(ref __self_0),) => { - RawEvent::Slashed(::core::clone::Clone::clone(&(*__self_0))) - } - } - } - } - impl ::core::marker::StructuralPartialEq for RawEvent {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for RawEvent { - #[inline] - fn eq(&self, other: &RawEvent) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &RawEvent::SolutionStored(ref __self_0), - &RawEvent::SolutionStored(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - ( - &RawEvent::ElectionFinalized(ref __self_0), - &RawEvent::ElectionFinalized(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - _ => unsafe { ::core::intrinsics::unreachable() }, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &RawEvent) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &RawEvent::SolutionStored(ref __self_0), - &RawEvent::SolutionStored(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - ( - &RawEvent::ElectionFinalized(ref __self_0), - &RawEvent::ElectionFinalized(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - _ => unsafe { ::core::intrinsics::unreachable() }, - } - } else { - true - } - } - } - } - impl ::core::marker::StructuralEq for RawEvent {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for RawEvent { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for RawEvent - where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - RawEvent::SolutionStored(ref aa) => { - dest.push_byte(0usize as u8); - dest.push(aa); - } - RawEvent::ElectionFinalized(ref aa) => { - dest.push_byte(1usize as u8); - dest.push(aa); - } - RawEvent::Rewarded(ref aa) => { - dest.push_byte(2usize as u8); - dest.push(aa); - } - RawEvent::Slashed(ref aa) => { - dest.push_byte(3usize as u8); - dest.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for RawEvent - where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for RawEvent - where - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(RawEvent::SolutionStored({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err( - "Error decoding field RawEvent :: SolutionStored.0".into() - ) - } - Ok(a) => a, - } - })), - x if x == 1usize as u8 => Ok(RawEvent::ElectionFinalized({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err( - "Error decoding field RawEvent :: ElectionFinalized.0".into() - ) - } - Ok(a) => a, - } - })), - x if x == 2usize as u8 => Ok(RawEvent::Rewarded({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field RawEvent :: Rewarded.0".into()) - } - Ok(a) => a, - } - })), - x if x == 3usize as u8 => Ok(RawEvent::Slashed({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field RawEvent :: Slashed.0".into()) - } - Ok(a) => a, - } - })), - x => Err("No such variant in enum RawEvent".into()), - } - } - } - }; - impl core::fmt::Debug for RawEvent - where - AccountId: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::SolutionStored(ref a0) => fmt - .debug_tuple("RawEvent::SolutionStored") - .field(a0) - .finish(), - Self::ElectionFinalized(ref a0) => fmt - .debug_tuple("RawEvent::ElectionFinalized") - .field(a0) - .finish(), - Self::Rewarded(ref a0) => fmt.debug_tuple("RawEvent::Rewarded").field(a0).finish(), - Self::Slashed(ref a0) => fmt.debug_tuple("RawEvent::Slashed").field(a0).finish(), - _ => Ok(()), - } - } - } - impl From> for () { - fn from(_: RawEvent) -> () { - () - } - } - impl RawEvent { - #[allow(dead_code)] - #[doc(hidden)] - pub fn metadata() -> &'static [::frame_support::event::EventMetadata] { - &[ - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("SolutionStored"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&[ - "ElectionCompute", - ]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" A solution was stored with the given compute.", - r"", - r" If the solution is signed, this means that it hasn't yet been processed. If the solution", - r" is unsigned, this means that it has also been processed.", - ]), - }, - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("ElectionFinalized"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&[ - "Option", - ]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" The election has been finalized, with `Some` of the given computation, or else if the", - r" election failed, `None`.", - ]), - }, - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("Rewarded"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" An account has been rewarded for their signed submission being finalized.", - ]), - }, - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("Slashed"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" An account has been slashed for submitting an invalid signed submission.", - ]), - }, - ] - } - } - pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>) - where - ExtendedBalance: From>>; - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Module - where - ExtendedBalance: From>>, - { - #[inline] - fn clone(&self) -> Module { - match *self { - Module(ref __self_0_0) => Module(::core::clone::Clone::clone(&(*__self_0_0))), - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for Module where - ExtendedBalance: From>> - { - } - impl ::core::marker::StructuralPartialEq for Module where - ExtendedBalance: From>> - { - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Module - where - ExtendedBalance: From>>, - { - #[inline] - fn eq(&self, other: &Module) -> bool { - match *other { - Module(ref __self_1_0) => match *self { - Module(ref __self_0_0) => (*__self_0_0) == (*__self_1_0), - }, - } - } - #[inline] - fn ne(&self, other: &Module) -> bool { - match *other { - Module(ref __self_1_0) => match *self { - Module(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), - }, - } - } - } - impl ::core::marker::StructuralEq for Module where - ExtendedBalance: From>> - { - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Module - where - ExtendedBalance: From>>, - { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq< - ::frame_support::sp_std::marker::PhantomData<(T,)>, - >; - } - } - } - impl core::fmt::Debug for Module - where - ExtendedBalance: From>>, - T: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_tuple("Module").field(&self.0).finish() - } - } - impl - ::frame_support::traits::OnInitialize<::BlockNumber> for Module - where - ExtendedBalance: From>>, - { - fn on_initialize(now: T::BlockNumber) -> Weight { - let __within_span__ = { - if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL - && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() - { - use ::tracing::__macro_support::*; - let callsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "on_initialize", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(407u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - static CALLSITE: MacroCallsite = MacroCallsite::new(&META); - CALLSITE.register(); - &CALLSITE - }; - if callsite.is_enabled() { - let meta = callsite.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - ::tracing::Span::none() - } - } else { - ::tracing::Span::none() - } - }; - let __tracing_guard__ = __within_span__.enter(); - { - let next_election = T::ElectionDataProvider::next_election_prediction(now); - let next_election = next_election.max(now); - let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); - let unsigned_deadline = T::UnsignedPhase::get(); - let remaining = next_election - now; - match Self::current_phase() { - Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { - CurrentPhase::put(Phase::Signed); - Self::start_signed_phase(); - } - Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { - let found_solution = Self::finalize_signed_phase(); - CurrentPhase::put(Phase::Unsigned(!found_solution)); - } - _ => {} - } - Default::default() - } - } - } - impl ::frame_support::traits::OnRuntimeUpgrade for Module where - ExtendedBalance: From>> - { - } - impl - ::frame_support::traits::OnFinalize<::BlockNumber> for Module - where - ExtendedBalance: From>>, - { - } - impl - ::frame_support::traits::OffchainWorker<::BlockNumber> for Module - where - ExtendedBalance: From>>, - { - fn offchain_worker(n: T::BlockNumber) {} - } - impl Module - where - ExtendedBalance: From>>, - { - /// Deposits an event using `frame_system::Module::deposit_event`. - fn deposit_event(event: impl Into<::Event>) { - >::deposit_event(event.into()) - } - } - #[cfg(feature = "std")] - impl ::frame_support::traits::IntegrityTest for Module where - ExtendedBalance: From>> - { - } - /// Can also be called using [`Call`]. - /// - /// [`Call`]: enum.Call.html - impl Module - where - ExtendedBalance: From>>, - { - /// Submit a solution for the signed phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// The solution potentially queued, based on the claimed score and processed at the end of - /// the signed phase. - /// - /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution - /// might be rewarded, slashed, or get all or a part of the deposit back. - /// - /// NOTE: Calling this function will bypass origin filters. - fn submit( - origin: T::Origin, - solution: RawSolution>, - ) -> DispatchResultWithPostInfo { - let __within_span__ = { - if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL - && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() - { - use ::tracing::__macro_support::*; - let callsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "submit", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(407u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - static CALLSITE: MacroCallsite = MacroCallsite::new(&META); - CALLSITE.register(); - &CALLSITE - }; - if callsite.is_enabled() { - let meta = callsite.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - ::tracing::Span::none() - } - } else { - ::tracing::Span::none() - } - }; - let __tracing_guard__ = __within_span__.enter(); - let who = ensure_signed(origin)?; - { - if !Self::current_phase().is_signed() { - { - return Err("EarlySubmission".into()); - }; - } - }; - let mut signed_submissions = Self::signed_submissions(); - let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution); - { - if !maybe_index.is_some() { - { - return Err("QueueFull".into()); - }; - } - }; - let index = maybe_index.expect("Option checked to be `Some`; qed."); - let deposit = signed_submissions[index].deposit; - T::Currency::reserve(&who, deposit).map_err(|_| "CannotPayDeposit")?; - if true { - if !(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()) { - { - :: std :: rt :: begin_panic ( "assertion failed: signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()" ) - } - }; - }; - >::put(signed_submissions); - Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Signed)); - Ok(None.into()) - } - #[allow(unreachable_code)] - /// Submit a solution for the unsigned phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. - /// Moreover, this unsigned solution is only validated when submitted to the pool from the - /// local process. Effectively, this means that only active validators can submit this - /// transaction when authoring a block. - /// - /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will - /// panic if the solution submitted by the validator is invalid, effectively putting their - /// authoring reward at risk. - /// - /// No deposit or reward is associated with this. - /// - /// NOTE: Calling this function will bypass origin filters. - fn submit_unsigned( - origin: T::Origin, - solution: RawSolution>, - ) -> ::frame_support::dispatch::DispatchResult { - let __within_span__ = { - if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL - && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() - { - use ::tracing::__macro_support::*; - let callsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "submit_unsigned", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(407u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - static CALLSITE: MacroCallsite = MacroCallsite::new(&META); - CALLSITE.register(); - &CALLSITE - }; - if callsite.is_enabled() { - let meta = callsite.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - ::tracing::Span::none() - } - } else { - ::tracing::Span::none() - } - }; - let __tracing_guard__ = __within_span__.enter(); - { - ensure_none(origin)?; - { - if !Self::current_phase().is_signed() { - { - return Err("EarlySubmission".into()); - }; - } - }; - use sp_npos_elections::is_score_better; - if !Self::queued_solution().map_or(true, |q| { - is_score_better( - solution.score, - q.score, - T::SolutionImprovementThreshold::get(), - ) - }) { - { - ::std::rt::begin_panic("WeakSolution") - } - }; - Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); - { - ::std::rt::begin_panic("not implemented") - } - } - Ok(()) - } - } - /// Dispatchable calls. - /// - /// Each variant of this enum maps to a dispatchable function from the associated module. - pub enum Call - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[codec(skip)] - __PhantomItem( - ::frame_support::sp_std::marker::PhantomData<(T,)>, - ::frame_support::Never, - ), - #[allow(non_camel_case_types)] - /// Submit a solution for the signed phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// The solution potentially queued, based on the claimed score and processed at the end of - /// the signed phase. - /// - /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution - /// might be rewarded, slashed, or get all or a part of the deposit back. - submit(RawSolution>), - #[allow(non_camel_case_types)] - /// Submit a solution for the unsigned phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. - /// Moreover, this unsigned solution is only validated when submitted to the pool from the - /// local process. Effectively, this means that only active validators can submit this - /// transaction when authoring a block. - /// - /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will - /// panic if the solution submitted by the validator is invalid, effectively putting their - /// authoring reward at risk. - /// - /// No deposit or reward is associated with this. - submit_unsigned(RawSolution>), - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - Call::submit(ref aa) => { - dest.push_byte(0usize as u8); - dest.push(aa); - } - Call::submit_unsigned(ref aa) => { - dest.push_byte(1usize as u8); - dest.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(Call::submit({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field Call :: submit.0".into()), - Ok(a) => a, - } - })), - x if x == 1usize as u8 => Ok(Call::submit_unsigned({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field Call :: submit_unsigned.0".into()) - } - Ok(a) => a, - } - })), - x => Err("No such variant in enum Call".into()), - } - } - } - }; - impl ::frame_support::dispatch::GetDispatchInfo for Call - where - ExtendedBalance: From>>, - { - fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { - match *self { - Call::submit(ref solution) => { - let base_weight = T::WeightInfo::submit(); - let weight = >, - )>>::weigh_data(&base_weight, (solution,)); - let class = >, - )>>::classify_dispatch(&base_weight, (solution,)); - let pays_fee = >, - )>>::pays_fee(&base_weight, (solution,)); - ::frame_support::dispatch::DispatchInfo { - weight, - class, - pays_fee, - } - } - Call::submit_unsigned(ref solution) => { - let base_weight = T::WeightInfo::submit_unsigned(); - let weight = >, - )>>::weigh_data(&base_weight, (solution,)); - let class = >, - )>>::classify_dispatch(&base_weight, (solution,)); - let pays_fee = >, - )>>::pays_fee(&base_weight, (solution,)); - ::frame_support::dispatch::DispatchInfo { - weight, - class, - pays_fee, - } - } - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"__PhantomItem should never be used.",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - } - } - } - impl ::frame_support::dispatch::GetCallName for Call - where - ExtendedBalance: From>>, - { - fn get_call_name(&self) -> &'static str { - match *self { - Call::submit(ref solution) => { - let _ = (solution); - "submit" - } - Call::submit_unsigned(ref solution) => { - let _ = (solution); - "submit_unsigned" - } - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"__PhantomItem should never be used.",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - } - } - fn get_call_names() -> &'static [&'static str] { - &["submit", "submit_unsigned"] - } - } - impl ::frame_support::dispatch::Clone for Call - where - ExtendedBalance: From>>, - { - fn clone(&self) -> Self { - match *self { - Call::submit(ref solution) => Call::submit((*solution).clone()), - Call::submit_unsigned(ref solution) => Call::submit_unsigned((*solution).clone()), - _ => ::std::rt::begin_panic("internal error: entered unreachable code"), - } - } - } - impl ::frame_support::dispatch::PartialEq for Call - where - ExtendedBalance: From>>, - { - fn eq(&self, _other: &Self) -> bool { - match *self { - Call::submit(ref solution) => { - let self_params = (solution,); - if let Call::submit(ref solution) = *_other { - self_params == (solution,) - } else { - match *_other { - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic("internal error: entered unreachable code") - } - _ => false, - } - } - } - Call::submit_unsigned(ref solution) => { - let self_params = (solution,); - if let Call::submit_unsigned(ref solution) = *_other { - self_params == (solution,) - } else { - match *_other { - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic("internal error: entered unreachable code") - } - _ => false, - } - } - } - _ => ::std::rt::begin_panic("internal error: entered unreachable code"), - } - } - } - impl ::frame_support::dispatch::Eq for Call where - ExtendedBalance: From>> - { - } - impl ::frame_support::dispatch::fmt::Debug for Call - where - ExtendedBalance: From>>, - { - fn fmt( - &self, - _f: &mut ::frame_support::dispatch::fmt::Formatter, - ) -> ::frame_support::dispatch::result::Result<(), ::frame_support::dispatch::fmt::Error> { - match *self { - Call::submit(ref solution) => _f.write_fmt(::core::fmt::Arguments::new_v1( - &["", ""], - &match (&"submit", &(solution.clone(),)) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), - ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), - ], - }, - )), - Call::submit_unsigned(ref solution) => { - _f.write_fmt(::core::fmt::Arguments::new_v1( - &["", ""], - &match (&"submit_unsigned", &(solution.clone(),)) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), - ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), - ], - }, - )) - } - _ => ::std::rt::begin_panic("internal error: entered unreachable code"), - } - } - } - impl ::frame_support::traits::UnfilteredDispatchable for Call - where - ExtendedBalance: From>>, - { - type Origin = T::Origin; - fn dispatch_bypass_filter( - self, - _origin: Self::Origin, - ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { - match self { - Call::submit(solution) => >::submit(_origin, solution) - .map(Into::into) - .map_err(Into::into), - Call::submit_unsigned(solution) => >::submit_unsigned(_origin, solution) - .map(Into::into) - .map_err(Into::into), - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"__PhantomItem should never be used.",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - } - } - } - impl ::frame_support::dispatch::Callable for Module - where - ExtendedBalance: From>>, - { - type Call = Call; - } - impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[allow(dead_code)] - pub fn call_functions() -> &'static [::frame_support::dispatch::FunctionMetadata] { - &[ - ::frame_support::dispatch::FunctionMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("submit"), - arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - ::frame_support::dispatch::FunctionArgumentMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), - ty: ::frame_support::dispatch::DecodeDifferent::Encode( - "RawSolution>", - ), - }, - ]), - documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - r" Submit a solution for the signed phase.", - r"", - r" The dispatch origin fo this call must be __signed__.", - r"", - r" The solution potentially queued, based on the claimed score and processed at the end of", - r" the signed phase.", - r"", - r" A deposit is reserved and recorded for the solution. Based on the outcome, the solution", - r" might be rewarded, slashed, or get all or a part of the deposit back.", - ]), - }, - ::frame_support::dispatch::FunctionMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("submit_unsigned"), - arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - ::frame_support::dispatch::FunctionArgumentMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), - ty: ::frame_support::dispatch::DecodeDifferent::Encode( - "RawSolution>", - ), - }, - ]), - documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - r" Submit a solution for the unsigned phase.", - r"", - r" The dispatch origin fo this call must be __signed__.", - r"", - r" This submission is checked on the fly, thus it is likely yo be more limited and smaller.", - r" Moreover, this unsigned solution is only validated when submitted to the pool from the", - r" local process. Effectively, this means that only active validators can submit this", - r" transaction when authoring a block.", - r"", - r" To prevent any incorrect solution (and thus wasted time/weight), this transaction will", - r" panic if the solution submitted by the validator is invalid, effectively putting their", - r" authoring reward at risk.", - r"", - r" No deposit or reward is associated with this.", - ]), - }, - ] - } - } - impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[allow(dead_code)] - pub fn module_constants_metadata( - ) -> &'static [::frame_support::dispatch::ModuleConstantMetadata] { - &[] - } - } - impl ::frame_support::dispatch::ModuleErrorMetadata for Module - where - ExtendedBalance: From>>, - { - fn metadata() -> &'static [::frame_support::dispatch::ErrorMetadata] { - <&'static str as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() - } - } - impl Module - where - ExtendedBalance: From>>, - { - /// Checks the feasibility of a solution. - /// - /// This checks the solution for the following: - /// - /// 0. **all** of the used indices must be correct. - /// 1. present correct number of winners. - /// 2. any assignment is checked to match with `SnapshotVoters`. - /// 3. for each assignment, the check of `ElectionDataProvider` is also examined. - /// 4. the claimed score is valid. - fn feasibility_check( - solution: RawSolution>, - compute: ElectionCompute, - ) -> Result, FeasibilityError> { - let RawSolution { compact, score } = solution; - let winners = compact.unique_targets(); - { - if !(winners.len() as u32 == Self::desired_targets()) { - { - return Err(FeasibilityError::WrongWinnerCount.into()); - }; - } - }; - let snapshot_voters = - Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; - let snapshot_targets = - Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - use sp_runtime::traits::UniqueSaturatedInto; - let voter_at = |i: CompactVoterIndexOf| -> Option { - snapshot_voters - .get(i.unique_saturated_into()) - .map(|(x, _, _)| x) - .cloned() - }; - let target_at = |i: CompactTargetIndexOf| -> Option { - snapshot_targets.get(i.unique_saturated_into()).cloned() - }; - let winners = winners - .into_iter() - .map(|i| target_at(i).ok_or(FeasibilityError::InvalidWinner)) - .collect::, FeasibilityError>>()?; - let assignments = compact - .into_assignment(voter_at, target_at) - .map_err::(Into::into)?; - let _ = assignments - .iter() - .map(|Assignment { who, distribution }| { - snapshot_voters.iter().find(|(v, _, _)| v == who).map_or( - Err(FeasibilityError::InvalidVoter), - |(_, _, t)| { - if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) - && T::ElectionDataProvider::feasibility_check_assignment::< - CompactAccuracyOf, - >(who, distribution) - { - Ok(()) - } else { - Err(FeasibilityError::InvalidVote) - } - }, - ) - }) - .collect::>()?; - let stake_of = |who: &T::AccountId| -> crate::VoteWeight { - snapshot_voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - }; - let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) - .map_err::(Into::into)?; - let supports = build_support_map(&winners, &staked_assignments) - .map(FlattenSupportMap::flatten) - .map_err::(Into::into)?; - let known_score = - evaluate_support::(supports.iter().map(|&(ref x, ref y)| (x, y))); - { - if !(known_score == score) { - { - return Err(FeasibilityError::InvalidScore.into()); - }; - } - }; - Ok(ReadySolution { supports, compute }) - } - /// On-chain fallback of election. - fn onchain_fallback() -> Result, Error> { - let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - >::elect::( - desired_targets, - targets, - voters, - ) - .map_err(Into::into) - } - } - impl crate::ElectionProvider for Module - where - ExtendedBalance: From>>, - { - type Error = Error; - const NEEDS_ELECT_DATA: bool = false; - fn elect( - _to_elect: usize, - _targets: Vec, - _voters: Vec<(T::AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>, - { - Self::queued_solution() - .map_or_else( - || { - Self::onchain_fallback() - .map(|r| (r, ElectionCompute::OnChain)) - .map_err(Into::into) - }, - |ReadySolution { - supports, compute, .. - }| Ok((supports, compute)), - ) - .map(|(supports, compute)| { - CurrentPhase::put(Phase::Off); - >::kill(); - >::kill(); - Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); - supports - }) - .map_err(|err| { - Self::deposit_event(RawEvent::ElectionFinalized(None)); - err - }) - } - fn ongoing() -> bool { - match Self::current_phase() { - Phase::Signed | Phase::Unsigned(_) => true, - _ => false, - } - } - } + //! # Two phase election provider pallet. + //! + //! As the name suggests, this election provider has two distinct phases (see [`Phase`]), signed and + //! unsigned. + //! + //! ## Phases + //! + //! The timeline of pallet is as follows. At each block, + //! [`ElectionDataProvider::next_election_prediction`] is used to estimate the time remaining to the + //! next call to `elect`. Based on this, a phase is chosen. The timeline is as follows. + //! + //! ```ignore + //! elect() + //! + <--T::SignedPhase--> + <--T::UnsignedPhase--> + + //! +-------------------------------------------------------------------+ + //! Phase::Off + Phase::Signed + Phase::Unsigned + + //! + //! Note that the unsigned phase starts `T::UnsignedPhase` blocks before the + //! `next_election_prediction`, but only ends when a call to `ElectionProvider::elect` happens. + //! + //! ``` + //! ### Signed Phase + //! + //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A + //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution + //! on-chain for a number of blocks. A maximum of [`Trait::MaxSignedSubmissions`] solutions are + //! stored. The queue is always sorted based on score (worse -> best). + //! + //! Upon arrival of a new solution: + //! + //! 1. If the queue is not full, it is stored. + //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the + //! worse solution is discarded (TODO: what to do with the bond?) and the new solution is stored + //! in the correct index. + //! 3. If the queue is full and the solution is not an improvement compared to any of the queued + //! ones, it is instantly rejected and no additional bond is reserved. + //! + //! A signed solution cannot be reversed, taken back, updated, or retracted. In other words, the + //! origin can not bail out in any way. + //! + //! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed + //! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure + //! the score claimed by this score was correct, among other checks. At each step, if the current + //! best solution is passes the feasibility check, it is considered to be the best one. The sender + //! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without + //! being checked. + //! + //! The following example covers all of the cases at the end of the signed phase: + //! + //! ```ignore + //! Queue + //! +-------------------------------+ + //! |Solution(score=20, valid=false)| +--> Slashed + //! +-------------------------------+ + //! |Solution(score=15, valid=true )| +--> Rewarded + //! +-------------------------------+ + //! |Solution(score=10, valid=true )| +--> Discarded + //! +-------------------------------+ + //! |Solution(score=05, valid=false)| +--> Discarded + //! +-------------------------------+ + //! | None | + //! +-------------------------------+ + //! ``` + //! + //! Note that both of the bottom solutions end up being discarded and get their deposit back, + //! despite one of them being invalid. + //! + //! ## Unsigned Phase + //! + //! If signed phase ends with a good solution, then the unsigned phase will be `active` + //! ([`Phase::Unsigned(true)`]), else the unsigned phase will be `passive`. + //! + //! TODO + //! + //! ### Fallback + //! + //! If we reach the end of both phases (i.e. call to `ElectionProvider::elect` happens) and no good + //! solution is queued, then we fallback to an on-chain election. The on-chain election is slow, and + //! contains to balancing or reduction post-processing. + //! + //! ## Correct Submission + //! + //! TODO + //! + //! ## Accuracy + //! + //! TODO + //! + use crate::onchain::OnChainSequentialPhragmen; + use codec::{Decode, Encode, HasCompact}; + use frame_support::{ + decl_event, decl_module, decl_storage, + dispatch::{DispatchResultWithPostInfo, Dispatchable}, + ensure, + traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, + weights::Weight, + }; + use frame_system::{ensure_none, ensure_signed}; + use sp_election_providers::{ElectionDataProvider, ElectionProvider}; + use sp_npos_elections::{ + assignment_ratio_to_staked_normalized, is_score_better, Assignment, CompactSolution, + ElectionScore, EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, + }; + use sp_runtime::{ + traits::Zero, transaction_validity::TransactionPriority, InnerOf, PerThing, Perbill, + RuntimeDebug, + }; + use sp_std::prelude::*; + #[macro_use] + pub(crate) mod macros { + //! Some helper macros for this crate. + } + pub mod signed { + //! The signed phase implementation. + use crate::two_phase::*; + use codec::Encode; + use sp_arithmetic::traits::SaturatedConversion; + use sp_npos_elections::is_score_better; + use sp_runtime::Perbill; + impl Module + where + ExtendedBalance: From>>, + { + /// Start the signed phase. + /// + /// Upon calling this, auxillary data for election is stored and signed solutions will be + /// accepted. + /// + /// The signed phase must always start before the unsigned phase. + pub fn start_signed_phase() { + let targets = T::ElectionDataProvider::targets(); + let voters = T::ElectionDataProvider::voters(); + let desired_targets = T::ElectionDataProvider::desired_targets(); + >::put(targets); + >::put(voters); + DesiredTargets::put(desired_targets); + } + /// Finish the singed phase. Process the signed submissions from best to worse until a valid one + /// is found, rewarding the best oen and slashing the invalid ones along the way. + /// + /// Returns true if we have a good solution in the signed phase. + /// + /// This drains the [`SignedSubmissions`], potentially storing the best valid one in + /// [`QueuedSolution`]. + pub fn finalize_signed_phase() -> bool { + let mut all_submission: Vec> = + >::take(); + let mut found_solution = false; + while let Some(best) = all_submission.pop() { + let SignedSubmission { + solution, + who, + deposit, + reward, + } = best; + match Self::feasibility_check(solution, ElectionCompute::Signed) { + Ok(ready_solution) => { + >::put(ready_solution); + let _remaining = T::Currency::unreserve(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic( + "assertion failed: _remaining.is_zero()", + ) + } + }; + }; + let positive_imbalance = T::Currency::deposit_creating(&who, reward); + T::RewardHandler::on_unbalanced(positive_imbalance); + found_solution = true; + break; + } + Err(_) => { + let (negative_imbalance, _remaining) = + T::Currency::slash_reserved(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic( + "assertion failed: _remaining.is_zero()", + ) + } + }; + }; + T::SlashHandler::on_unbalanced(negative_imbalance); + } + } + } + all_submission.into_iter().for_each(|not_processed| { + let SignedSubmission { who, deposit, .. } = not_processed; + let _remaining = T::Currency::unreserve(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic("assertion failed: _remaining.is_zero()") + } + }; + }; + }); + found_solution + } + /// Find a proper position in the queue for the signed queue, whilst maintaining the order of + /// solution quality. + /// + /// The length of the queue will always be kept less than or equal to `T::MaxSignedSubmissions`. + pub fn insert_submission( + who: &T::AccountId, + queue: &mut Vec, CompactOf>>, + solution: RawSolution>, + ) -> Option { + let outcome = queue + .iter() + .enumerate() + .rev() + .find_map(|(i, s)| { + if is_score_better::( + solution.score, + s.solution.score, + T::SolutionImprovementThreshold::get(), + ) { + Some(i + 1) + } else { + None + } + }) + .or(Some(0)) + .and_then(|at| { + if at == 0 && queue.len() as u32 >= T::MaxSignedSubmissions::get() { + None + } else { + let reward = Self::reward_for(&solution); + let deposit = Self::deposit_for(&solution); + let submission = SignedSubmission { + who: who.clone(), + deposit, + reward, + solution, + }; + queue.insert(at, submission); + if queue.len() as u32 > T::MaxSignedSubmissions::get() { + queue.remove(0); + Some(at - 1) + } else { + Some(at) + } + } + }); + if true { + if !(queue.len() as u32 <= T::MaxSignedSubmissions::get()) { + { + :: std :: rt :: begin_panic ( "assertion failed: queue.len() as u32 <= T::MaxSignedSubmissions::get()" ) + } + }; + }; + outcome + } + /// Collect sufficient deposit to store this solution this chain. + /// + /// The deposit is composed of 3 main elements: + /// + /// 1. base deposit, fixed for all submissions. + /// 2. a per-byte deposit, for renting the state usage. + /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize + pub fn deposit_for(solution: &RawSolution>) -> BalanceOf { + let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); + let feasibility_weight = T::WeightInfo::feasibility_check(); + let len_deposit = T::SignedDepositByte::get() * encoded_len; + let weight_deposit = + T::SignedDepositWeight::get() * feasibility_weight.saturated_into(); + T::SignedDepositBase::get() + len_deposit + weight_deposit + } + /// The reward for this solution, if successfully chosen as the best one at the end of the + /// signed phase. + pub fn reward_for(solution: &RawSolution>) -> BalanceOf { + T::SignedRewardBase::get() + + T::SignedRewardFactor::get() + * solution.score[0].saturated_into::>() + } + } + } + pub mod unsigned { + //! The unsigned phase implementation. + use crate::two_phase::*; + use frame_support::{dispatch::DispatchResult, unsigned::ValidateUnsigned}; + use sp_npos_elections::{seq_phragmen, CompactSolution, ElectionResult}; + use sp_runtime::{ + traits::TrailingZeroInput, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, + TransactionValidityError, ValidTransaction, + }, + PerU16, SaturatedConversion, + }; + use sp_std::cmp::Ordering; + /// Witness data about the size of the election. + /// + /// This is needed for proper weight calculation. + pub struct WitnessData { + /// Number of all voters. + /// + /// This must match the on-chain snapshot. + #[codec(compact)] + voters: u32, + /// Number of all targets. + /// + /// This must match the on-chain snapshot. + #[codec(compact)] + target: u32, + } + impl ::core::marker::StructuralPartialEq for WitnessData {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for WitnessData { + #[inline] + fn eq(&self, other: &WitnessData) -> bool { + match *other { + WitnessData { + voters: ref __self_1_0, + target: ref __self_1_1, + } => match *self { + WitnessData { + voters: ref __self_0_0, + target: ref __self_0_1, + } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), + }, + } + } + #[inline] + fn ne(&self, other: &WitnessData) -> bool { + match *other { + WitnessData { + voters: ref __self_1_0, + target: ref __self_1_1, + } => match *self { + WitnessData { + voters: ref __self_0_0, + target: ref __self_0_1, + } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), + }, + } + } + } + impl ::core::marker::StructuralEq for WitnessData {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for WitnessData { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for WitnessData { + #[inline] + fn clone(&self) -> WitnessData { + { + let _: ::core::clone::AssertParamIsClone; + let _: ::core::clone::AssertParamIsClone; + *self + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for WitnessData {} + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for WitnessData { + fn encode_to(&self, dest: &mut EncOut) { + { + dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . voters ) ) ; + } + { + dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . target ) ) ; + } + } + } + impl _parity_scale_codec::EncodeLike for WitnessData {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for WitnessData { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(WitnessData { + voters: { + let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; + match res { + Err(_) => { + return Err("Error decoding field WitnessData.voters".into()) + } + Ok(a) => a.into(), + } + }, + target: { + let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; + match res { + Err(_) => { + return Err("Error decoding field WitnessData.target".into()) + } + Ok(a) => a.into(), + } + }, + }) + } + } + }; + impl core::fmt::Debug for WitnessData { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("WitnessData") + .field("voters", &self.voters) + .field("target", &self.target) + .finish() + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for WitnessData { + #[inline] + fn default() -> WitnessData { + WitnessData { + voters: ::core::default::Default::default(), + target: ::core::default::Default::default(), + } + } + } + /// Storage key used to store the persistent offchain worker status. + pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; + /// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice + /// within a window of 5 blocks. + pub(crate) const OFFCHAIN_REPEAT: u32 = 5; + /// Default number of blocks for which the unsigned transaction should stay in the pool + pub(crate) const DEFAULT_LONGEVITY: u64 = 25; + impl Module + where + ExtendedBalance: From>>, + { + /// Min a new npos solution. + pub fn mine_solution(iters: usize) -> Result>, Error> { + let desired_targets = Self::desired_targets() as usize; + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + seq_phragmen::<_, CompactAccuracyOf>( + desired_targets, + targets, + voters, + Some((iters, 0)), + ) + .map_err(Into::into) + .and_then(Self::prepare_election_result) + } + /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which + /// is ready to be submitted to the chain. + /// + /// Will always reduce the solution as well. + pub fn prepare_election_result( + election_result: ElectionResult>, + ) -> Result>, Error> { + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + let voter_index = + |who: &T::AccountId| -> Option> { + voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < T > > > :: try_into ( i ) . ok ( ) ) + }; + let target_index = + |who: &T::AccountId| -> Option> { + targets . iter ( ) . position ( | x | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactTargetIndexOf < T > > > :: try_into ( i ) . ok ( ) ) + }; + let voter_at = + |i: crate::two_phase::CompactVoterIndexOf| -> Option { + < crate :: two_phase :: CompactVoterIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | voters . get ( i ) . map ( | ( x , _ , _ ) | x ) . cloned ( ) ) + }; + let target_at = + |i: crate::two_phase::CompactTargetIndexOf| -> Option { + < crate :: two_phase :: CompactTargetIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | targets . get ( i ) . cloned ( ) ) + }; + let stake_of = |who: &T::AccountId| -> crate::VoteWeight { + voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + }; + let ElectionResult { + assignments, + winners, + } = election_result; + let mut staked = sp_npos_elections::assignment_ratio_to_staked_normalized( + assignments, + &stake_of, + ) + .map_err::(Into::into)?; + sp_npos_elections::reduce(&mut staked); + let ratio = sp_npos_elections::assignment_staked_to_ratio_normalized(staked)?; + let compact = >::from_assignment(ratio, &voter_index, &target_index)?; + let maximum_allowed_voters = + Self::maximum_compact_len::(0, Default::default(), 0); + let compact = Self::trim_compact(compact.len() as u32, compact, &voter_index)?; + let winners = sp_npos_elections::to_without_backing(winners); + let score = compact + .clone() + .score(&winners, stake_of, voter_at, target_at)?; + Ok(RawSolution { compact, score }) + } + /// Get a random number of iterations to run the balancing in the OCW. + /// + /// Uses the offchain seed to generate a random number, maxed with `T::UnsignedMaxIterations`. + pub fn get_balancing_iters() -> usize { + match T::UnsignedMaxIterations::get() { + 0 => 0, + max @ _ => { + let seed = sp_io::offchain::random_seed(); + let random = ::decode(&mut TrailingZeroInput::new(seed.as_ref())) + .expect("input is padded with zeroes; qed") + % max.saturating_add(1); + random as usize + } + } + } + /// Greedily reduce the size of the a solution to fit into the block, w.r.t. weight. + /// + /// The weight of the solution is foremost a function of the number of voters (i.e. + /// `compact.len()`). Aside from this, the other components of the weight are invariant. The + /// number of winners shall not be changed (otherwise the solution is invalid) and the + /// `ElectionSize` is merely a representation of the total number of stakers. + /// + /// Thus, we reside to stripping away some voters. This means only changing the `compact` + /// struct. + /// + /// Note that the solution is already computed, and the winners are elected based on the merit + /// of teh entire stake in the system. Nonetheless, some of the voters will be removed further + /// down the line. + /// + /// Indeed, the score must be computed **after** this step. If this step reduces the score too + /// much, then the solution will be discarded. + pub fn trim_compact( + maximum_allowed_voters: u32, + mut compact: CompactOf, + nominator_index: FN, + ) -> Result, Error> + where + for<'r> FN: Fn(&'r T::AccountId) -> Option>, + { + match compact.len().checked_sub(maximum_allowed_voters as usize) { + Some(to_remove) if to_remove > 0 => { + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let mut voters_sorted = voters + .into_iter() + .map(|(who, stake, _)| (who.clone(), stake)) + .collect::>(); + voters_sorted.sort_by_key(|(_, y)| *y); + let mut removed = 0; + for (maybe_index, _stake) in voters_sorted + .iter() + .map(|(who, stake)| (nominator_index(&who), stake)) + { + let index = maybe_index.ok_or(Error::SnapshotUnAvailable)?; + if compact.remove_voter(index) { + removed += 1 + } + if removed >= to_remove { + break; + } + } + Ok(compact) + } + _ => Ok(compact), + } + } + /// Find the maximum `len` that a compact can have in order to fit into the block weight. + /// + /// This only returns a value between zero and `size.nominators`. + pub fn maximum_compact_len( + _winners_len: u32, + witness: WitnessData, + max_weight: Weight, + ) -> u32 { + if witness.voters < 1 { + return witness.voters; + } + let max_voters = witness.voters.max(1); + let mut voters = max_voters; + let weight_with = |_voters: u32| -> Weight { W::submit_unsigned() }; + let next_voters = + |current_weight: Weight, voters: u32, step: u32| -> Result { + match current_weight.cmp(&max_weight) { + Ordering::Less => { + let next_voters = voters.checked_add(step); + match next_voters { + Some(voters) if voters < max_voters => Ok(voters), + _ => Err(()), + } + } + Ordering::Greater => voters.checked_sub(step).ok_or(()), + Ordering::Equal => Ok(voters), + } + }; + let mut step = voters / 2; + let mut current_weight = weight_with(voters); + while step > 0 { + match next_voters(current_weight, voters, step) { + Ok(next) if next != voters => { + voters = next; + } + Err(()) => { + break; + } + Ok(next) => return next, + } + step = step / 2; + current_weight = weight_with(voters); + } + while voters + 1 <= max_voters && weight_with(voters + 1) < max_weight { + voters += 1; + } + while voters.checked_sub(1).is_some() && weight_with(voters) > max_weight { + voters -= 1; + } + if true { + if !(weight_with(voters.min(witness.voters)) <= max_weight) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["weight_with(", ") <= "], + &match (&voters.min(witness.voters), &max_weight) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Display::fmt, + ), + ], + }, + )) + } + }; + }; + voters.min(witness.voters) + } + /// Checks if an execution of the offchain worker is permitted at the given block number, or not. + /// + /// This essentially makes sure that we don't run on previous blocks in case of a re-org, and we + /// don't run twice within a window of length [`OFFCHAIN_REPEAT`]. + /// + /// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise. + pub(crate) fn set_check_offchain_execution_status( + now: T::BlockNumber, + ) -> Result<(), &'static str> { + let storage = + sp_runtime::offchain::storage::StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); + let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); + let mutate_stat = storage.mutate::<_, &'static str, _>( + |maybe_head: Option>| match maybe_head { + Some(Some(head)) if now < head => Err("fork."), + Some(Some(head)) if now >= head && now <= head + threshold => { + Err("recently executed.") + } + Some(Some(head)) if now > head + threshold => Ok(now), + _ => Ok(now), + }, + ); + match mutate_stat { + Ok(Ok(_)) => Ok(()), + Ok(Err(_)) => Err("failed to write to offchain db."), + Err(why) => Err(why), + } + } + /// Mine a new solution, and submit it back to the chian as an unsigned transaction. + pub(crate) fn mine_and_submit() -> Result<(), Error> { + let balancing = Self::get_balancing_iters(); + Self::mine_solution(balancing).map(|raw_solution| ()) + } + pub(crate) fn pre_dispatch_checks( + solution: &RawSolution>, + ) -> DispatchResult { + { + if !Self::current_phase().is_unsigned_open() { + { + return Err("UnsignedPhaseClosed".into()); + }; + } + }; + { + if !Self::queued_solution().map_or(true, |q: ReadySolution<_>| { + is_score_better::( + solution.score, + q.score, + T::SolutionImprovementThreshold::get(), + ) + }) { + { + return Err("WeakSolution".into()); + }; + } + }; + Ok(()) + } + } + #[allow(deprecated)] + impl ValidateUnsigned for Module + where + ExtendedBalance: From>>, + { + type Call = Call; + fn validate_unsigned( + source: TransactionSource, + call: &Self::Call, + ) -> TransactionValidity { + if let Call::submit_unsigned(solution) = call { + match source { + TransactionSource::Local | TransactionSource::InBlock => {} + _ => { + return InvalidTransaction::Call.into(); + } + } + if let Err(_why) = Self::pre_dispatch_checks(solution) { + return InvalidTransaction::Custom(99).into(); + } + ValidTransaction::with_tag_prefix("OffchainElection") + .priority( + T::UnsignedPriority::get() + .saturating_add(solution.score[0].saturated_into()), + ) + .longevity(DEFAULT_LONGEVITY) + .propagate(false) + .build() + } else { + InvalidTransaction::Call.into() + } + } + fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { + if let Call::submit_unsigned(solution) = call { + Self::pre_dispatch_checks(solution) + .map_err(|_| InvalidTransaction::Custom(99).into()) + } else { + Err(InvalidTransaction::Call.into()) + } + } + } + } + /// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] + /// implementer. + pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< + ::AccountId, + ::BlockNumber, + >>::CompactSolution; + /// The voter index. Derived from [`CompactOf`]. + pub type CompactVoterIndexOf = as CompactSolution>::Voter; + /// The target index. Derived from [`CompactOf`]. + pub type CompactTargetIndexOf = as CompactSolution>::Target; + /// The accuracy of the election. Derived from [`CompactOf`]. + pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; + type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + type PositiveImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::PositiveImbalance; + type NegativeImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::NegativeImbalance; + /// Current phase of the pallet. + pub enum Phase { + /// Nothing, the election is not happening. + Off, + /// Signed phase is open. + Signed, + /// Unsigned phase is open. + Unsigned((bool, Bn)), + } + impl ::core::marker::StructuralPartialEq for Phase {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Phase { + #[inline] + fn eq(&self, other: &Phase) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &Phase) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + _ => false, + } + } else { + true + } + } + } + } + impl ::core::marker::StructuralEq for Phase {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Phase { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq<(bool, Bn)>; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Phase { + #[inline] + fn clone(&self) -> Phase { + match (&*self,) { + (&Phase::Off,) => Phase::Off, + (&Phase::Signed,) => Phase::Signed, + (&Phase::Unsigned(ref __self_0),) => { + Phase::Unsigned(::core::clone::Clone::clone(&(*__self_0))) + } + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for Phase {} + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for Phase + where + Bn: _parity_scale_codec::Encode, + (bool, Bn): _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + Phase::Off => { + dest.push_byte(0usize as u8); + } + Phase::Signed => { + dest.push_byte(1usize as u8); + } + Phase::Unsigned(ref aa) => { + dest.push_byte(2usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for Phase + where + Bn: _parity_scale_codec::Encode, + (bool, Bn): _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for Phase + where + Bn: _parity_scale_codec::Decode, + (bool, Bn): _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(Phase::Off), + x if x == 1usize as u8 => Ok(Phase::Signed), + x if x == 2usize as u8 => Ok(Phase::Unsigned({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field Phase :: Unsigned.0".into()), + Ok(a) => a, + } + })), + x => Err("No such variant in enum Phase".into()), + } + } + } + }; + impl core::fmt::Debug for Phase + where + Bn: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::Off => fmt.debug_tuple("Phase::Off").finish(), + Self::Signed => fmt.debug_tuple("Phase::Signed").finish(), + Self::Unsigned(ref a0) => fmt.debug_tuple("Phase::Unsigned").field(a0).finish(), + _ => Ok(()), + } + } + } + impl Default for Phase { + fn default() -> Self { + Phase::Off + } + } + impl Phase { + /// Weather the phase is signed or not. + pub fn is_signed(&self) -> bool { + match self { + Phase::Signed => true, + _ => false, + } + } + /// Weather the phase is unsigned or not. + pub fn is_unsigned(&self) -> bool { + match self { + Phase::Unsigned(_) => true, + _ => false, + } + } + /// Weather the phase is unsigned and open or not, with specific start. + pub fn is_unsigned_open_at(&self, at: Bn) -> bool { + match self { + Phase::Unsigned((true, real)) if *real == at => true, + _ => false, + } + } + /// Weather the phase is unsigned and open or not. + pub fn is_unsigned_open(&self) -> bool { + match self { + Phase::Unsigned((true, _)) => true, + _ => false, + } + } + /// Weather the phase is off or not. + pub fn is_off(&self) -> bool { + match self { + Phase::Off => true, + _ => false, + } + } + } + /// The type of `Computation` that provided this election data. + pub enum ElectionCompute { + /// Election was computed on-chain. + OnChain, + /// Election was computed with a signed submission. + Signed, + /// Election was computed with an unsigned submission. + Unsigned, + } + impl ::core::marker::StructuralPartialEq for ElectionCompute {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for ElectionCompute { + #[inline] + fn eq(&self, other: &ElectionCompute) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + _ => true, + } + } else { + false + } + } + } + } + impl ::core::marker::StructuralEq for ElectionCompute {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for ElectionCompute { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + {} + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for ElectionCompute { + #[inline] + fn clone(&self) -> ElectionCompute { + { + *self + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for ElectionCompute {} + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for ElectionCompute { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + ElectionCompute::OnChain => { + dest.push_byte(0usize as u8); + } + ElectionCompute::Signed => { + dest.push_byte(1usize as u8); + } + ElectionCompute::Unsigned => { + dest.push_byte(2usize as u8); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for ElectionCompute {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for ElectionCompute { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(ElectionCompute::OnChain), + x if x == 1usize as u8 => Ok(ElectionCompute::Signed), + x if x == 2usize as u8 => Ok(ElectionCompute::Unsigned), + x => Err("No such variant in enum ElectionCompute".into()), + } + } + } + }; + impl core::fmt::Debug for ElectionCompute { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::OnChain => fmt.debug_tuple("ElectionCompute::OnChain").finish(), + Self::Signed => fmt.debug_tuple("ElectionCompute::Signed").finish(), + Self::Unsigned => fmt.debug_tuple("ElectionCompute::Unsigned").finish(), + _ => Ok(()), + } + } + } + impl Default for ElectionCompute { + fn default() -> Self { + ElectionCompute::OnChain + } + } + /// A raw, unchecked solution. + /// + /// Such a solution should never become effective in anyway before being checked by the + /// [`Module::feasibility_check`] + pub struct RawSolution { + /// Compact election edges. + compact: C, + /// The _claimed_ score of the solution. + score: ElectionScore, + } + impl ::core::marker::StructuralPartialEq for RawSolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for RawSolution { + #[inline] + fn eq(&self, other: &RawSolution) -> bool { + match *other { + RawSolution { + compact: ref __self_1_0, + score: ref __self_1_1, + } => match *self { + RawSolution { + compact: ref __self_0_0, + score: ref __self_0_1, + } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), + }, + } + } + #[inline] + fn ne(&self, other: &RawSolution) -> bool { + match *other { + RawSolution { + compact: ref __self_1_0, + score: ref __self_1_1, + } => match *self { + RawSolution { + compact: ref __self_0_0, + score: ref __self_0_1, + } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), + }, + } + } + } + impl ::core::marker::StructuralEq for RawSolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for RawSolution { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for RawSolution { + #[inline] + fn clone(&self) -> RawSolution { + match *self { + RawSolution { + compact: ref __self_0_0, + score: ref __self_0_1, + } => RawSolution { + compact: ::core::clone::Clone::clone(&(*__self_0_0)), + score: ::core::clone::Clone::clone(&(*__self_0_1)), + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for RawSolution + where + C: _parity_scale_codec::Encode, + C: _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + dest.push(&self.compact); + dest.push(&self.score); + } + } + impl _parity_scale_codec::EncodeLike for RawSolution + where + C: _parity_scale_codec::Encode, + C: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for RawSolution + where + C: _parity_scale_codec::Decode, + C: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(RawSolution { + compact: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field RawSolution.compact".into()), + Ok(a) => a, + } + }, + score: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field RawSolution.score".into()), + Ok(a) => a, + } + }, + }) + } + } + }; + impl core::fmt::Debug for RawSolution + where + C: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("RawSolution") + .field("compact", &self.compact) + .field("score", &self.score) + .finish() + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for RawSolution { + #[inline] + fn default() -> RawSolution { + RawSolution { + compact: ::core::default::Default::default(), + score: ::core::default::Default::default(), + } + } + } + /// A raw, unchecked signed submission. + /// + /// This is just a wrapper around [`RawSolution`] and some additional info. + pub struct SignedSubmission { + /// Who submitted this solution. + who: A, + /// The deposit reserved for storing this solution. + deposit: B, + /// The reward that should be given to this solution, if chosen the as the final one. + reward: B, + /// The raw solution itself. + solution: RawSolution, + } + impl ::core::marker::StructuralPartialEq for SignedSubmission {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl< + A: ::core::cmp::PartialEq, + B: ::core::cmp::PartialEq + HasCompact, + C: ::core::cmp::PartialEq, + > ::core::cmp::PartialEq for SignedSubmission + { + #[inline] + fn eq(&self, other: &SignedSubmission) -> bool { + match *other { + SignedSubmission { + who: ref __self_1_0, + deposit: ref __self_1_1, + reward: ref __self_1_2, + solution: ref __self_1_3, + } => match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + && (*__self_0_3) == (*__self_1_3) + } + }, + } + } + #[inline] + fn ne(&self, other: &SignedSubmission) -> bool { + match *other { + SignedSubmission { + who: ref __self_1_0, + deposit: ref __self_1_1, + reward: ref __self_1_2, + solution: ref __self_1_3, + } => match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) + || (*__self_0_2) != (*__self_1_2) + || (*__self_0_3) != (*__self_1_3) + } + }, + } + } + } + impl ::core::marker::StructuralEq for SignedSubmission {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq + for SignedSubmission + { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq>; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl< + A: ::core::clone::Clone, + B: ::core::clone::Clone + HasCompact, + C: ::core::clone::Clone, + > ::core::clone::Clone for SignedSubmission + { + #[inline] + fn clone(&self) -> SignedSubmission { + match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => SignedSubmission { + who: ::core::clone::Clone::clone(&(*__self_0_0)), + deposit: ::core::clone::Clone::clone(&(*__self_0_1)), + reward: ::core::clone::Clone::clone(&(*__self_0_2)), + solution: ::core::clone::Clone::clone(&(*__self_0_3)), + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for SignedSubmission + where + A: _parity_scale_codec::Encode, + A: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + dest.push(&self.who); + dest.push(&self.deposit); + dest.push(&self.reward); + dest.push(&self.solution); + } + } + impl _parity_scale_codec::EncodeLike for SignedSubmission + where + A: _parity_scale_codec::Encode, + A: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for SignedSubmission + where + A: _parity_scale_codec::Decode, + A: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + RawSolution: _parity_scale_codec::Decode, + RawSolution: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(SignedSubmission { + who: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.who".into()) + } + Ok(a) => a, + } + }, + deposit: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.deposit".into()) + } + Ok(a) => a, + } + }, + reward: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.reward".into()) + } + Ok(a) => a, + } + }, + solution: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.solution".into()) + } + Ok(a) => a, + } + }, + }) + } + } + }; + impl core::fmt::Debug for SignedSubmission + where + A: core::fmt::Debug, + B: core::fmt::Debug, + C: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("SignedSubmission") + .field("who", &self.who) + .field("deposit", &self.deposit) + .field("reward", &self.reward) + .field("solution", &self.solution) + .finish() + } + } + /// A checked and parsed solution, ready to be enacted. + pub struct ReadySolution { + /// The final supports of the solution. This is target-major vector, storing each winners, total + /// backing, and each individual backer. + supports: Supports, + /// The score of the solution. + /// + /// This is needed to potentially challenge the solution. + score: ElectionScore, + /// How this election was computed. + compute: ElectionCompute, + } + impl ::core::marker::StructuralPartialEq for ReadySolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for ReadySolution { + #[inline] + fn eq(&self, other: &ReadySolution) -> bool { + match *other { + ReadySolution { + supports: ref __self_1_0, + score: ref __self_1_1, + compute: ref __self_1_2, + } => match *self { + ReadySolution { + supports: ref __self_0_0, + score: ref __self_0_1, + compute: ref __self_0_2, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + } + }, + } + } + #[inline] + fn ne(&self, other: &ReadySolution) -> bool { + match *other { + ReadySolution { + supports: ref __self_1_0, + score: ref __self_1_1, + compute: ref __self_1_2, + } => match *self { + ReadySolution { + supports: ref __self_0_0, + score: ref __self_0_1, + compute: ref __self_0_2, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) + || (*__self_0_2) != (*__self_1_2) + } + }, + } + } + } + impl ::core::marker::StructuralEq for ReadySolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for ReadySolution { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for ReadySolution { + #[inline] + fn clone(&self) -> ReadySolution { + match *self { + ReadySolution { + supports: ref __self_0_0, + score: ref __self_0_1, + compute: ref __self_0_2, + } => ReadySolution { + supports: ::core::clone::Clone::clone(&(*__self_0_0)), + score: ::core::clone::Clone::clone(&(*__self_0_1)), + compute: ::core::clone::Clone::clone(&(*__self_0_2)), + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for ReadySolution + where + Supports: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + dest.push(&self.supports); + dest.push(&self.score); + dest.push(&self.compute); + } + } + impl _parity_scale_codec::EncodeLike for ReadySolution + where + Supports: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for ReadySolution + where + Supports: _parity_scale_codec::Decode, + Supports: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(ReadySolution { + supports: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field ReadySolution.supports".into()) + } + Ok(a) => a, + } + }, + score: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field ReadySolution.score".into()), + Ok(a) => a, + } + }, + compute: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field ReadySolution.compute".into()) + } + Ok(a) => a, + } + }, + }) + } + } + }; + impl core::fmt::Debug for ReadySolution + where + A: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("ReadySolution") + .field("supports", &self.supports) + .field("score", &self.score) + .field("compute", &self.compute) + .finish() + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for ReadySolution { + #[inline] + fn default() -> ReadySolution { + ReadySolution { + supports: ::core::default::Default::default(), + score: ::core::default::Default::default(), + compute: ::core::default::Default::default(), + } + } + } + /// The crate errors. Note that this is different from the [`PalletError`]. + pub enum Error { + /// A feasibility error. + Feasibility(FeasibilityError), + /// An error in the on-chain fallback. + OnChainFallback(crate::onchain::Error), + /// An internal error in the NPoS elections crate. + NposElections(sp_npos_elections::Error), + /// Snapshot data was unavailable unexpectedly. + SnapshotUnAvailable, + } + impl core::fmt::Debug for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::Feasibility(ref a0) => { + fmt.debug_tuple("Error::Feasibility").field(a0).finish() + } + Self::OnChainFallback(ref a0) => { + fmt.debug_tuple("Error::OnChainFallback").field(a0).finish() + } + Self::NposElections(ref a0) => { + fmt.debug_tuple("Error::NposElections").field(a0).finish() + } + Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), + _ => Ok(()), + } + } + } + impl ::core::marker::StructuralEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + impl ::core::marker::StructuralPartialEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + ( + &Error::OnChainFallback(ref __self_0), + &Error::OnChainFallback(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + ( + &Error::NposElections(ref __self_0), + &Error::NposElections(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + ( + &Error::OnChainFallback(ref __self_0), + &Error::OnChainFallback(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + ( + &Error::NposElections(ref __self_0), + &Error::NposElections(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => false, + } + } else { + true + } + } + } + } + impl From for Error { + fn from(e: crate::onchain::Error) -> Self { + Error::OnChainFallback(e) + } + } + impl From for Error { + fn from(e: sp_npos_elections::Error) -> Self { + Error::NposElections(e) + } + } + /// Errors that can happen in the feasibility check. + pub enum FeasibilityError { + /// Wrong number of winners presented. + WrongWinnerCount, + /// The snapshot is not available. + /// + /// This must be an internal error of the chain. + SnapshotUnavailable, + /// Internal error from the election crate. + NposElectionError(sp_npos_elections::Error), + /// A vote is invalid. + InvalidVote, + /// A voter is invalid. + InvalidVoter, + /// A winner is invalid. + InvalidWinner, + /// The given score was invalid. + InvalidScore, + } + impl core::fmt::Debug for FeasibilityError { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::WrongWinnerCount => fmt + .debug_tuple("FeasibilityError::WrongWinnerCount") + .finish(), + Self::SnapshotUnavailable => fmt + .debug_tuple("FeasibilityError::SnapshotUnavailable") + .finish(), + Self::NposElectionError(ref a0) => fmt + .debug_tuple("FeasibilityError::NposElectionError") + .field(a0) + .finish(), + Self::InvalidVote => fmt.debug_tuple("FeasibilityError::InvalidVote").finish(), + Self::InvalidVoter => fmt.debug_tuple("FeasibilityError::InvalidVoter").finish(), + Self::InvalidWinner => fmt.debug_tuple("FeasibilityError::InvalidWinner").finish(), + Self::InvalidScore => fmt.debug_tuple("FeasibilityError::InvalidScore").finish(), + _ => Ok(()), + } + } + } + impl ::core::marker::StructuralEq for FeasibilityError {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for FeasibilityError { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } + impl ::core::marker::StructuralPartialEq for FeasibilityError {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for FeasibilityError { + #[inline] + fn eq(&self, other: &FeasibilityError) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &FeasibilityError::NposElectionError(ref __self_0), + &FeasibilityError::NposElectionError(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &FeasibilityError) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &FeasibilityError::NposElectionError(ref __self_0), + &FeasibilityError::NposElectionError(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => false, + } + } else { + true + } + } + } + } + impl From for FeasibilityError { + fn from(e: sp_npos_elections::Error) -> Self { + FeasibilityError::NposElectionError(e) + } + } + /// The weights for this pallet. + pub trait WeightInfo { + fn feasibility_check() -> Weight; + fn submit() -> Weight; + fn submit_unsigned() -> Weight; + } + impl WeightInfo for () { + fn feasibility_check() -> Weight { + Default::default() + } + fn submit() -> Weight { + Default::default() + } + fn submit_unsigned() -> Weight { + Default::default() + } + } + pub trait Trait: frame_system::Trait { + /// Event type. + type Event: From> + Into<::Event>; + /// Currency type. + type Currency: ReservableCurrency + Currency; + /// Duration of the signed phase. + type SignedPhase: Get; + /// Duration of the unsigned phase. + type UnsignedPhase: Get; + /// Maximum number of singed submissions that can be queued. + type MaxSignedSubmissions: Get; + type SignedRewardBase: Get>; + type SignedRewardFactor: Get; + type SignedRewardMax: Get>>; + type SignedDepositBase: Get>; + type SignedDepositByte: Get>; + type SignedDepositWeight: Get>; + /// The minimum amount of improvement to the solution score that defines a solution as "better". + type SolutionImprovementThreshold: Get; + type UnsignedMaxIterations: Get; + type UnsignedCall: Dispatchable + Clone; + type UnsignedPriority: Get; + /// Handler for the slashed deposits. + type SlashHandler: OnUnbalanced>; + /// Handler for the rewards. + type RewardHandler: OnUnbalanced>; + /// Something that will provide the election data. + type ElectionDataProvider: ElectionDataProvider; + /// The weight of the pallet. + type WeightInfo: WeightInfo; + } + use self::sp_api_hidden_includes_decl_storage::hidden_include::{ + IterableStorageDoubleMap as _, IterableStorageMap as _, StorageDoubleMap as _, + StorageMap as _, StoragePrefixedMap as _, StorageValue as _, + }; + #[doc(hidden)] + mod sp_api_hidden_includes_decl_storage { + pub extern crate frame_support as hidden_include; + } + trait Store { + type CurrentPhase; + type SignedSubmissions; + type QueuedSolution; + type SnapshotTargets; + type SnapshotVoters; + type DesiredTargets; + } + impl Store for Module + where + ExtendedBalance: From>>, + { + type CurrentPhase = CurrentPhase; + type SignedSubmissions = SignedSubmissions; + type QueuedSolution = QueuedSolution; + type SnapshotTargets = SnapshotTargets; + type SnapshotVoters = SnapshotVoters; + type DesiredTargets = DesiredTargets; + } + impl Module + where + ExtendedBalance: From>>, + { + /// Current phase. + pub fn current_phase() -> Phase { + < CurrentPhase < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase < T :: BlockNumber > > > :: get ( ) + } + /// Sorted (worse -> best) list of unchecked, signed solutions. + pub fn signed_submissions( + ) -> Vec, CompactOf>> { + < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > > > :: get ( ) + } + /// Current best solution, signed or unsigned. + pub fn queued_solution() -> Option> { + < QueuedSolution < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < ReadySolution < T :: AccountId > > > :: get ( ) + } + /// Snapshot of all Voters. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub fn snapshot_targets() -> Option> { + < SnapshotTargets < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < T :: AccountId > > > :: get ( ) + } + /// Snapshot of all targets. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub fn snapshot_voters() -> Option)>> { + < SnapshotVoters < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < ( T :: AccountId , VoteWeight , Vec < T :: AccountId > ) > > > :: get ( ) + } + /// Desired number of targets to elect. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub fn desired_targets() -> u32 { + < DesiredTargets < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) + } + } + #[doc(hidden)] + pub struct __GetByteStructCurrentPhase( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_CurrentPhase: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructCurrentPhase + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec + { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_CurrentPhase + .get_or_init(|| { + let def_val: Phase = Phase::Off; + as Encode>::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructCurrentPhase where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructCurrentPhase where + ExtendedBalance: From>> + { + } + #[doc(hidden)] + pub struct __GetByteStructSignedSubmissions( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_SignedSubmissions: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructSignedSubmissions + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec + { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_SignedSubmissions . get_or_init ( | | { let def_val : Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > = Default :: default ( ) ; < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > as Encode > :: encode ( & def_val ) } ) . clone ( ) + } + } + unsafe impl Send for __GetByteStructSignedSubmissions where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructSignedSubmissions where + ExtendedBalance: From>> + { + } + #[doc(hidden)] + pub struct __GetByteStructQueuedSolution( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_QueuedSolution: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructQueuedSolution + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec + { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_QueuedSolution + .get_or_init(|| { + let def_val: Option> = Default::default(); + > as Encode>::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructQueuedSolution where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructQueuedSolution where + ExtendedBalance: From>> + { + } + #[doc(hidden)] + pub struct __GetByteStructSnapshotTargets( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_SnapshotTargets: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructSnapshotTargets + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec + { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_SnapshotTargets + .get_or_init(|| { + let def_val: Option> = Default::default(); + > as Encode>::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructSnapshotTargets where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructSnapshotTargets where + ExtendedBalance: From>> + { + } + #[doc(hidden)] + pub struct __GetByteStructSnapshotVoters( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_SnapshotVoters: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructSnapshotVoters + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec + { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_SnapshotVoters + .get_or_init(|| { + let def_val: Option)>> = + Default::default(); + )>> as Encode>::encode( + &def_val, + ) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructSnapshotVoters where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructSnapshotVoters where + ExtendedBalance: From>> + { + } + #[doc(hidden)] + pub struct __GetByteStructDesiredTargets( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_DesiredTargets: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructDesiredTargets + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec + { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_DesiredTargets + .get_or_init(|| { + let def_val: u32 = Default::default(); + ::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructDesiredTargets where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructDesiredTargets where + ExtendedBalance: From>> + { + } + impl Module + where + ExtendedBalance: From>>, + { + #[doc(hidden)] + pub fn storage_metadata( + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::StorageMetadata + { + self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec, CompactOf>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted (worse -> best) list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current best solution, signed or unsigned." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } ] [ .. ] ) , } + } + } + /// Hidden instance generated to be internally used when module is used without + /// instance. + #[doc(hidden)] + pub struct __InherentHiddenInstance; + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for __InherentHiddenInstance { + #[inline] + fn clone(&self) -> __InherentHiddenInstance { + match *self { + __InherentHiddenInstance => __InherentHiddenInstance, + } + } + } + impl ::core::marker::StructuralEq for __InherentHiddenInstance {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for __InherentHiddenInstance { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + {} + } + } + impl ::core::marker::StructuralPartialEq for __InherentHiddenInstance {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for __InherentHiddenInstance { + #[inline] + fn eq(&self, other: &__InherentHiddenInstance) -> bool { + match *other { + __InherentHiddenInstance => match *self { + __InherentHiddenInstance => true, + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for __InherentHiddenInstance { + fn encode_to(&self, dest: &mut EncOut) {} + } + impl _parity_scale_codec::EncodeLike for __InherentHiddenInstance {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for __InherentHiddenInstance { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(__InherentHiddenInstance) + } + } + }; + impl core::fmt::Debug for __InherentHiddenInstance { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_tuple("__InherentHiddenInstance").finish() + } + } + impl self::sp_api_hidden_includes_decl_storage::hidden_include::traits::Instance + for __InherentHiddenInstance + { + const PREFIX: &'static str = "TwoPhaseElectionProvider"; + } + /// Current phase. + pub struct CurrentPhase( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ) + where + ExtendedBalance: From>>; + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Phase, + > for CurrentPhase + where + ExtendedBalance: From>>, + { + type Query = Phase; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"CurrentPhase" + } + fn from_optional_value_to_query(v: Option>) -> Self::Query { + v.unwrap_or_else(|| Phase::Off) + } + fn from_query_to_optional_value(v: Self::Query) -> Option> { + Some(v) + } + } + /// Sorted (worse -> best) list of unchecked, signed solutions. + pub struct SignedSubmissions( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ) + where + ExtendedBalance: From>>; + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Vec, CompactOf>>, + > for SignedSubmissions + where + ExtendedBalance: From>>, + { + type Query = Vec, CompactOf>>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"SignedSubmissions" + } + fn from_optional_value_to_query( + v: Option, CompactOf>>>, + ) -> Self::Query { + v.unwrap_or_else(|| Default::default()) + } + fn from_query_to_optional_value( + v: Self::Query, + ) -> Option, CompactOf>>> { + Some(v) + } + } + /// Current best solution, signed or unsigned. + pub struct QueuedSolution( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ) + where + ExtendedBalance: From>>; + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + ReadySolution, + > for QueuedSolution + where + ExtendedBalance: From>>, + { + type Query = Option>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"QueuedSolution" + } + fn from_optional_value_to_query(v: Option>) -> Self::Query { + v.or_else(|| Default::default()) + } + fn from_query_to_optional_value(v: Self::Query) -> Option> { + v + } + } + /// Snapshot of all Voters. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub struct SnapshotTargets( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ) + where + ExtendedBalance: From>>; + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Vec, + > for SnapshotTargets + where + ExtendedBalance: From>>, + { + type Query = Option>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"SnapshotTargets" + } + fn from_optional_value_to_query(v: Option>) -> Self::Query { + v.or_else(|| Default::default()) + } + fn from_query_to_optional_value(v: Self::Query) -> Option> { + v + } + } + /// Snapshot of all targets. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub struct SnapshotVoters( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ) + where + ExtendedBalance: From>>; + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Vec<(T::AccountId, VoteWeight, Vec)>, + > for SnapshotVoters + where + ExtendedBalance: From>>, + { + type Query = Option)>>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"SnapshotVoters" + } + fn from_optional_value_to_query( + v: Option)>>, + ) -> Self::Query { + v.or_else(|| Default::default()) + } + fn from_query_to_optional_value( + v: Self::Query, + ) -> Option)>> { + v + } + } + /// Desired number of targets to elect. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub struct DesiredTargets( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + u32, + > for DesiredTargets + { + type Query = u32; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"DesiredTargets" + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + v.unwrap_or_else(|| Default::default()) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + Some(v) + } + } + /// [`RawEvent`] specialized for the configuration [`Trait`] + /// + /// [`RawEvent`]: enum.RawEvent.html + /// [`Trait`]: trait.Trait.html + pub type Event = RawEvent<::AccountId>; + /// Events for this module. + /// + pub enum RawEvent { + /// A solution was stored with the given compute. + /// + /// If the solution is signed, this means that it hasn't yet been processed. If the solution + /// is unsigned, this means that it has also been processed. + SolutionStored(ElectionCompute), + /// The election has been finalized, with `Some` of the given computation, or else if the + /// election failed, `None`. + ElectionFinalized(Option), + /// An account has been rewarded for their signed submission being finalized. + Rewarded(AccountId), + /// An account has been slashed for submitting an invalid signed submission. + Slashed(AccountId), + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for RawEvent { + #[inline] + fn clone(&self) -> RawEvent { + match (&*self,) { + (&RawEvent::SolutionStored(ref __self_0),) => { + RawEvent::SolutionStored(::core::clone::Clone::clone(&(*__self_0))) + } + (&RawEvent::ElectionFinalized(ref __self_0),) => { + RawEvent::ElectionFinalized(::core::clone::Clone::clone(&(*__self_0))) + } + (&RawEvent::Rewarded(ref __self_0),) => { + RawEvent::Rewarded(::core::clone::Clone::clone(&(*__self_0))) + } + (&RawEvent::Slashed(ref __self_0),) => { + RawEvent::Slashed(::core::clone::Clone::clone(&(*__self_0))) + } + } + } + } + impl ::core::marker::StructuralPartialEq for RawEvent {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for RawEvent { + #[inline] + fn eq(&self, other: &RawEvent) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &RawEvent::SolutionStored(ref __self_0), + &RawEvent::SolutionStored(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + ( + &RawEvent::ElectionFinalized(ref __self_0), + &RawEvent::ElectionFinalized(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + _ => unsafe { ::core::intrinsics::unreachable() }, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &RawEvent) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &RawEvent::SolutionStored(ref __self_0), + &RawEvent::SolutionStored(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + ( + &RawEvent::ElectionFinalized(ref __self_0), + &RawEvent::ElectionFinalized(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + _ => unsafe { ::core::intrinsics::unreachable() }, + } + } else { + true + } + } + } + } + impl ::core::marker::StructuralEq for RawEvent {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for RawEvent { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for RawEvent + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + RawEvent::SolutionStored(ref aa) => { + dest.push_byte(0usize as u8); + dest.push(aa); + } + RawEvent::ElectionFinalized(ref aa) => { + dest.push_byte(1usize as u8); + dest.push(aa); + } + RawEvent::Rewarded(ref aa) => { + dest.push_byte(2usize as u8); + dest.push(aa); + } + RawEvent::Slashed(ref aa) => { + dest.push_byte(3usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for RawEvent + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for RawEvent + where + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(RawEvent::SolutionStored({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err( + "Error decoding field RawEvent :: SolutionStored.0".into() + ) + } + Ok(a) => a, + } + })), + x if x == 1usize as u8 => Ok(RawEvent::ElectionFinalized({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err( + "Error decoding field RawEvent :: ElectionFinalized.0".into() + ) + } + Ok(a) => a, + } + })), + x if x == 2usize as u8 => Ok(RawEvent::Rewarded({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field RawEvent :: Rewarded.0".into()) + } + Ok(a) => a, + } + })), + x if x == 3usize as u8 => Ok(RawEvent::Slashed({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field RawEvent :: Slashed.0".into()) + } + Ok(a) => a, + } + })), + x => Err("No such variant in enum RawEvent".into()), + } + } + } + }; + impl core::fmt::Debug for RawEvent + where + AccountId: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::SolutionStored(ref a0) => fmt + .debug_tuple("RawEvent::SolutionStored") + .field(a0) + .finish(), + Self::ElectionFinalized(ref a0) => fmt + .debug_tuple("RawEvent::ElectionFinalized") + .field(a0) + .finish(), + Self::Rewarded(ref a0) => fmt.debug_tuple("RawEvent::Rewarded").field(a0).finish(), + Self::Slashed(ref a0) => fmt.debug_tuple("RawEvent::Slashed").field(a0).finish(), + _ => Ok(()), + } + } + } + impl From> for () { + fn from(_: RawEvent) -> () { + () + } + } + impl RawEvent { + #[allow(dead_code)] + #[doc(hidden)] + pub fn metadata() -> &'static [::frame_support::event::EventMetadata] { + &[ + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("SolutionStored"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&[ + "ElectionCompute", + ]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" A solution was stored with the given compute.", + r"", + r" If the solution is signed, this means that it hasn't yet been processed. If the solution", + r" is unsigned, this means that it has also been processed.", + ]), + }, + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("ElectionFinalized"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&[ + "Option", + ]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" The election has been finalized, with `Some` of the given computation, or else if the", + r" election failed, `None`.", + ]), + }, + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("Rewarded"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" An account has been rewarded for their signed submission being finalized.", + ]), + }, + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("Slashed"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" An account has been slashed for submitting an invalid signed submission.", + ]), + }, + ] + } + } + pub enum PalletError + where + ExtendedBalance: From>>, + { + #[doc(hidden)] + __Ignore( + ::frame_support::sp_std::marker::PhantomData<(T,)>, + ::frame_support::Never, + ), + /// Submission was too early. + EarlySubmission, + /// The queue was full, and the solution was not better than any of the existing ones. + QueueFull, + /// The origin failed to pay the deposit. + CannotPayDeposit, + } + impl ::frame_support::sp_std::fmt::Debug for PalletError + where + ExtendedBalance: From>>, + { + fn fmt( + &self, + f: &mut ::frame_support::sp_std::fmt::Formatter<'_>, + ) -> ::frame_support::sp_std::fmt::Result { + f.write_str(self.as_str()) + } + } + impl PalletError + where + ExtendedBalance: From>>, + { + fn as_u8(&self) -> u8 { + match self { + PalletError::__Ignore(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"`__Ignore` can never be constructed",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + PalletError::EarlySubmission => 0, + PalletError::QueueFull => 0 + 1, + PalletError::CannotPayDeposit => 0 + 1 + 1, + } + } + fn as_str(&self) -> &'static str { + match self { + Self::__Ignore(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"`__Ignore` can never be constructed",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + PalletError::EarlySubmission => "EarlySubmission", + PalletError::QueueFull => "QueueFull", + PalletError::CannotPayDeposit => "CannotPayDeposit", + } + } + } + impl From> for &'static str + where + ExtendedBalance: From>>, + { + fn from(err: PalletError) -> &'static str { + err.as_str() + } + } + impl From> for ::frame_support::sp_runtime::DispatchError + where + ExtendedBalance: From>>, + { + fn from(err: PalletError) -> Self { + let index = ::index::>() + .expect("Every active module has an index in the runtime; qed") + as u8; + ::frame_support::sp_runtime::DispatchError::Module { + index, + error: err.as_u8(), + message: Some(err.as_str()), + } + } + } + impl ::frame_support::error::ModuleErrorMetadata for PalletError + where + ExtendedBalance: From>>, + { + fn metadata() -> &'static [::frame_support::error::ErrorMetadata] { + &[ + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("EarlySubmission"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[ + r" Submission was too early.", + ]), + }, + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("QueueFull"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[ + r" The queue was full, and the solution was not better than any of the existing ones.", + ]), + }, + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("CannotPayDeposit"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[ + r" The origin failed to pay the deposit.", + ]), + }, + ] + } + } + pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>) + where + ExtendedBalance: From>>; + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Module + where + ExtendedBalance: From>>, + { + #[inline] + fn clone(&self) -> Module { + match *self { + Module(ref __self_0_0) => Module(::core::clone::Clone::clone(&(*__self_0_0))), + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for Module where + ExtendedBalance: From>> + { + } + impl ::core::marker::StructuralPartialEq for Module where + ExtendedBalance: From>> + { + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Module + where + ExtendedBalance: From>>, + { + #[inline] + fn eq(&self, other: &Module) -> bool { + match *other { + Module(ref __self_1_0) => match *self { + Module(ref __self_0_0) => (*__self_0_0) == (*__self_1_0), + }, + } + } + #[inline] + fn ne(&self, other: &Module) -> bool { + match *other { + Module(ref __self_1_0) => match *self { + Module(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), + }, + } + } + } + impl ::core::marker::StructuralEq for Module where + ExtendedBalance: From>> + { + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Module + where + ExtendedBalance: From>>, + { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq< + ::frame_support::sp_std::marker::PhantomData<(T,)>, + >; + } + } + } + impl core::fmt::Debug for Module + where + ExtendedBalance: From>>, + T: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_tuple("Module").field(&self.0).finish() + } + } + impl + ::frame_support::traits::OnInitialize<::BlockNumber> for Module + where + ExtendedBalance: From>>, + { + fn on_initialize(now: T::BlockNumber) -> Weight { + let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "on_initialize", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(429u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + MacroCallsite::new(&META) + }; + let mut interest = ::tracing::subscriber::Interest::never(); + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + && { + interest = CALLSITE.interest(); + !interest.is_never() + } + && CALLSITE.is_enabled(interest) + { + let meta = CALLSITE.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + let span = CALLSITE.disabled_span(); + {}; + span + } + }; + let __tracing_guard__ = __within_span__.enter(); + { + let next_election = T::ElectionDataProvider::next_election_prediction(now); + let next_election = next_election.max(now); + let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); + let unsigned_deadline = T::UnsignedPhase::get(); + let remaining = next_election - now; + match Self::current_phase() { + Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { + >::put(Phase::Signed); + Self::start_signed_phase(); + { + let lvl = ::log::Level::Info; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( + ::core::fmt::Arguments::new_v1( + &["Starting signed phase at #"], + &match (&now,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + ), + lvl, + &( + crate::LOG_TARGET, + "frame_election_providers::two_phase", + "frame/election-providers/src/two_phase/mod.rs", + 452u32, + ), + ); + } + }; + } + Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { + let found_solution = Self::finalize_signed_phase(); + >::put(Phase::Unsigned((!found_solution, now))); + { + let lvl = ::log::Level::Info; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( + ::core::fmt::Arguments::new_v1( + &["Starting unsigned phase at #"], + &match (&now,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + ), + lvl, + &( + crate::LOG_TARGET, + "frame_election_providers::two_phase", + "frame/election-providers/src/two_phase/mod.rs", + 458u32, + ), + ); + } + }; + } + _ => {} + } + Default::default() + } + } + } + impl ::frame_support::traits::OnRuntimeUpgrade for Module where + ExtendedBalance: From>> + { + } + impl + ::frame_support::traits::OnFinalize<::BlockNumber> for Module + where + ExtendedBalance: From>>, + { + } + impl + ::frame_support::traits::OffchainWorker<::BlockNumber> + for Module + where + ExtendedBalance: From>>, + { + fn offchain_worker(n: T::BlockNumber) { + if Self::set_check_offchain_execution_status(n).is_ok() + && Self::current_phase().is_unsigned_open_at(n) + { + let _ = Self::mine_and_submit().map_err(|e| { + let lvl = ::log::Level::Error; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( + ::core::fmt::Arguments::new_v1( + &["error while submitting transaction in OCW: "], + &match (&e,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + ), + lvl, + &( + crate::LOG_TARGET, + "frame_election_providers::two_phase", + "frame/election-providers/src/two_phase/mod.rs", + 475u32, + ), + ); + } + }); + } + } + } + impl Module + where + ExtendedBalance: From>>, + { + /// Deposits an event using `frame_system::Module::deposit_event`. + fn deposit_event(event: impl Into<::Event>) { + >::deposit_event(event.into()) + } + } + #[cfg(feature = "std")] + impl ::frame_support::traits::IntegrityTest for Module where + ExtendedBalance: From>> + { + } + /// Can also be called using [`Call`]. + /// + /// [`Call`]: enum.Call.html + impl Module + where + ExtendedBalance: From>>, + { + /// Submit a solution for the signed phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// The solution potentially queued, based on the claimed score and processed at the end of + /// the signed phase. + /// + /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution + /// might be rewarded, slashed, or get all or a part of the deposit back. + /// + /// NOTE: Calling this function will bypass origin filters. + fn submit( + origin: T::Origin, + solution: RawSolution>, + ) -> DispatchResultWithPostInfo { + let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "submit", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(429u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + MacroCallsite::new(&META) + }; + let mut interest = ::tracing::subscriber::Interest::never(); + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + && { + interest = CALLSITE.interest(); + !interest.is_never() + } + && CALLSITE.is_enabled(interest) + { + let meta = CALLSITE.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + let span = CALLSITE.disabled_span(); + {}; + span + } + }; + let __tracing_guard__ = __within_span__.enter(); + let who = ensure_signed(origin)?; + { + if !Self::current_phase().is_signed() { + { + return Err(PalletError::::EarlySubmission.into()); + }; + } + }; + let mut signed_submissions = Self::signed_submissions(); + let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution); + { + if !maybe_index.is_some() { + { + return Err("QueueFull".into()); + }; + } + }; + let index = maybe_index.expect("Option checked to be `Some`; qed."); + let deposit = signed_submissions[index].deposit; + T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; + if true { + if !(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()) { + { + :: std :: rt :: begin_panic ( "assertion failed: signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()" ) + } + }; + }; + >::put(signed_submissions); + Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Signed)); + Ok(None.into()) + } + #[allow(unreachable_code)] + /// Submit a solution for the unsigned phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. + /// Moreover, this unsigned solution is only validated when submitted to the pool from the + /// local process. Effectively, this means that only active validators can submit this + /// transaction when authoring a block. + /// + /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will + /// panic if the solution submitted by the validator is invalid, effectively putting their + /// authoring reward at risk. + /// + /// No deposit or reward is associated with this. + /// + /// NOTE: Calling this function will bypass origin filters. + fn submit_unsigned( + origin: T::Origin, + solution: RawSolution>, + ) -> ::frame_support::dispatch::DispatchResult { + let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "submit_unsigned", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(429u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + MacroCallsite::new(&META) + }; + let mut interest = ::tracing::subscriber::Interest::never(); + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + && { + interest = CALLSITE.interest(); + !interest.is_never() + } + && CALLSITE.is_enabled(interest) + { + let meta = CALLSITE.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + let span = CALLSITE.disabled_span(); + {}; + span + } + }; + let __tracing_guard__ = __within_span__.enter(); + { + ensure_none(origin)?; + let _ = Self::pre_dispatch_checks(&solution)?; + let ready = Self::feasibility_check(solution, ElectionCompute::Unsigned).expect( + "Invalid unsigned submission must produce invalid block and deprive \ + validator from their authoring reward.", + ); + >::put(ready); + Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); + } + Ok(()) + } + } + /// Dispatchable calls. + /// + /// Each variant of this enum maps to a dispatchable function from the associated module. + pub enum Call + where + ExtendedBalance: From>>, + { + #[doc(hidden)] + #[codec(skip)] + __PhantomItem( + ::frame_support::sp_std::marker::PhantomData<(T,)>, + ::frame_support::Never, + ), + #[allow(non_camel_case_types)] + /// Submit a solution for the signed phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// The solution potentially queued, based on the claimed score and processed at the end of + /// the signed phase. + /// + /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution + /// might be rewarded, slashed, or get all or a part of the deposit back. + submit(RawSolution>), + #[allow(non_camel_case_types)] + /// Submit a solution for the unsigned phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. + /// Moreover, this unsigned solution is only validated when submitted to the pool from the + /// local process. Effectively, this means that only active validators can submit this + /// transaction when authoring a block. + /// + /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will + /// panic if the solution submitted by the validator is invalid, effectively putting their + /// authoring reward at risk. + /// + /// No deposit or reward is associated with this. + submit_unsigned(RawSolution>), + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + Call::submit(ref aa) => { + dest.push_byte(0usize as u8); + dest.push(aa); + } + Call::submit_unsigned(ref aa) => { + dest.push_byte(1usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(Call::submit({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field Call :: submit.0".into()), + Ok(a) => a, + } + })), + x if x == 1usize as u8 => Ok(Call::submit_unsigned({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field Call :: submit_unsigned.0".into()) + } + Ok(a) => a, + } + })), + x => Err("No such variant in enum Call".into()), + } + } + } + }; + impl ::frame_support::dispatch::GetDispatchInfo for Call + where + ExtendedBalance: From>>, + { + fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { + match *self { + Call::submit(ref solution) => { + let base_weight = T::WeightInfo::submit(); + let weight = >, + )>>::weigh_data(&base_weight, (solution,)); + let class = + >, + )>>::classify_dispatch(&base_weight, (solution,)); + let pays_fee = >, + )>>::pays_fee(&base_weight, (solution,)); + ::frame_support::dispatch::DispatchInfo { + weight, + class, + pays_fee, + } + } + Call::submit_unsigned(ref solution) => { + let base_weight = T::WeightInfo::submit_unsigned(); + let weight = >, + )>>::weigh_data(&base_weight, (solution,)); + let class = + >, + )>>::classify_dispatch(&base_weight, (solution,)); + let pays_fee = >, + )>>::pays_fee(&base_weight, (solution,)); + ::frame_support::dispatch::DispatchInfo { + weight, + class, + pays_fee, + } + } + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__PhantomItem should never be used.",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + } + } + impl ::frame_support::dispatch::GetCallName for Call + where + ExtendedBalance: From>>, + { + fn get_call_name(&self) -> &'static str { + match *self { + Call::submit(ref solution) => { + let _ = (solution); + "submit" + } + Call::submit_unsigned(ref solution) => { + let _ = (solution); + "submit_unsigned" + } + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__PhantomItem should never be used.",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + } + fn get_call_names() -> &'static [&'static str] { + &["submit", "submit_unsigned"] + } + } + impl ::frame_support::dispatch::Clone for Call + where + ExtendedBalance: From>>, + { + fn clone(&self) -> Self { + match *self { + Call::submit(ref solution) => Call::submit((*solution).clone()), + Call::submit_unsigned(ref solution) => Call::submit_unsigned((*solution).clone()), + _ => ::std::rt::begin_panic("internal error: entered unreachable code"), + } + } + } + impl ::frame_support::dispatch::PartialEq for Call + where + ExtendedBalance: From>>, + { + fn eq(&self, _other: &Self) -> bool { + match *self { + Call::submit(ref solution) => { + let self_params = (solution,); + if let Call::submit(ref solution) = *_other { + self_params == (solution,) + } else { + match *_other { + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic("internal error: entered unreachable code") + } + _ => false, + } + } + } + Call::submit_unsigned(ref solution) => { + let self_params = (solution,); + if let Call::submit_unsigned(ref solution) = *_other { + self_params == (solution,) + } else { + match *_other { + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic("internal error: entered unreachable code") + } + _ => false, + } + } + } + _ => ::std::rt::begin_panic("internal error: entered unreachable code"), + } + } + } + impl ::frame_support::dispatch::Eq for Call where + ExtendedBalance: From>> + { + } + impl ::frame_support::dispatch::fmt::Debug for Call + where + ExtendedBalance: From>>, + { + fn fmt( + &self, + _f: &mut ::frame_support::dispatch::fmt::Formatter, + ) -> ::frame_support::dispatch::result::Result<(), ::frame_support::dispatch::fmt::Error> + { + match *self { + Call::submit(ref solution) => _f.write_fmt(::core::fmt::Arguments::new_v1( + &["", ""], + &match (&"submit", &(solution.clone(),)) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), + ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), + ], + }, + )), + Call::submit_unsigned(ref solution) => { + _f.write_fmt(::core::fmt::Arguments::new_v1( + &["", ""], + &match (&"submit_unsigned", &(solution.clone(),)) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), + ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), + ], + }, + )) + } + _ => ::std::rt::begin_panic("internal error: entered unreachable code"), + } + } + } + impl ::frame_support::traits::UnfilteredDispatchable for Call + where + ExtendedBalance: From>>, + { + type Origin = T::Origin; + fn dispatch_bypass_filter( + self, + _origin: Self::Origin, + ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { + match self { + Call::submit(solution) => >::submit(_origin, solution) + .map(Into::into) + .map_err(Into::into), + Call::submit_unsigned(solution) => >::submit_unsigned(_origin, solution) + .map(Into::into) + .map_err(Into::into), + Call::__PhantomItem(_, _) => { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["internal error: entered unreachable code: "], + &match (&"__PhantomItem should never be used.",) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + )) + } + } + } + } + impl ::frame_support::dispatch::Callable for Module + where + ExtendedBalance: From>>, + { + type Call = Call; + } + impl Module + where + ExtendedBalance: From>>, + { + #[doc(hidden)] + #[allow(dead_code)] + pub fn call_functions() -> &'static [::frame_support::dispatch::FunctionMetadata] { + &[ + ::frame_support::dispatch::FunctionMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("submit"), + arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + ::frame_support::dispatch::FunctionArgumentMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), + ty: ::frame_support::dispatch::DecodeDifferent::Encode( + "RawSolution>", + ), + }, + ]), + documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + r" Submit a solution for the signed phase.", + r"", + r" The dispatch origin fo this call must be __signed__.", + r"", + r" The solution potentially queued, based on the claimed score and processed at the end of", + r" the signed phase.", + r"", + r" A deposit is reserved and recorded for the solution. Based on the outcome, the solution", + r" might be rewarded, slashed, or get all or a part of the deposit back.", + ]), + }, + ::frame_support::dispatch::FunctionMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("submit_unsigned"), + arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + ::frame_support::dispatch::FunctionArgumentMetadata { + name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), + ty: ::frame_support::dispatch::DecodeDifferent::Encode( + "RawSolution>", + ), + }, + ]), + documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + r" Submit a solution for the unsigned phase.", + r"", + r" The dispatch origin fo this call must be __signed__.", + r"", + r" This submission is checked on the fly, thus it is likely yo be more limited and smaller.", + r" Moreover, this unsigned solution is only validated when submitted to the pool from the", + r" local process. Effectively, this means that only active validators can submit this", + r" transaction when authoring a block.", + r"", + r" To prevent any incorrect solution (and thus wasted time/weight), this transaction will", + r" panic if the solution submitted by the validator is invalid, effectively putting their", + r" authoring reward at risk.", + r"", + r" No deposit or reward is associated with this.", + ]), + }, + ] + } + } + impl Module + where + ExtendedBalance: From>>, + { + #[doc(hidden)] + #[allow(dead_code)] + pub fn module_constants_metadata( + ) -> &'static [::frame_support::dispatch::ModuleConstantMetadata] { + &[] + } + } + impl ::frame_support::dispatch::ModuleErrorMetadata for Module + where + ExtendedBalance: From>>, + { + fn metadata() -> &'static [::frame_support::dispatch::ErrorMetadata] { + as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() + } + } + impl Module + where + ExtendedBalance: From>>, + { + /// Checks the feasibility of a solution. + /// + /// This checks the solution for the following: + /// + /// 0. **all** of the used indices must be correct. + /// 1. present correct number of winners. + /// 2. any assignment is checked to match with `SnapshotVoters`. + /// 3. for each assignment, the check of `ElectionDataProvider` is also examined. + /// 4. the claimed score is valid. + fn feasibility_check( + solution: RawSolution>, + compute: ElectionCompute, + ) -> Result, FeasibilityError> { + let RawSolution { compact, score } = solution; + let winners = compact.unique_targets(); + { + if !(winners.len() as u32 == Self::desired_targets()) { + { + return Err(FeasibilityError::WrongWinnerCount.into()); + }; + } + }; + let snapshot_voters = + Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; + let snapshot_targets = + Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; + let voter_at = |i: crate::two_phase::CompactVoterIndexOf| -> Option { + as crate::TryInto>::try_into(i) + .ok() + .and_then(|i| snapshot_voters.get(i).map(|(x, _, _)| x).cloned()) + }; + let target_at = |i: crate::two_phase::CompactTargetIndexOf| -> Option { + as crate::TryInto>::try_into(i) + .ok() + .and_then(|i| snapshot_targets.get(i).cloned()) + }; + let winners = winners + .into_iter() + .map(|i| target_at(i).ok_or(FeasibilityError::InvalidWinner)) + .collect::, FeasibilityError>>()?; + let assignments = compact + .into_assignment(voter_at, target_at) + .map_err::(Into::into)?; + let _ = assignments + .iter() + .map(|Assignment { who, distribution }| { + snapshot_voters.iter().find(|(v, _, _)| v == who).map_or( + Err(FeasibilityError::InvalidVoter), + |(_, _, t)| { + if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) + && T::ElectionDataProvider::feasibility_check_assignment::< + CompactAccuracyOf, + >(who, distribution) + { + Ok(()) + } else { + Err(FeasibilityError::InvalidVote) + } + }, + ) + }) + .collect::>()?; + let stake_of = |who: &T::AccountId| -> crate::VoteWeight { + snapshot_voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + }; + let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) + .map_err::(Into::into)?; + let supports = sp_npos_elections::to_supports(&winners, &staked_assignments) + .map_err::(Into::into)?; + let known_score = supports.evaluate(); + { + if !(known_score == score) { + { + return Err(FeasibilityError::InvalidScore.into()); + }; + } + }; + Ok(ReadySolution { + supports, + compute, + score, + }) + } + /// On-chain fallback of election. + fn onchain_fallback() -> Result, Error> { + let desired_targets = Self::desired_targets() as usize; + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + >::elect::( + desired_targets, + targets, + voters, + ) + .map_err(Into::into) + } + } + impl ElectionProvider for Module + where + ExtendedBalance: From>>, + { + const NEEDS_ELECT_DATA: bool = false; + type Error = Error; + fn elect( + _to_elect: usize, + _targets: Vec, + _voters: Vec<(T::AccountId, VoteWeight, Vec)>, + ) -> Result, Self::Error> + where + ExtendedBalance: From<

::Inner>, + { + Self::queued_solution() + .map_or_else( + || { + Self::onchain_fallback() + .map(|r| (r, ElectionCompute::OnChain)) + .map_err(Into::into) + }, + |ReadySolution { + supports, compute, .. + }| Ok((supports, compute)), + ) + .map(|(supports, compute)| { + >::put(Phase::Off); + >::kill(); + >::kill(); + Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); + { + let lvl = ::log::Level::Info; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( + ::core::fmt::Arguments::new_v1( + &["Finalized election round with compute ", "."], + &match (&compute,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + ), + lvl, + &( + crate::LOG_TARGET, + "frame_election_providers::two_phase", + "frame/election-providers/src/two_phase/mod.rs", + 689u32, + ), + ); + } + }; + supports + }) + .map_err(|err| { + Self::deposit_event(RawEvent::ElectionFinalized(None)); + { + let lvl = ::log::Level::Error; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( + ::core::fmt::Arguments::new_v1( + &["Failed to finalize election round. Error = "], + &match (&err,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + ), + lvl, + &( + crate::LOG_TARGET, + "frame_election_providers::two_phase", + "frame/election-providers/src/two_phase/mod.rs", + 694u32, + ), + ); + } + }; + err + }) + } + fn ongoing() -> bool { + match Self::current_phase() { + Phase::Signed | Phase::Unsigned(_) => true, + _ => false, + } + } + } } -use sp_arithmetic::PerThing; +const LOG_TARGET: &'static str = "election-provider"; #[doc(hidden)] pub use sp_npos_elections::VoteWeight; -use sp_npos_elections::{CompactSolution, ExtendedBalance, PerThing128, Support, SupportMap}; +#[doc(hidden)] +use sp_runtime::traits::UniqueSaturatedInto; #[doc(hidden)] pub use sp_std::convert::TryInto; -/// A flat variant of [`sp_npos_elections::SupportMap`]. -/// -/// The main advantage of this is that it is encodable. -pub type Supports = Vec<(A, Support)>; -/// Helper trait to convert from a support map to a flat support vector. -pub trait FlattenSupportMap { - fn flatten(self) -> Supports; -} -impl FlattenSupportMap for SupportMap { - fn flatten(self) -> Supports { - self.into_iter().map(|(k, v)| (k, v)).collect::>() - } -} -/// Something that can provide the data to something else that implements [`ElectionProvider`], such -/// as the [`two_phase`] module. -/// -/// The underlying purpose of this is to provide auxillary data to long-lasting election providers. -/// For example, the [`two_phase`] election provider needs to know the voters/targets list well in -/// advance and before a call to [`ElectionProvider::elect`]. -/// -/// For example, if pallet A wants to use the two-phase election: -/// -/// ```rust,ignore -/// pub trait TraitA { -/// type ElectionProvider: ElectionProvider<_, _>; -/// } -/// -/// // these function will be called by `Self::ElectionProvider` whenever needed. -/// impl ElectionDataProvider for PalletA { /* .. */ } -/// -/// impl Module { -/// fn do_election() { -/// // finalize the election. -/// T::ElectionProvider::elect( /* .. */ ); -/// } -/// } -/// ``` -pub trait ElectionDataProvider { - /// The compact solution type. - /// - /// This should encode the entire solution with the least possible space usage. - type CompactSolution: codec::Codec + Default + PartialEq + Eq + Clone + Debug + CompactSolution; - /// All possible targets for the election, i.e. the candidates. - fn targets() -> Vec; - /// All possible voters for the election. - /// - /// Note that if a notion of self-vote exists, it should be represented here. - fn voters() -> Vec<(AccountId, VoteWeight, Vec)>; - /// The number of targets to elect. - fn desired_targets() -> u32; - /// Check the feasibility of a single assignment for the underlying `ElectionProvider`. In other - /// words, check if `who` having a weight distribution described as `distribution` is correct or - /// not. - /// - /// This might be called by the [`ElectionProvider`] upon processing solutions. - fn feasibility_check_assignment( - who: &AccountId, - distribution: &[(AccountId, P)], - ) -> bool; - /// Provide a best effort prediction about when the next election is about to happen. - /// - /// In essence, `Self` should predict with this function when it will trigger the - /// `ElectionDataProvider::elect`. - fn next_election_prediction(now: B) -> B; -} -/// Something that can compute the result of an election and pass it back to the caller. -pub trait ElectionProvider { - /// Indicate weather this election provider needs data when calling [`elect`] or not. - const NEEDS_ELECT_DATA: bool; - /// The error type that is returned by the provider. - type Error; - /// Elect a new set of winners. - /// - /// The result is returned in a target major format, namely as a support map. - /// - /// Note that based on the logic of the type that will implement this trait, the input data may - /// or may not be used. To hint about this to the call site, [`NEEDS_ELECT_DATA`] should be - /// properly set. - /// - /// The implementation should, if possible, use the accuracy `P` to compute the election result. - fn elect( - to_elect: usize, - targets: Vec, - voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>; - /// Returns true if an election is still ongoing. This can be used by the call site to - /// dynamically check of a long-lasting election (such as [`two_phase`]) is still on-going or - /// not. - fn ongoing() -> bool; -} diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs index cd81ef5b3d59a..fbd20a9287aed 100644 --- a/frame/election-providers/src/lib.rs +++ b/frame/election-providers/src/lib.rs @@ -38,6 +38,6 @@ const LOG_TARGET: &'static str = "election-provider"; #[doc(hidden)] pub use sp_npos_elections::VoteWeight; #[doc(hidden)] -use sp_runtime::traits::UniqueSaturatedInto; +pub use sp_runtime::traits::UniqueSaturatedInto; #[doc(hidden)] pub use sp_std::convert::TryInto; diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 33bd6cc1f9b78..97d788558d69b 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -415,16 +415,18 @@ decl_event!( } ); -// decl_error! { -// pub enum PalletError for Module { -// /// Submission was too early. -// EarlySubmission, -// /// The queue was full, and the solution was not better than any of the existing ones. -// QueueFull, -// /// The origin failed to pay the deposit. -// CannotPayDeposit, -// } -// } +frame_support::decl_error! { + pub enum PalletError for Module where ExtendedBalance: From>> { + /// Submission was too early. + EarlySubmission, + /// Submission was too weak, score-wise. + WeakSubmission, + /// The queue was full, and the solution was not better than any of the existing ones. + QueueFull, + /// The origin failed to pay the deposit. + CannotPayDeposit, + } +} decl_module! { pub struct Module for enum Call @@ -433,7 +435,7 @@ decl_module! { ExtendedBalance: From>> { // TODO: replace with PalletError once we have it working. - type Error = &'static str; + type Error = PalletError; fn deposit_event() = default; fn on_initialize(now: T::BlockNumber) -> Weight { @@ -491,7 +493,7 @@ decl_module! { let who = ensure_signed(origin)?; // ensure solution is timely. - ensure!(Self::current_phase().is_signed(), "EarlySubmission"); + ensure!(Self::current_phase().is_signed(), PalletError::::EarlySubmission); // ensure solution claims is better. let mut signed_submissions = Self::signed_submissions(); @@ -501,7 +503,7 @@ decl_module! { // collect deposit. Thereafter, the function cannot fail. let deposit = signed_submissions[index].deposit; - T::Currency::reserve(&who, deposit).map_err(|_| "CannotPayDeposit")?; + T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; // store the new signed submission. debug_assert!(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()); diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index 4d1ae9b0db41b..8c0a49987b2c4 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -196,7 +196,7 @@ mod tests { assert_noop!( TwoPhase::submit(Origin::signed(10), solution), - "EarlySubmission", + PalletError::::EarlySubmission, ); }) } diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 66fd8fc6d0e3e..e27f4db5360bb 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -26,7 +26,7 @@ use sp_runtime::{ InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, }, - PerU16, SaturatedConversion, + SaturatedConversion, }; use sp_std::cmp::Ordering; @@ -316,7 +316,7 @@ where // ensure solution is timely. Don't panic yet. This is a cheap check. ensure!( Self::current_phase().is_unsigned_open(), - "UnsignedPhaseClosed" + PalletError::::EarlySubmission ); // ensure score is being improved. Panic henceforth. @@ -326,7 +326,7 @@ where q.score, T::SolutionImprovementThreshold::get() )), - "WeakSolution" + PalletError::::WeakSubmission ); Ok(()) @@ -735,7 +735,7 @@ mod tests { assert_noop!( TwoPhase::submit_unsigned(Origin::none(), solution), - "WeakSolution" + PalletError::::WeakSubmission, ); // trial 2: a solution who's score is only 7, i.e. 70% better in the first element. From d53785caa6e10e477ed1e0c4ecb324f771f1ac17 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 16 Oct 2020 16:31:51 +0200 Subject: [PATCH 13/62] Add basic benchmark setup, needs more work --- Cargo.lock | 6 +- frame/election-providers/Cargo.toml | 17 +- frame/election-providers/expanded.rs | 1127 +++++++++-------- .../src/two_phase/benchmarking.rs | 133 ++ .../src/two_phase/macros.rs | 56 +- .../election-providers/src/two_phase/mock.rs | 32 +- frame/election-providers/src/two_phase/mod.rs | 54 +- .../src/two_phase/unsigned.rs | 110 +- primitives/npos-elections/src/lib.rs | 4 +- 9 files changed, 959 insertions(+), 580 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d4e3bfeaa386..d0d253899f24e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1552,13 +1552,16 @@ dependencies = [ name = "frame-election-providers" version = "2.0.0" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "hex-literal", "pallet-balances", "parity-scale-codec", - "parking_lot 0.11.0", + "parking_lot 0.10.2", "paste 1.0.1", + "rand 0.7.3", + "rand_chacha 0.2.2", "serde", "sp-arithmetic", "sp-core", @@ -1568,6 +1571,7 @@ dependencies = [ "sp-runtime", "sp-staking", "sp-std", + "sp-tracing", "static_assertions", "substrate-test-utils", ] diff --git a/frame/election-providers/Cargo.toml b/frame/election-providers/Cargo.toml index deb28743e9273..001bc7989abe3 100644 --- a/frame/election-providers/Cargo.toml +++ b/frame/election-providers/Cargo.toml @@ -27,6 +27,11 @@ sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primit sp-arithmetic = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/arithmetic" } sp-election-providers = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/election-providers" } +# Optional imports for benchmarking +frame-benchmarking = { version = "2.0.0", default-features = false, path = "../benchmarking", optional = true } +rand_chacha = { version = "0.2", default-features = false, optional = true } +rand = { version = "0.7.3", optional = true } + [dev-dependencies] sp-io = { version = "2.0.0", path = "../../primitives/io" } hex-literal = "0.3.1" @@ -34,7 +39,12 @@ pallet-balances = { version = "2.0.0", path = "../balances" } sp-core = { version = "2.0.0", path = "../../primitives/core" } paste = "1.0.1" substrate-test-utils = { version = "2.0.0", path = "../../test-utils" } -parking_lot = "0.11.0" +parking_lot = "0.10.2" +sp-tracing = { version = "2.0.0", path = "../../primitives/tracing" } + +frame-benchmarking = { version = "2.0.0", path = "../benchmarking" } +rand_chacha = { version = "0.2" } +rand = "0.7.3" [features] default = ["std"] @@ -48,3 +58,8 @@ std = [ "sp-std/std", "sp-election-providers/std" ] +runtime-benchmarks = [ + "frame-benchmarking", + "rand_chacha", + "rand", +] diff --git a/frame/election-providers/expanded.rs b/frame/election-providers/expanded.rs index 53cbfe81ef2d8..14d412384b5fe 100644 --- a/frame/election-providers/expanded.rs +++ b/frame/election-providers/expanded.rs @@ -123,113 +123,115 @@ pub mod onchain { /// The two-phase module. pub mod two_phase { //! # Two phase election provider pallet. - //! - //! As the name suggests, this election provider has two distinct phases (see [`Phase`]), signed and - //! unsigned. - //! - //! ## Phases - //! - //! The timeline of pallet is as follows. At each block, - //! [`ElectionDataProvider::next_election_prediction`] is used to estimate the time remaining to the - //! next call to `elect`. Based on this, a phase is chosen. The timeline is as follows. - //! - //! ```ignore - //! elect() - //! + <--T::SignedPhase--> + <--T::UnsignedPhase--> + - //! +-------------------------------------------------------------------+ - //! Phase::Off + Phase::Signed + Phase::Unsigned + - //! - //! Note that the unsigned phase starts `T::UnsignedPhase` blocks before the - //! `next_election_prediction`, but only ends when a call to `ElectionProvider::elect` happens. - //! - //! ``` - //! ### Signed Phase - //! - //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A - //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution - //! on-chain for a number of blocks. A maximum of [`Trait::MaxSignedSubmissions`] solutions are - //! stored. The queue is always sorted based on score (worse -> best). - //! - //! Upon arrival of a new solution: - //! - //! 1. If the queue is not full, it is stored. - //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the - //! worse solution is discarded (TODO: what to do with the bond?) and the new solution is stored - //! in the correct index. - //! 3. If the queue is full and the solution is not an improvement compared to any of the queued - //! ones, it is instantly rejected and no additional bond is reserved. - //! - //! A signed solution cannot be reversed, taken back, updated, or retracted. In other words, the - //! origin can not bail out in any way. - //! - //! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed - //! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure - //! the score claimed by this score was correct, among other checks. At each step, if the current - //! best solution is passes the feasibility check, it is considered to be the best one. The sender - //! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without - //! being checked. - //! - //! The following example covers all of the cases at the end of the signed phase: - //! - //! ```ignore - //! Queue - //! +-------------------------------+ - //! |Solution(score=20, valid=false)| +--> Slashed - //! +-------------------------------+ - //! |Solution(score=15, valid=true )| +--> Rewarded - //! +-------------------------------+ - //! |Solution(score=10, valid=true )| +--> Discarded - //! +-------------------------------+ - //! |Solution(score=05, valid=false)| +--> Discarded - //! +-------------------------------+ - //! | None | - //! +-------------------------------+ - //! ``` - //! - //! Note that both of the bottom solutions end up being discarded and get their deposit back, - //! despite one of them being invalid. - //! - //! ## Unsigned Phase - //! - //! If signed phase ends with a good solution, then the unsigned phase will be `active` - //! ([`Phase::Unsigned(true)`]), else the unsigned phase will be `passive`. - //! - //! TODO - //! - //! ### Fallback - //! - //! If we reach the end of both phases (i.e. call to `ElectionProvider::elect` happens) and no good - //! solution is queued, then we fallback to an on-chain election. The on-chain election is slow, and - //! contains to balancing or reduction post-processing. - //! - //! ## Correct Submission - //! - //! TODO - //! - //! ## Accuracy - //! - //! TODO - //! + //! + //! As the name suggests, this election provider has two distinct phases (see [`Phase`]), signed and + //! unsigned. + //! + //! ## Phases + //! + //! The timeline of pallet is as follows. At each block, + //! [`ElectionDataProvider::next_election_prediction`] is used to estimate the time remaining to the + //! next call to `elect`. Based on this, a phase is chosen. The timeline is as follows. + //! + //! ```ignore + //! elect() + //! + <--T::SignedPhase--> + <--T::UnsignedPhase--> + + //! +-------------------------------------------------------------------+ + //! Phase::Off + Phase::Signed + Phase::Unsigned + + //! + //! Note that the unsigned phase starts `T::UnsignedPhase` blocks before the + //! `next_election_prediction`, but only ends when a call to `ElectionProvider::elect` happens. + //! + //! ``` + //! ### Signed Phase + //! + //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A + //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution + //! on-chain for a number of blocks. A maximum of [`Trait::MaxSignedSubmissions`] solutions are + //! stored. The queue is always sorted based on score (worse -> best). + //! + //! Upon arrival of a new solution: + //! + //! 1. If the queue is not full, it is stored. + //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the + //! worse solution is discarded (TODO: what to do with the bond?) and the new solution is stored + //! in the correct index. + //! 3. If the queue is full and the solution is not an improvement compared to any of the queued + //! ones, it is instantly rejected and no additional bond is reserved. + //! + //! A signed solution cannot be reversed, taken back, updated, or retracted. In other words, the + //! origin can not bail out in any way. + //! + //! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed + //! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure + //! the score claimed by this score was correct, among other checks. At each step, if the current + //! best solution is passes the feasibility check, it is considered to be the best one. The sender + //! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without + //! being checked. + //! + //! The following example covers all of the cases at the end of the signed phase: + //! + //! ```ignore + //! Queue + //! +-------------------------------+ + //! |Solution(score=20, valid=false)| +--> Slashed + //! +-------------------------------+ + //! |Solution(score=15, valid=true )| +--> Rewarded + //! +-------------------------------+ + //! |Solution(score=10, valid=true )| +--> Discarded + //! +-------------------------------+ + //! |Solution(score=05, valid=false)| +--> Discarded + //! +-------------------------------+ + //! | None | + //! +-------------------------------+ + //! ``` + //! + //! TODO: what if length of some phase is zero? + //! + //! Note that both of the bottom solutions end up being discarded and get their deposit back, + //! despite one of them being invalid. + //! + //! ## Unsigned Phase + //! + //! If signed phase ends with a good solution, then the unsigned phase will be `active` + //! ([`Phase::Unsigned(true)`]), else the unsigned phase will be `passive`. + //! + //! TODO + //! + //! ### Fallback + //! + //! If we reach the end of both phases (i.e. call to `ElectionProvider::elect` happens) and no good + //! solution is queued, then we fallback to an on-chain election. The on-chain election is slow, and + //! contains to balancing or reduction post-processing. + //! + //! ## Correct Submission + //! + //! TODO + //! + //! ## Accuracy + //! + //! TODO + //! use crate::onchain::OnChainSequentialPhragmen; - use codec::{Decode, Encode, HasCompact}; - use frame_support::{ - decl_event, decl_module, decl_storage, - dispatch::{DispatchResultWithPostInfo, Dispatchable}, - ensure, - traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, - weights::Weight, - }; - use frame_system::{ensure_none, ensure_signed}; - use sp_election_providers::{ElectionDataProvider, ElectionProvider}; - use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, is_score_better, Assignment, CompactSolution, - ElectionScore, EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, - }; - use sp_runtime::{ - traits::Zero, transaction_validity::TransactionPriority, InnerOf, PerThing, Perbill, - RuntimeDebug, - }; - use sp_std::prelude::*; + use codec::{Decode, Encode, HasCompact}; + use frame_support::{ + decl_event, decl_module, decl_storage, + dispatch::DispatchResultWithPostInfo, + ensure, + traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, + weights::Weight, + }; + use frame_system::{ensure_none, ensure_signed, offchain::SendTransactionTypes}; + use sp_election_providers::{ElectionDataProvider, ElectionProvider}; + use sp_npos_elections::{ + assignment_ratio_to_staked_normalized, is_score_better, Assignment, CompactSolution, + ElectionScore, EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, + }; + use sp_runtime::{ + traits::Zero, transaction_validity::TransactionPriority, InnerOf, PerThing, Perbill, + RuntimeDebug, + }; + use sp_std::prelude::*; #[macro_use] pub(crate) mod macros { //! Some helper macros for this crate. @@ -404,173 +406,33 @@ pub mod two_phase { } } pub mod unsigned { - //! The unsigned phase implementation. - use crate::two_phase::*; - use frame_support::{dispatch::DispatchResult, unsigned::ValidateUnsigned}; - use sp_npos_elections::{seq_phragmen, CompactSolution, ElectionResult}; - use sp_runtime::{ - traits::TrailingZeroInput, - transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionValidity, - TransactionValidityError, ValidTransaction, - }, - PerU16, SaturatedConversion, - }; - use sp_std::cmp::Ordering; - /// Witness data about the size of the election. - /// - /// This is needed for proper weight calculation. - pub struct WitnessData { - /// Number of all voters. - /// - /// This must match the on-chain snapshot. - #[codec(compact)] - voters: u32, - /// Number of all targets. - /// - /// This must match the on-chain snapshot. - #[codec(compact)] - target: u32, - } - impl ::core::marker::StructuralPartialEq for WitnessData {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for WitnessData { - #[inline] - fn eq(&self, other: &WitnessData) -> bool { - match *other { - WitnessData { - voters: ref __self_1_0, - target: ref __self_1_1, - } => match *self { - WitnessData { - voters: ref __self_0_0, - target: ref __self_0_1, - } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), - }, - } - } - #[inline] - fn ne(&self, other: &WitnessData) -> bool { - match *other { - WitnessData { - voters: ref __self_1_0, - target: ref __self_1_1, - } => match *self { - WitnessData { - voters: ref __self_0_0, - target: ref __self_0_1, - } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), - }, - } - } - } - impl ::core::marker::StructuralEq for WitnessData {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for WitnessData { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for WitnessData { - #[inline] - fn clone(&self) -> WitnessData { - { - let _: ::core::clone::AssertParamIsClone; - let _: ::core::clone::AssertParamIsClone; - *self - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for WitnessData {} - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for WitnessData { - fn encode_to(&self, dest: &mut EncOut) { - { - dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . voters ) ) ; - } - { - dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . target ) ) ; - } - } - } - impl _parity_scale_codec::EncodeLike for WitnessData {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for WitnessData { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(WitnessData { - voters: { - let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; - match res { - Err(_) => { - return Err("Error decoding field WitnessData.voters".into()) - } - Ok(a) => a.into(), - } - }, - target: { - let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; - match res { - Err(_) => { - return Err("Error decoding field WitnessData.target".into()) - } - Ok(a) => a.into(), - } - }, - }) - } - } - }; - impl core::fmt::Debug for WitnessData { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("WitnessData") - .field("voters", &self.voters) - .field("target", &self.target) - .finish() - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for WitnessData { - #[inline] - fn default() -> WitnessData { - WitnessData { - voters: ::core::default::Default::default(), - target: ::core::default::Default::default(), - } - } - } - /// Storage key used to store the persistent offchain worker status. - pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; - /// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice - /// within a window of 5 blocks. + //! The unsigned phase implementation. + use crate::two_phase::*; + use frame_support::{dispatch::DispatchResult, unsigned::ValidateUnsigned}; + use frame_system::offchain::SubmitTransaction; + use sp_npos_elections::{seq_phragmen, CompactSolution, ElectionResult}; + use sp_runtime::{ + offchain::storage::StorageValueRef, + traits::TrailingZeroInput, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, + TransactionValidityError, ValidTransaction, + }, + SaturatedConversion, + }; + use sp_std::cmp::Ordering; + /// Storage key used to store the persistent offchain worker status. + pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; + /// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice + /// within a window of 5 blocks. pub(crate) const OFFCHAIN_REPEAT: u32 = 5; /// Default number of blocks for which the unsigned transaction should stay in the pool pub(crate) const DEFAULT_LONGEVITY: u64 = 25; impl Module - where - ExtendedBalance: From>>, - { - /// Min a new npos solution. + where + ExtendedBalance: From>>, + { + /// Min a new npos solution. pub fn mine_solution(iters: usize) -> Result>, Error> { let desired_targets = Self::desired_targets() as usize; let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; @@ -775,19 +637,19 @@ pub mod two_phase { voters.min(witness.voters) } /// Checks if an execution of the offchain worker is permitted at the given block number, or not. - /// - /// This essentially makes sure that we don't run on previous blocks in case of a re-org, and we - /// don't run twice within a window of length [`OFFCHAIN_REPEAT`]. - /// - /// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise. - pub(crate) fn set_check_offchain_execution_status( - now: T::BlockNumber, - ) -> Result<(), &'static str> { - let storage = - sp_runtime::offchain::storage::StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); - let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); - let mutate_stat = storage.mutate::<_, &'static str, _>( - |maybe_head: Option>| match maybe_head { + /// + /// This essentially makes sure that we don't run on previous blocks in case of a re-org, and we + /// don't run twice within a window of length [`OFFCHAIN_REPEAT`]. + /// + /// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise. + pub(crate) fn set_check_offchain_execution_status( + now: T::BlockNumber, + ) -> Result<(), &'static str> { + let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); + let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); + let mutate_stat = storage.mutate::<_, &'static str, _>( + |maybe_head: Option>| { + match maybe_head { Some(Some(head)) if now < head => Err("fork."), Some(Some(head)) if now >= head && now <= head + threshold => { Err("recently executed.") @@ -795,29 +657,33 @@ pub mod two_phase { Some(Some(head)) if now > head + threshold => Ok(now), _ => Ok(now), }, - ); + ); match mutate_stat { Ok(Ok(_)) => Ok(()), Ok(Err(_)) => Err("failed to write to offchain db."), Err(why) => Err(why), } } - /// Mine a new solution, and submit it back to the chian as an unsigned transaction. - pub(crate) fn mine_and_submit() -> Result<(), Error> { - let balancing = Self::get_balancing_iters(); - Self::mine_solution(balancing).map(|raw_solution| ()) - } - pub(crate) fn pre_dispatch_checks( - solution: &RawSolution>, - ) -> DispatchResult { - { - if !Self::current_phase().is_unsigned_open() { - { - return Err("UnsignedPhaseClosed".into()); - }; - } - }; - { + /// Mine a new solution, and submit it back to the chian as an unsigned transaction. + pub(crate) fn mine_and_submit() -> Result<(), Error> { + let balancing = Self::get_balancing_iters(); + Self::mine_solution(balancing).and_then(|raw_solution| { + let call = Call::submit_unsigned(raw_solution).into(); + SubmitTransaction::>::submit_unsigned_transaction(call) + .map_err(|_| Error::PoolSubmissionFailed) + }) + } + pub(crate) fn pre_dispatch_checks( + solution: &RawSolution>, + ) -> DispatchResult { + { + if !Self::current_phase().is_unsigned_open() { + { + return Err(PalletError::::EarlySubmission.into()); + }; + } + }; + { if !Self::queued_solution().map_or(true, |q: ReadySolution<_>| { is_score_better::( solution.score, @@ -826,13 +692,13 @@ pub mod two_phase { ) }) { { - return Err("WeakSolution".into()); + return Err(PalletError::::WeakSubmission.into()); }; } - }; - Ok(()) + }; + Ok(()) } - } + } #[allow(deprecated)] impl ValidateUnsigned for Module where @@ -874,7 +740,7 @@ pub mod two_phase { } } } - } + } /// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] /// implementer. pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< @@ -1723,31 +1589,173 @@ pub mod two_phase { } } #[automatically_derived] - #[allow(unused_qualifications)] + #[allow(unused_qualifications)] impl ::core::default::Default for ReadySolution { - #[inline] + #[inline] fn default() -> ReadySolution { ReadySolution { supports: ::core::default::Default::default(), score: ::core::default::Default::default(), compute: ::core::default::Default::default(), } - } - } - /// The crate errors. Note that this is different from the [`PalletError`]. - pub enum Error { - /// A feasibility error. - Feasibility(FeasibilityError), - /// An error in the on-chain fallback. - OnChainFallback(crate::onchain::Error), - /// An internal error in the NPoS elections crate. - NposElections(sp_npos_elections::Error), - /// Snapshot data was unavailable unexpectedly. - SnapshotUnAvailable, - } - impl core::fmt::Debug for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { + } + } + /// Witness data about the size of the election. + /// + /// This is needed for proper weight calculation. + pub struct WitnessData { + /// Number of all voters. + /// + /// This must match the on-chain snapshot. + #[codec(compact)] + voters: u32, + /// Number of all targets. + /// + /// This must match the on-chain snapshot. + #[codec(compact)] + targets: u32, + } + impl ::core::marker::StructuralPartialEq for WitnessData {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for WitnessData { + #[inline] + fn eq(&self, other: &WitnessData) -> bool { + match *other { + WitnessData { + voters: ref __self_1_0, + targets: ref __self_1_1, + } => match *self { + WitnessData { + voters: ref __self_0_0, + targets: ref __self_0_1, + } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), + }, + } + } + #[inline] + fn ne(&self, other: &WitnessData) -> bool { + match *other { + WitnessData { + voters: ref __self_1_0, + targets: ref __self_1_1, + } => match *self { + WitnessData { + voters: ref __self_0_0, + targets: ref __self_0_1, + } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), + }, + } + } + } + impl ::core::marker::StructuralEq for WitnessData {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for WitnessData { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for WitnessData { + #[inline] + fn clone(&self) -> WitnessData { + { + let _: ::core::clone::AssertParamIsClone; + let _: ::core::clone::AssertParamIsClone; + *self + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for WitnessData {} + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for WitnessData { + fn encode_to(&self, dest: &mut EncOut) { + { + dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . voters ) ) ; + } + { + dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . targets ) ) ; + } + } + } + impl _parity_scale_codec::EncodeLike for WitnessData {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for WitnessData { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(WitnessData { + voters: { + let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; + match res { + Err(_) => return Err("Error decoding field WitnessData.voters".into()), + Ok(a) => a.into(), + } + }, + targets: { + let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; + match res { + Err(_) => return Err("Error decoding field WitnessData.targets".into()), + Ok(a) => a.into(), + } + }, + }) + } + } + }; + impl core::fmt::Debug for WitnessData { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("WitnessData") + .field("voters", &self.voters) + .field("targets", &self.targets) + .finish() + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for WitnessData { + #[inline] + fn default() -> WitnessData { + WitnessData { + voters: ::core::default::Default::default(), + targets: ::core::default::Default::default(), + } + } + } + /// The crate errors. Note that this is different from the [`PalletError`]. + pub enum Error { + /// A feasibility error. + Feasibility(FeasibilityError), + /// An error in the on-chain fallback. + OnChainFallback(crate::onchain::Error), + /// An internal error in the NPoS elections crate. + NposElections(sp_npos_elections::Error), + /// Snapshot data was unavailable unexpectedly. + SnapshotUnAvailable, + /// Submitting a transaction to the pool failed. + /// + /// This can only happen in the unsigned phase. + PoolSubmissionFailed, + } + impl core::fmt::Debug for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { Self::Feasibility(ref a0) => { fmt.debug_tuple("Error::Feasibility").field(a0).finish() } @@ -1758,10 +1766,13 @@ pub mod two_phase { fmt.debug_tuple("Error::NposElections").field(a0).finish() } Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), + Self::PoolSubmissionFailed => { + fmt.debug_tuple("Error::PoolSubmissionFailed").finish() + } _ => Ok(()), } - } - } + } + } impl ::core::marker::StructuralEq for Error {} #[automatically_derived] #[allow(unused_qualifications)] @@ -1946,21 +1957,24 @@ pub mod two_phase { fn submit_unsigned() -> Weight; } impl WeightInfo for () { - fn feasibility_check() -> Weight { + fn feasibility_check() -> Weight { Default::default() } fn submit() -> Weight { Default::default() } fn submit_unsigned() -> Weight { - Default::default() - } - } - pub trait Trait: frame_system::Trait { - /// Event type. - type Event: From> + Into<::Event>; - /// Currency type. - type Currency: ReservableCurrency + Currency; + Default::default() + } + } + pub trait Trait: frame_system::Trait + SendTransactionTypes> + where + ExtendedBalance: From>>, + { + /// Event type. + type Event: From> + Into<::Event>; + /// Currency type. + type Currency: ReservableCurrency + Currency; /// Duration of the signed phase. type SignedPhase: Get; /// Duration of the unsigned phase. @@ -1973,55 +1987,65 @@ pub mod two_phase { type SignedDepositBase: Get>; type SignedDepositByte: Get>; type SignedDepositWeight: Get>; - /// The minimum amount of improvement to the solution score that defines a solution as "better". - type SolutionImprovementThreshold: Get; - type UnsignedMaxIterations: Get; - type UnsignedCall: Dispatchable + Clone; - type UnsignedPriority: Get; - /// Handler for the slashed deposits. - type SlashHandler: OnUnbalanced>; - /// Handler for the rewards. + /// The minimum amount of improvement to the solution score that defines a solution as "better". + type SolutionImprovementThreshold: Get; + type UnsignedMaxIterations: Get; + type UnsignedPriority: Get; + /// Handler for the slashed deposits. + type SlashHandler: OnUnbalanced>; + /// Handler for the rewards. type RewardHandler: OnUnbalanced>; /// Something that will provide the election data. type ElectionDataProvider: ElectionDataProvider; /// The weight of the pallet. type WeightInfo: WeightInfo; - } + } use self::sp_api_hidden_includes_decl_storage::hidden_include::{ IterableStorageDoubleMap as _, IterableStorageMap as _, StorageDoubleMap as _, StorageMap as _, StoragePrefixedMap as _, StorageValue as _, }; #[doc(hidden)] mod sp_api_hidden_includes_decl_storage { - pub extern crate frame_support as hidden_include; - } - trait Store { - type CurrentPhase; - type SignedSubmissions; - type QueuedSolution; - type SnapshotTargets; + pub extern crate frame_support as hidden_include; + } + trait Store { + type Round; + type CurrentPhase; + type SignedSubmissions; + type QueuedSolution; + type SnapshotTargets; type SnapshotVoters; type DesiredTargets; - } + } impl Store for Module - where - ExtendedBalance: From>>, - { - type CurrentPhase = CurrentPhase; - type SignedSubmissions = SignedSubmissions; - type QueuedSolution = QueuedSolution; - type SnapshotTargets = SnapshotTargets; + where + ExtendedBalance: From>>, + { + type Round = Round; + type CurrentPhase = CurrentPhase; + type SignedSubmissions = SignedSubmissions; + type QueuedSolution = QueuedSolution; + type SnapshotTargets = SnapshotTargets; type SnapshotVoters = SnapshotVoters; type DesiredTargets = DesiredTargets; - } + } impl Module - where - ExtendedBalance: From>>, - { - /// Current phase. - pub fn current_phase() -> Phase { - < CurrentPhase < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase < T :: BlockNumber > > > :: get ( ) - } + where + ExtendedBalance: From>>, + { + /// Internal counter ofr the number of rounds. + /// + /// This is useful for de-duplication of transactions submitted to the pool, and general + /// diagnostics of the module. + /// + /// This is merely incremented once per every time that signed phase starts. + pub fn round() -> u32 { + < Round < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) + } + /// Current phase. + pub fn current_phase() -> Phase { + < CurrentPhase < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase < T :: BlockNumber > > > :: get ( ) + } /// Sorted (worse -> best) list of unchecked, signed solutions. pub fn signed_submissions( ) -> Vec, CompactOf>> { @@ -2049,13 +2073,51 @@ pub mod two_phase { pub fn desired_targets() -> u32 { < DesiredTargets < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) } - } - #[doc(hidden)] - pub struct __GetByteStructCurrentPhase( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); + } + #[doc(hidden)] + pub struct __GetByteStructRound( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_Round: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructRound + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_Round + .get_or_init(|| { + let def_val: u32 = 0; + ::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructRound where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructRound where + ExtendedBalance: From>> + { + } + #[doc(hidden)] + pub struct __GetByteStructCurrentPhase( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); #[cfg(feature = "std")] #[allow(non_upper_case_globals)] static __CACHE_GET_BYTE_STRUCT_CurrentPhase: @@ -2289,18 +2351,17 @@ pub mod two_phase { { } impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - pub fn storage_metadata( - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::StorageMetadata - { - self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec, CompactOf>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted (worse -> best) list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current best solution, signed or unsigned." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } ] [ .. ] ) , } - } - } - /// Hidden instance generated to be internally used when module is used without - /// instance. + where + ExtendedBalance: From>>, + { + #[doc(hidden)] + pub fn storage_metadata( + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::StorageMetadata { + self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Round" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructRound :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Internal counter ofr the number of rounds." , "" , " This is useful for de-duplication of transactions submitted to the pool, and general" , " diagnostics of the module." , "" , " This is merely incremented once per every time that signed phase starts." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec, CompactOf>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted (worse -> best) list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current best solution, signed or unsigned." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } ] [ .. ] ) , } + } + } + /// Hidden instance generated to be internally used when module is used without + /// instance. #[doc(hidden)] pub struct __InherentHiddenInstance; #[automatically_derived] @@ -2363,18 +2424,46 @@ pub mod two_phase { } } impl self::sp_api_hidden_includes_decl_storage::hidden_include::traits::Instance - for __InherentHiddenInstance - { - const PREFIX: &'static str = "TwoPhaseElectionProvider"; - } - /// Current phase. - pub struct CurrentPhase( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; + for __InherentHiddenInstance + { + const PREFIX: &'static str = "TwoPhaseElectionProvider"; + } + /// Internal counter ofr the number of rounds. + /// + /// This is useful for de-duplication of transactions submitted to the pool, and general + /// diagnostics of the module. + /// + /// This is merely incremented once per every time that signed phase starts. + pub struct Round( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, + ); + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + u32, + > for Round + { + type Query = u32; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"Round" + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + v.unwrap_or_else(|| 0) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + Some(v) + } + } + /// Current phase. + pub struct CurrentPhase( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ) + where + ExtendedBalance: From>>; impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< Phase, @@ -2839,21 +2928,23 @@ pub mod two_phase { } } pub enum PalletError - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - __Ignore( - ::frame_support::sp_std::marker::PhantomData<(T,)>, - ::frame_support::Never, - ), - /// Submission was too early. - EarlySubmission, - /// The queue was full, and the solution was not better than any of the existing ones. - QueueFull, - /// The origin failed to pay the deposit. - CannotPayDeposit, - } + where + ExtendedBalance: From>>, + { + #[doc(hidden)] + __Ignore( + ::frame_support::sp_std::marker::PhantomData<(T,)>, + ::frame_support::Never, + ), + /// Submission was too early. + EarlySubmission, + /// Submission was too weak, score-wise. + WeakSubmission, + /// The queue was full, and the solution was not better than any of the existing ones. + QueueFull, + /// The origin failed to pay the deposit. + CannotPayDeposit, + } impl ::frame_support::sp_std::fmt::Debug for PalletError where ExtendedBalance: From>>, @@ -2866,10 +2957,10 @@ pub mod two_phase { } } impl PalletError - where - ExtendedBalance: From>>, - { - fn as_u8(&self) -> u8 { + where + ExtendedBalance: From>>, + { + fn as_u8(&self) -> u8 { match self { PalletError::__Ignore(_, _) => { ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( @@ -2883,12 +2974,13 @@ pub mod two_phase { )) } PalletError::EarlySubmission => 0, - PalletError::QueueFull => 0 + 1, - PalletError::CannotPayDeposit => 0 + 1 + 1, + PalletError::WeakSubmission => 0 + 1, + PalletError::QueueFull => 0 + 1 + 1, + PalletError::CannotPayDeposit => 0 + 1 + 1 + 1, } - } - fn as_str(&self) -> &'static str { - match self { + } + fn as_str(&self) -> &'static str { + match self { Self::__Ignore(_, _) => { ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( &["internal error: entered unreachable code: "], @@ -2901,11 +2993,12 @@ pub mod two_phase { )) } PalletError::EarlySubmission => "EarlySubmission", + PalletError::WeakSubmission => "WeakSubmission", PalletError::QueueFull => "QueueFull", PalletError::CannotPayDeposit => "CannotPayDeposit", } - } - } + } + } impl From> for &'static str where ExtendedBalance: From>>, @@ -2930,10 +3023,10 @@ pub mod two_phase { } } impl ::frame_support::error::ModuleErrorMetadata for PalletError - where - ExtendedBalance: From>>, - { - fn metadata() -> &'static [::frame_support::error::ErrorMetadata] { + where + ExtendedBalance: From>>, + { + fn metadata() -> &'static [::frame_support::error::ErrorMetadata] { &[ ::frame_support::error::ErrorMetadata { name: ::frame_support::error::DecodeDifferent::Encode("EarlySubmission"), @@ -2941,6 +3034,12 @@ pub mod two_phase { r" Submission was too early.", ]), }, + ::frame_support::error::ErrorMetadata { + name: ::frame_support::error::DecodeDifferent::Encode("WeakSubmission"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[ + r" Submission was too weak, score-wise.", + ]), + }, ::frame_support::error::ErrorMetadata { name: ::frame_support::error::DecodeDifferent::Encode("QueueFull"), documentation: ::frame_support::error::DecodeDifferent::Encode(&[ @@ -2955,7 +3054,7 @@ pub mod two_phase { }, ] } - } + } pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>) where ExtendedBalance: From>>; @@ -3035,11 +3134,11 @@ pub mod two_phase { } } impl - ::frame_support::traits::OnInitialize<::BlockNumber> for Module - where - ExtendedBalance: From>>, - { - fn on_initialize(now: T::BlockNumber) -> Weight { + ::frame_support::traits::OnInitialize<::BlockNumber> for Module + where + ExtendedBalance: From>>, + { + fn on_initialize(now: T::BlockNumber) -> Weight { let __within_span__ = { use ::tracing::__macro_support::Callsite as _; static CALLSITE: ::tracing::__macro_support::MacroCallsite = { @@ -3050,7 +3149,7 @@ pub mod two_phase { "frame_election_providers::two_phase", ::tracing::Level::TRACE, Some("frame/election-providers/src/two_phase/mod.rs"), - Some(429u32), + Some(464u32), Some("frame_election_providers::two_phase"), ::tracing_core::field::FieldSet::new( &[], @@ -3085,21 +3184,28 @@ pub mod two_phase { let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); let unsigned_deadline = T::UnsignedPhase::get(); let remaining = next_election - now; - match Self::current_phase() { + match Self::current_phase() { Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { >::put(Phase::Signed); + Round::mutate(|r| *r += 1); Self::start_signed_phase(); { let lvl = ::log::Level::Info; if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { ::log::__private_api_log( ::core::fmt::Arguments::new_v1( - &["Starting signed phase at #"], - &match (&now,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], + &["\u{1f3e6} Starting signed phase at #", " , round "], + &match (&now, &Self::round()) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Display::fmt, + ), + ], }, ), lvl, @@ -3107,7 +3213,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 452u32, + 488u32, ), ); } @@ -3121,7 +3227,7 @@ pub mod two_phase { if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { ::log::__private_api_log( ::core::fmt::Arguments::new_v1( - &["Starting unsigned phase at #"], + &["\u{1f3e6} Starting unsigned phase at #"], &match (&now,) { (arg0,) => [::core::fmt::ArgumentV1::new( arg0, @@ -3134,7 +3240,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 458u32, + 494u32, ), ); } @@ -3145,7 +3251,7 @@ pub mod two_phase { Default::default() } } - } + } impl ::frame_support::traits::OnRuntimeUpgrade for Module where ExtendedBalance: From>> { @@ -3157,12 +3263,11 @@ pub mod two_phase { { } impl - ::frame_support::traits::OffchainWorker<::BlockNumber> - for Module - where - ExtendedBalance: From>>, - { - fn offchain_worker(n: T::BlockNumber) { + ::frame_support::traits::OffchainWorker<::BlockNumber> for Module + where + ExtendedBalance: From>>, + { + fn offchain_worker(n: T::BlockNumber) { if Self::set_check_offchain_execution_status(n).is_ok() && Self::current_phase().is_unsigned_open_at(n) { @@ -3171,7 +3276,7 @@ pub mod two_phase { if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { ::log::__private_api_log( ::core::fmt::Arguments::new_v1( - &["error while submitting transaction in OCW: "], + &["\u{1f3e6} error while submitting transaction in OCW: "], &match (&e,) { (arg0,) => [::core::fmt::ArgumentV1::new( arg0, @@ -3184,14 +3289,14 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 475u32, + 511u32, ), ); } }); } } - } + } impl Module where ExtendedBalance: From>>, @@ -3207,27 +3312,27 @@ pub mod two_phase { { } /// Can also be called using [`Call`]. - /// - /// [`Call`]: enum.Call.html + /// + /// [`Call`]: enum.Call.html impl Module - where - ExtendedBalance: From>>, - { - /// Submit a solution for the signed phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// The solution potentially queued, based on the claimed score and processed at the end of - /// the signed phase. - /// - /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution - /// might be rewarded, slashed, or get all or a part of the deposit back. - /// - /// NOTE: Calling this function will bypass origin filters. + where + ExtendedBalance: From>>, + { + /// Submit a solution for the signed phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// The solution potentially queued, based on the claimed score and processed at the end of + /// the signed phase. + /// + /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution + /// might be rewarded, slashed, or get all or a part of the deposit back. + /// + /// NOTE: Calling this function will bypass origin filters. fn submit( - origin: T::Origin, - solution: RawSolution>, - ) -> DispatchResultWithPostInfo { + origin: T::Origin, + solution: RawSolution>, + ) -> DispatchResultWithPostInfo { let __within_span__ = { use ::tracing::__macro_support::Callsite as _; static CALLSITE: ::tracing::__macro_support::MacroCallsite = { @@ -3238,7 +3343,7 @@ pub mod two_phase { "frame_election_providers::two_phase", ::tracing::Level::TRACE, Some("frame/election-providers/src/two_phase/mod.rs"), - Some(429u32), + Some(464u32), Some("frame_election_providers::two_phase"), ::tracing_core::field::FieldSet::new( &[], @@ -3299,26 +3404,26 @@ pub mod two_phase { Ok(None.into()) } #[allow(unreachable_code)] - /// Submit a solution for the unsigned phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. - /// Moreover, this unsigned solution is only validated when submitted to the pool from the - /// local process. Effectively, this means that only active validators can submit this - /// transaction when authoring a block. - /// - /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will - /// panic if the solution submitted by the validator is invalid, effectively putting their - /// authoring reward at risk. - /// - /// No deposit or reward is associated with this. - /// - /// NOTE: Calling this function will bypass origin filters. + /// Submit a solution for the unsigned phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. + /// Moreover, this unsigned solution is only validated when submitted to the pool from the + /// local process. Effectively, this means that only active validators can submit this + /// transaction when authoring a block. + /// + /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will + /// panic if the solution submitted by the validator is invalid, effectively putting their + /// authoring reward at risk. + /// + /// No deposit or reward is associated with this. + /// + /// NOTE: Calling this function will bypass origin filters. fn submit_unsigned( - origin: T::Origin, - solution: RawSolution>, - ) -> ::frame_support::dispatch::DispatchResult { + origin: T::Origin, + solution: RawSolution>, + ) -> ::frame_support::dispatch::DispatchResult { let __within_span__ = { use ::tracing::__macro_support::Callsite as _; static CALLSITE: ::tracing::__macro_support::MacroCallsite = { @@ -3329,7 +3434,7 @@ pub mod two_phase { "frame_election_providers::two_phase", ::tracing::Level::TRACE, Some("frame/election-providers/src/two_phase/mod.rs"), - Some(429u32), + Some(464u32), Some("frame_election_providers::two_phase"), ::tracing_core::field::FieldSet::new( &[], @@ -3370,7 +3475,7 @@ pub mod two_phase { } Ok(()) } - } + } /// Dispatchable calls. /// /// Each variant of this enum maps to a dispatchable function from the associated module. @@ -3878,19 +3983,19 @@ pub mod two_phase { } } impl ElectionProvider for Module - where - ExtendedBalance: From>>, - { - const NEEDS_ELECT_DATA: bool = false; + where + ExtendedBalance: From>>, + { + const NEEDS_ELECT_DATA: bool = false; type Error = Error; fn elect( - _to_elect: usize, - _targets: Vec, - _voters: Vec<(T::AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>, - { + _to_elect: usize, + _targets: Vec, + _voters: Vec<(T::AccountId, VoteWeight, Vec)>, + ) -> Result, Self::Error> + where + ExtendedBalance: From<

::Inner>, + { Self::queued_solution() .map_or_else( || { @@ -3912,7 +4017,7 @@ pub mod two_phase { if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { ::log::__private_api_log( ::core::fmt::Arguments::new_v1( - &["Finalized election round with compute ", "."], + &["\u{1f3e6} Finalized election round with compute ", "."], &match (&compute,) { (arg0,) => [::core::fmt::ArgumentV1::new( arg0, @@ -3925,7 +4030,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 689u32, + 727u32, ), ); } @@ -3939,7 +4044,7 @@ pub mod two_phase { if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { ::log::__private_api_log( ::core::fmt::Arguments::new_v1( - &["Failed to finalize election round. Error = "], + &["\u{1f3e6} Failed to finalize election round. Error = "], &match (&err,) { (arg0,) => [::core::fmt::ArgumentV1::new( arg0, @@ -3952,7 +4057,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 694u32, + 732u32, ), ); } @@ -3966,12 +4071,12 @@ pub mod two_phase { _ => false, } } - } + } } const LOG_TARGET: &'static str = "election-provider"; #[doc(hidden)] pub use sp_npos_elections::VoteWeight; #[doc(hidden)] -use sp_runtime::traits::UniqueSaturatedInto; +pub use sp_runtime::traits::UniqueSaturatedInto; #[doc(hidden)] pub use sp_std::convert::TryInto; diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index e69de29bb2d1d..685ec982129c1 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -0,0 +1,133 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Two phase election pallet benchmarking. + +use super::*; +use crate::two_phase::{Module as TwoPhase, *}; + +pub use frame_benchmarking::{account, benchmarks, whitelist_account, whitelisted_caller}; +use rand::{seq::SliceRandom, thread_rng}; +use sp_npos_elections::{ExtendedBalance, VoteWeight}; +use frame_support::assert_ok; +use sp_runtime::InnerOf; + +const SEED: u32 = 0; + +// TODO: the entire snapshot can probably live in a single place.. + +/// Generate mock on-chain snapshots. +/// +/// This emulates the start of signed phase, where snapshots are received from an upstream crate. +fn mock_snapshot( + witness: WitnessData, +) -> ( + Vec, + Vec<(T::AccountId, VoteWeight, Vec)>, +) +where + ExtendedBalance: From>>, +{ + // first generates random targets. + let targets: Vec = (0..witness.targets) + .map(|i| account("Targets", i, SEED)) + .collect(); + + // generate targets, each voting for a random subset of the targets.\ + let mut voters = (0..(witness.voters - witness.targets)) + .map(|i| { + let mut rng = thread_rng(); + let stake = 1000_000u64; + let to_vote = rand::random::() % >::LIMIT; + let votes = targets.as_slice().choose_multiple(&mut rng, to_vote).cloned().collect::>(); + let voter = account::("Voter", i, SEED); + + (voter, stake, votes) + }) + .collect::>(); + + // targets should have self vote. This is very helpful, because it ensure that by doing the trim, + // we almost never reduce the number of unique targets. For this cause, we also make the self + // vote heavier, to ensure that trimming only removes a voter here and there, not a target. + voters.extend(targets.iter().map(|t| (t.clone(), 1000_000_0u64, vec![t.clone()]))); + + (targets, voters) +} + +fn put_mock_snapshot(witness: WitnessData, desired_targets: u32) +where + ExtendedBalance: From>>, +{ + let (targets, voters) = mock_snapshot::(witness); + >::put(targets); + >::put(voters); + DesiredTargets::put(desired_targets); +} + +benchmarks! { + where_clause { where ExtendedBalance: From>>, } + _{} + submit_signed {}: {} verify {} + submit_unsigned {}: {} verify {} + open_signed_phase {}: {} verify {} + close_signed_phase {}: {} verify {} + + // This is checking a valid solution. The worse case is indeed a valid solution. + feasibility_check { + // number of votes in snapshot. + let v in 2000 .. 3000; + // number of targets in snapshot. + let t in 500 .. 800; + // number of assignments, i.e. compact.len(). This means the active nominators, thus must be + // a subset of `v` component. + let a in 200 .. 800; + // number of desired targets. Must be a subset of `t` component. + let d in 200 .. 400; + + println!("running v {}, t {}, a {}, d {}", v, t, a, d); + + let witness = WitnessData { voters: v, targets: t }; + put_mock_snapshot::(witness, d); + + let voters = >::snapshot_voters().unwrap(); + let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); + + let RawSolution { compact, score } = >::mine_solution(0).unwrap(); + let compact = >::trim_compact(a, compact, voter_index).unwrap(); + + assert_eq!(compact.len() as u32, a); + assert_eq!(compact.unique_targets().len() as u32, d); + + let raw_solution = RawSolution { compact, score }; + let compute = ElectionCompute::Unsigned; + }: { + assert_ok!(>::feasibility_check(raw_solution, compute)); + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::two_phase::mock::*; + + #[test] + fn test_benchmarks() { + ExtBuilder::default().build_and_execute(|| { + assert_ok!(test_benchmark_feasibility_check::()); + }) + } +} diff --git a/frame/election-providers/src/two_phase/macros.rs b/frame/election-providers/src/two_phase/macros.rs index e6daafcb99e60..83146a7263075 100644 --- a/frame/election-providers/src/two_phase/macros.rs +++ b/frame/election-providers/src/two_phase/macros.rs @@ -22,7 +22,7 @@ macro_rules! log { ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { frame_support::debug::$level!( target: crate::LOG_TARGET, - $patter $(, $values)* + concat!("🏦 ", $patter) $(, $values)* ) }; } @@ -30,12 +30,12 @@ macro_rules! log { #[macro_export] macro_rules! voter_index_fn { ($voters:ident, $acc:ty, $t:ident) => { - |who: &$acc| -> Option<$crate::two_phase::CompactVoterIndexOf<$t>> { - $voters - .iter() - .position(|(x, _, _)| x == who) - .and_then(|i| >>::try_into(i).ok()) - } + |who: &$acc| -> Option<$crate::two_phase::CompactVoterIndexOf<$t>> { + $voters + .iter() + .position(|(x, _, _)| x == who) + .and_then(|i| >>::try_into(i).ok()) + } }; } @@ -55,14 +55,14 @@ macro_rules! target_index_fn { macro_rules! voter_at_fn { ($snap:ident, $acc:ty, $t:ident) => { |i: $crate::two_phase::CompactVoterIndexOf<$t>| -> Option<$acc> { - <$crate::two_phase::CompactVoterIndexOf<$t> as $crate::TryInto>::try_into(i) - .ok() - .and_then(|i| $snap - .get(i) - .map(|(x, _, _)| x) - .cloned() - ) - } + <$crate::two_phase::CompactVoterIndexOf<$t> as $crate::TryInto>::try_into(i) + .ok() + .and_then(|i| $snap + .get(i) + .map(|(x, _, _)| x) + .cloned() + ) + } }; } @@ -70,13 +70,13 @@ macro_rules! voter_at_fn { macro_rules! target_at_fn { ($snap:ident, $acc:ty, $t:ident) => { |i: $crate::two_phase::CompactTargetIndexOf<$t>| -> Option<$acc> { - <$crate::two_phase::CompactTargetIndexOf<$t> as $crate::TryInto>::try_into(i) - .ok() - .and_then(|i| $snap - .get(i) - .cloned() - ) - }; + <$crate::two_phase::CompactTargetIndexOf<$t> as $crate::TryInto>::try_into(i) + .ok() + .and_then(|i| $snap + .get(i) + .cloned() + ) + }; }; } @@ -85,11 +85,11 @@ macro_rules! target_at_fn { macro_rules! stake_of_fn { ($voters:ident, $acc:ty) => { |who: &$acc| -> $crate::VoteWeight { - $voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - } + $voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + } }; } diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index cc6d021f788d2..614d9903796f8 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -10,14 +10,15 @@ use sp_core::{ }; use sp_election_providers::ElectionDataProvider; use sp_npos_elections::{ - seq_phragmen, to_without_backing, CompactSolution, ElectionResult, EvaluateSupport, + assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, to_without_backing, + CompactSolution, ElectionResult, EvaluateSupport, }; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, PerU16, }; -use std::{cell::RefCell}; +use std::{cell::RefCell, sync::Arc}; pub use frame_support::{assert_noop, assert_ok}; @@ -70,10 +71,8 @@ pub fn raw_solution() -> RawSolution> { let winners = to_without_backing(winners); let score = { - let staked = sp_npos_elections::assignment_ratio_to_staked(assignments.clone(), &stake_of); - sp_npos_elections::to_supports(&winners, &staked) - .unwrap() - .evaluate() + let staked = assignment_ratio_to_staked_normalized(assignments.clone(), &stake_of).unwrap(); + to_supports(&winners, &staked).unwrap().evaluate() }; let compact = >::from_assignment(assignments, &voter_index, &target_index).unwrap(); @@ -211,12 +210,21 @@ impl crate::two_phase::Trait for Runtime { type SlashHandler = (); type RewardHandler = (); type UnsignedMaxIterations = MaxUnsignedIterations; - type UnsignedCall = (); type UnsignedPriority = UnsignedPriority; type ElectionDataProvider = StakingMock; type WeightInfo = (); } +impl frame_system::offchain::SendTransactionTypes for Runtime +where + OuterCall: From, +{ + type OverarchingCall = OuterCall; + type Extrinsic = Extrinsic; +} + +pub type Extrinsic = sp_runtime::testing::TestXt; + pub struct ExtBuilder {} impl Default for ExtBuilder { @@ -268,6 +276,7 @@ impl ExtBuilder { self } pub fn build(self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::default() .build_storage::() .unwrap(); @@ -284,10 +293,13 @@ impl ExtBuilder { sp_io::TestExternalities::from(storage) } - pub fn build_offchainify(self, iters: u32) -> sp_io::TestExternalities { + pub fn build_offchainify( + self, + iters: u32, + ) -> (sp_io::TestExternalities, Arc>) { let mut ext = self.build(); let (offchain, offchain_state) = TestOffchainExt::new(); - let (pool, _pool_state) = TestTransactionPoolExt::new(); + let (pool, pool_state) = TestTransactionPoolExt::new(); let mut seed = [0_u8; 32]; seed[0..4].copy_from_slice(&iters.to_le_bytes()); @@ -296,7 +308,7 @@ impl ExtBuilder { ext.register_extension(OffchainExt::new(offchain)); ext.register_extension(TransactionPoolExt::new(pool)); - ext + (ext, pool_state) } pub fn build_and_execute(self, test: impl FnOnce() -> ()) { self.build().execute_with(test) diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 97d788558d69b..642fa5ce4fd5d 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -79,6 +79,8 @@ //! +-------------------------------+ //! ``` //! +//! TODO: what if length of some phase is zero? +//! //! Note that both of the bottom solutions end up being discarded and get their deposit back, //! despite one of them being invalid. //! @@ -108,12 +110,12 @@ use crate::onchain::OnChainSequentialPhragmen; use codec::{Decode, Encode, HasCompact}; use frame_support::{ decl_event, decl_module, decl_storage, - dispatch::{DispatchResultWithPostInfo, Dispatchable}, + dispatch::DispatchResultWithPostInfo, ensure, traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, weights::Weight, }; -use frame_system::{ensure_none, ensure_signed}; +use frame_system::{ensure_none, ensure_signed, offchain::SendTransactionTypes}; use sp_election_providers::{ElectionDataProvider, ElectionProvider}; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, is_score_better, Assignment, CompactSolution, @@ -125,6 +127,8 @@ use sp_runtime::{ }; use sp_std::prelude::*; +#[cfg(any(feature = "runtime-benchmarks", test))] +pub mod benchmarking; #[cfg(test)] mod mock; #[macro_use] @@ -257,6 +261,23 @@ pub struct ReadySolution { compute: ElectionCompute, } +/// Witness data about the size of the election. +/// +/// This is needed for proper weight calculation. +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, Default)] +pub struct WitnessData { + /// Number of all voters. + /// + /// This must match the on-chain snapshot. + #[codec(compact)] + voters: u32, + /// Number of all targets. + /// + /// This must match the on-chain snapshot. + #[codec(compact)] + targets: u32, +} + /// The crate errors. Note that this is different from the [`PalletError`]. #[derive(RuntimeDebug, Eq, PartialEq)] pub enum Error { @@ -268,6 +289,10 @@ pub enum Error { NposElections(sp_npos_elections::Error), /// Snapshot data was unavailable unexpectedly. SnapshotUnAvailable, + /// Submitting a transaction to the pool failed. + /// + /// This can only happen in the unsigned phase. + PoolSubmissionFailed, } impl From for Error { @@ -328,7 +353,10 @@ impl WeightInfo for () { } } -pub trait Trait: frame_system::Trait { +pub trait Trait: frame_system::Trait + SendTransactionTypes> +where + ExtendedBalance: From>>, +{ /// Event type. type Event: From> + Into<::Event>; @@ -354,8 +382,6 @@ pub trait Trait: frame_system::Trait { type SolutionImprovementThreshold: Get; type UnsignedMaxIterations: Get; - // TODO: - type UnsignedCall: Dispatchable + Clone; type UnsignedPriority: Get; /// Handler for the slashed deposits. @@ -372,6 +398,13 @@ pub trait Trait: frame_system::Trait { decl_storage! { trait Store for Module as TwoPhaseElectionProvider where ExtendedBalance: From>> { + /// Internal counter ofr the number of rounds. + /// + /// This is useful for de-duplication of transactions submitted to the pool, and general + /// diagnostics of the module. + /// + /// This is merely incremented once per every time that signed phase starts. + pub Round get(fn round): u32 = 0; /// Current phase. pub CurrentPhase get(fn current_phase): Phase = Phase::Off; @@ -450,8 +483,9 @@ decl_module! { Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { // check only for the signed phase. >::put(Phase::Signed); + Round::mutate(|r| *r +=1); Self::start_signed_phase(); - log!(info, "Starting signed phase at #{}", now); + log!(info, "Starting signed phase at #{} , round {}", now, Self::round()); }, Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { // check the unsigned phase. @@ -570,6 +604,8 @@ where let RawSolution { compact, score } = solution; // winners are not directly encoded in the solution. + // TODO: dupe winner + // TODO: dupe in compact. let winners = compact.unique_targets(); // Ensure that we have received enough winners. @@ -632,6 +668,7 @@ where // Finally, check that the claimed score was indeed correct. let known_score = supports.evaluate(); + dbg!(known_score, score); ensure!(known_score == score, FeasibilityError::InvalidScore); // let supports = supports.flatten(); @@ -718,18 +755,22 @@ mod tests { assert_eq!(System::block_number(), 0); assert_eq!(TwoPhase::current_phase(), Phase::Off); + assert_eq!(TwoPhase::round(), 0); roll_to(4); assert_eq!(TwoPhase::current_phase(), Phase::Off); assert!(TwoPhase::snapshot_voters().is_none()); + assert_eq!(TwoPhase::round(), 0); roll_to(5); assert_eq!(TwoPhase::current_phase(), Phase::Signed); assert!(TwoPhase::snapshot_voters().is_some()); + assert_eq!(TwoPhase::round(), 1); roll_to(14); assert_eq!(TwoPhase::current_phase(), Phase::Signed); assert!(TwoPhase::snapshot_voters().is_some()); + assert_eq!(TwoPhase::round(), 1); roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); @@ -752,6 +793,7 @@ mod tests { .unwrap(); assert_eq!(TwoPhase::current_phase(), Phase::Off); assert!(TwoPhase::snapshot_voters().is_none()); + assert_eq!(TwoPhase::round(), 1); }) } diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index e27f4db5360bb..31090121db1a0 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -19,8 +19,10 @@ use crate::two_phase::*; use frame_support::{dispatch::DispatchResult, unsigned::ValidateUnsigned}; +use frame_system::offchain::SubmitTransaction; use sp_npos_elections::{seq_phragmen, CompactSolution, ElectionResult}; use sp_runtime::{ + offchain::storage::StorageValueRef, traits::TrailingZeroInput, transaction_validity::{ InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, @@ -30,23 +32,6 @@ use sp_runtime::{ }; use sp_std::cmp::Ordering; -/// Witness data about the size of the election. -/// -/// This is needed for proper weight calculation. -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, Default)] -pub struct WitnessData { - /// Number of all voters. - /// - /// This must match the on-chain snapshot. - #[codec(compact)] - voters: u32, - /// Number of all targets. - /// - /// This must match the on-chain snapshot. - #[codec(compact)] - target: u32, -} - /// Storage key used to store the persistent offchain worker status. pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; /// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice @@ -272,7 +257,7 @@ where pub(crate) fn set_check_offchain_execution_status( now: T::BlockNumber, ) -> Result<(), &'static str> { - let storage = sp_runtime::offchain::storage::StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); + let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); let mutate_stat = @@ -306,9 +291,12 @@ where /// Mine a new solution, and submit it back to the chian as an unsigned transaction. pub(crate) fn mine_and_submit() -> Result<(), Error> { let balancing = Self::get_balancing_iters(); - Self::mine_solution(balancing).map(|raw_solution| { + Self::mine_solution(balancing).and_then(|raw_solution| { // submit the raw solution to the pool. - () + let call = Call::submit_unsigned(raw_solution).into(); + + SubmitTransaction::>::submit_unsigned_transaction(call) + .map_err(|_| Error::PoolSubmissionFailed) }) } @@ -528,6 +516,8 @@ where #[cfg(test)] mod tests { use super::{mock::*, *}; + use frame_support::traits::OffchainWorker; + use sp_runtime::PerU16; #[test] fn validate_unsigned_retracts_wrong_phase() { @@ -686,6 +676,11 @@ mod tests { }) } + #[test] + fn ocw_will_only_submit_if_feasible() { + // the ocw should only submit a solution if it is sure that it is valid. + } + #[test] fn can_only_submit_threshold_better() { ExtBuilder::default() @@ -694,7 +689,7 @@ mod tests { .add_voter(8, 5, vec![10]) .solution_improvement_threshold(Perbill::from_percent(50)) .build_and_execute(|| { - use sp_npos_elections::{Assignment, ElectionResult}; + roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); assert_eq!(TwoPhase::desired_targets(), 1); @@ -764,4 +759,77 @@ mod tests { assert_ok!(TwoPhase::submit_unsigned(Origin::none(), solution)); }) } + + #[test] + fn ocw_check_prevent_duplicate() { + let (mut ext, _) = ExtBuilder::default().build_offchainify(0); + ext.execute_with(|| { + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + + // first execution -- okay. + assert!(TwoPhase::set_check_offchain_execution_status(15).is_ok()); + + // next block: rejected. + assert!(TwoPhase::set_check_offchain_execution_status(16).is_err()); + + // allowed after `OFFCHAIN_REPEAT` + assert!( + TwoPhase::set_check_offchain_execution_status((16 + OFFCHAIN_REPEAT).into()) + .is_ok() + ); + + // a fork like situation: re-execute last 3. + assert!(TwoPhase::set_check_offchain_execution_status( + (16 + OFFCHAIN_REPEAT - 3).into() + ) + .is_err()); + assert!(TwoPhase::set_check_offchain_execution_status( + (16 + OFFCHAIN_REPEAT - 2).into() + ) + .is_err()); + assert!(TwoPhase::set_check_offchain_execution_status( + (16 + OFFCHAIN_REPEAT - 1).into() + ) + .is_err()); + }) + } + + #[test] + fn ocw_only_runs_when_signed_open_now() { + let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); + ext.execute_with(|| { + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + // we must clear the offchain storage to ensure the offchain execution check doesn't get + // in the way. + let mut storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); + + TwoPhase::offchain_worker(14); + assert!(pool.read().transactions.len().is_zero()); + storage.clear(); + + TwoPhase::offchain_worker(16); + assert!(pool.read().transactions.len().is_zero()); + storage.clear(); + + TwoPhase::offchain_worker(15); + assert!(!pool.read().transactions.len().is_zero()); + }) + } + + #[test] + fn ocw_can_submit_to_pool() { + let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); + ext.execute_with(|| { + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + TwoPhase::offchain_worker(15); + + let encoded = pool.read().transactions[0].clone(); + let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); + let call = extrinsic.call; + matches!(call, OuterCall::TwoPhase(Call::submit_unsigned(_))); + }) + } } diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 0071d2a56bcc5..34b7a52aa8d56 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -137,8 +137,8 @@ impl __OrInvalidIndex for Option { /// See [`compact`] for more info. pub trait CompactSolution: Sized { const LIMIT: usize; - type Voter: UniqueSaturatedInto + TryInto + TryFrom; - type Target: UniqueSaturatedInto + TryInto + TryFrom; + type Voter: UniqueSaturatedInto + TryInto + TryFrom + Debug; + type Target: UniqueSaturatedInto + TryInto + TryFrom + Debug; type VoteWeight: PerThing128; fn from_assignment( From 525f6e0c2e5ff69796df16ecb34e2888abdba0a7 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 16 Oct 2020 19:42:23 +0200 Subject: [PATCH 14/62] Comment. --- frame/election-providers/src/two_phase/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 642fa5ce4fd5d..742fbf13394da 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -489,6 +489,9 @@ decl_module! { }, Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { // check the unsigned phase. + // TODO: this is probably very bad as it is.. we should only assume we don't + // want OCW solutions if the solutions is checked to be PJR as well. Probably a + // good middle ground for now is to always let the unsigned phase be open. let found_solution = Self::finalize_signed_phase(); >::put(Phase::Unsigned((!found_solution, now))); log!(info, "Starting unsigned phase at #{}", now); From 30263166aacae960b6e80b9d9b6cfac52b5b7298 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 20 Oct 2020 11:16:53 +0200 Subject: [PATCH 15/62] Checkpoint. --- frame/election-providers/exapnded.test.rs | 15070 ++++++++++------ frame/election-providers/expanded.rs | 2156 +-- .../src/two_phase/benchmarking.rs | 105 +- .../election-providers/src/two_phase/mock.rs | 3 +- primitives/npos-elections/src/lib.rs | 6 +- 5 files changed, 10740 insertions(+), 6600 deletions(-) diff --git a/frame/election-providers/exapnded.test.rs b/frame/election-providers/exapnded.test.rs index 34f10a2c6bf0b..0640a9bc62ff9 100644 --- a/frame/election-providers/exapnded.test.rs +++ b/frame/election-providers/exapnded.test.rs @@ -1,26 +1,97 @@ #![feature(prelude_import)] +//! Various implementation for `ElectionProvider`. +//! +//! Two main election providers are implemented in this crate. +//! +//! 1. [`onchain`]: A `struct` that perform the election onchain (i.e. in the fly). This type is +//! likely to be expensive for most chains and damage the block time. Only use when you are sure +//! that the inputs are bounded and small enough. +//! 2. [`two_phase`]: An individual `pallet` that performs the election in two phases, signed and +//! unsigned. Needless to say, the pallet needs to be included in the final runtime. #[prelude_import] use std::prelude::v1::*; #[macro_use] extern crate std; -use sp_std::prelude::*; +/// The onchain module. pub mod onchain { - use crate::{ElectionProvider, Error}; use sp_arithmetic::PerThing; + use sp_election_providers::ElectionProvider; use sp_npos_elections::{ - ElectionResult, ExtendedBalance, FlattenSupportMap, IdentifierT, Supports, VoteWeight, + ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Supports, VoteWeight, }; + use sp_runtime::RuntimeDebug; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; + /// Errors of the on-chain election. + pub enum Error { + /// An internal error in the NPoS elections crate. + NposElections(sp_npos_elections::Error), + } + impl core::fmt::Debug for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::NposElections(ref a0) => { + fmt.debug_tuple("Error::NposElections").field(a0).finish() + } + _ => Ok(()), + } + } + } + impl ::core::marker::StructuralEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } + impl ::core::marker::StructuralPartialEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + match (&*self, &*other) { + (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + } + } + #[inline] + fn ne(&self, other: &Error) -> bool { + match (&*self, &*other) { + (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + } + } + } + impl From for Error { + fn from(e: sp_npos_elections::Error) -> Self { + Error::NposElections(e) + } + } + /// A simple on-chian implementation of the election provider trait. + /// + /// This will accept voting data on the fly and produce the results immediately. + /// + /// ### Warning + /// + /// This can be very expensive to run frequently on-chain. Use with care. pub struct OnChainSequentialPhragmen; impl ElectionProvider for OnChainSequentialPhragmen { - fn elect( + type Error = Error; + const NEEDS_ELECT_DATA: bool = true; + fn elect( to_elect: usize, targets: Vec, voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, - P: sp_std::ops::Mul, { let mut stake_map: BTreeMap = BTreeMap::new(); voters.iter().for_each(|(v, s, _)| { @@ -40,7 +111,7 @@ pub mod onchain { &stake_of, )?; let winners = sp_npos_elections::to_without_backing(winners); - sp_npos_elections::build_support_map(&winners, &staked).map(|s| s.flatten()) + sp_npos_elections::to_supports(&winners, &staked) }) .map_err(From::from) } @@ -49,4727 +120,7365 @@ pub mod onchain { } } } +/// The two-phase module. pub mod two_phase { - use crate::{ - onchain::OnChainSequentialPhragmen, ElectionDataProvider, ElectionProvider, Error, - }; + //! # Two phase election provider pallet. + //! + //! As the name suggests, this election provider has two distinct phases (see [`Phase`]), signed and + //! unsigned. + //! + //! ## Phases + //! + //! The timeline of pallet is as follows. At each block, + //! [`ElectionDataProvider::next_election_prediction`] is used to estimate the time remaining to the + //! next call to `elect`. Based on this, a phase is chosen. The timeline is as follows. + //! + //! ```ignore + //! elect() + //! + <--T::SignedPhase--> + <--T::UnsignedPhase--> + + //! +-------------------------------------------------------------------+ + //! Phase::Off + Phase::Signed + Phase::Unsigned + + //! + //! Note that the unsigned phase starts `T::UnsignedPhase` blocks before the + //! `next_election_prediction`, but only ends when a call to `ElectionProvider::elect` happens. + //! + //! ``` + //! ### Signed Phase + //! + //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A + //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution + //! on-chain for a number of blocks. A maximum of [`Trait::MaxSignedSubmissions`] solutions are + //! stored. The queue is always sorted based on score (worse -> best). + //! + //! Upon arrival of a new solution: + //! + //! 1. If the queue is not full, it is stored. + //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the + //! worse solution is discarded (TODO: what to do with the bond?) and the new solution is stored + //! in the correct index. + //! 3. If the queue is full and the solution is not an improvement compared to any of the queued + //! ones, it is instantly rejected and no additional bond is reserved. + //! + //! A signed solution cannot be reversed, taken back, updated, or retracted. In other words, the + //! origin can not bail out in any way. + //! + //! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed + //! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure + //! the score claimed by this score was correct, among other checks. At each step, if the current + //! best solution is passes the feasibility check, it is considered to be the best one. The sender + //! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without + //! being checked. + //! + //! The following example covers all of the cases at the end of the signed phase: + //! + //! ```ignore + //! Queue + //! +-------------------------------+ + //! |Solution(score=20, valid=false)| +--> Slashed + //! +-------------------------------+ + //! |Solution(score=15, valid=true )| +--> Rewarded + //! +-------------------------------+ + //! |Solution(score=10, valid=true )| +--> Discarded + //! +-------------------------------+ + //! |Solution(score=05, valid=false)| +--> Discarded + //! +-------------------------------+ + //! | None | + //! +-------------------------------+ + //! ``` + //! + //! TODO: what if length of some phase is zero? + //! + //! Note that both of the bottom solutions end up being discarded and get their deposit back, + //! despite one of them being invalid. + //! + //! ## Unsigned Phase + //! + //! If signed phase ends with a good solution, then the unsigned phase will be `active` + //! ([`Phase::Unsigned(true)`]), else the unsigned phase will be `passive`. + //! + //! TODO + //! + //! ### Fallback + //! + //! If we reach the end of both phases (i.e. call to `ElectionProvider::elect` happens) and no good + //! solution is queued, then we fallback to an on-chain election. The on-chain election is slow, and + //! contains to balancing or reduction post-processing. + //! + //! ## Correct Submission + //! + //! TODO + //! + //! ## Accuracy + //! + //! TODO + //! + use crate::onchain::OnChainSequentialPhragmen; use codec::{Decode, Encode, HasCompact}; use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, + decl_event, decl_module, decl_storage, dispatch::DispatchResultWithPostInfo, ensure, traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, weights::Weight, }; - use frame_system::{ensure_none, ensure_signed}; + use frame_system::{ensure_none, ensure_signed, offchain::SendTransactionTypes}; + use sp_election_providers::{ElectionDataProvider, ElectionProvider}; use sp_npos_elections::{ - evaluate_support, generate_solution_type, is_score_better, Assignment, ElectionScore, - ExtendedBalance, FlattenSupportMap, Supports, VoteWeight, + assignment_ratio_to_staked_normalized, is_score_better, Assignment, CompactSolution, + ElectionScore, EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, }; - use sp_runtime::{traits::Zero, PerThing, PerU16, Perbill, RuntimeDebug}; - use sp_std::{mem::size_of, prelude::*}; - #[cfg(test)] - mod mock { + use sp_runtime::{ + traits::Zero, transaction_validity::TransactionPriority, InnerOf, PerThing, Perbill, + RuntimeDebug, + }; + use sp_std::prelude::*; + #[cfg(any(feature = "runtime-benchmarks", test))] + pub mod benchmarking { + //! Two phase election pallet benchmarking. use super::*; - pub use frame_support::{assert_noop, assert_ok}; - use frame_support::{parameter_types, traits::OnInitialize, weights::Weight}; - use sp_core::H256; - use sp_npos_elections::Supports; - use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - }; - use std::cell::RefCell; - pub struct Runtime; - impl ::core::marker::StructuralEq for Runtime {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Runtime { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - {} - } - } - impl ::core::marker::StructuralPartialEq for Runtime {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Runtime { - #[inline] - fn eq(&self, other: &Runtime) -> bool { - match *other { - Runtime => match *self { - Runtime => true, - }, - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Runtime { - #[inline] - fn clone(&self) -> Runtime { - match *self { - Runtime => Runtime, - } - } - } - pub(crate) type Balances = pallet_balances::Module; - pub(crate) type System = frame_system::Module; - pub(crate) type TwoPhase = super::Module; - pub(crate) type Balance = u64; - pub(crate) type AccountId = u64; - /// To from `now` to block `n`. - pub fn roll_to(n: u64) { - let now = System::block_number(); - for i in now + 1..=n { - System::set_block_number(i); - TwoPhase::on_initialize(i); - } - } - /// Get the free and reserved balance of some account. - pub fn balances(who: &AccountId) -> (Balance, Balance) { - (Balances::free_balance(who), Balances::reserved_balance(who)) - } - /// Spit out a verifiable raw solution. + use crate::two_phase::{Module as TwoPhase, *}; + pub use frame_benchmarking::{account, benchmarks, whitelist_account, whitelisted_caller}; + use frame_support::assert_ok; + use rand::{seq::SliceRandom, thread_rng}; + use sp_npos_elections::{ExtendedBalance, VoteWeight}; + use sp_runtime::InnerOf; + const SEED: u32 = 0; + /// Generate mock on-chain snapshots. /// - /// This is a good example of what an offchain miner would do. - pub fn raw_solution() -> RawSolution { - let voters = TwoPhase::snapshot_voters().unwrap(); - let targets = TwoPhase::snapshot_targets().unwrap(); - let desired = TwoPhase::desired_targets() as usize; - let voter_index = |who: &AccountId| -> Option { - voters.iter().position(|(x, _, _)| x == who).and_then(|i| { - >::try_into(i).ok() - }) - }; - let target_index = |who: &AccountId| -> Option { - targets.iter().position(|x| x == who).and_then(|i| { - >::try_into(i).ok() + /// This emulates the start of signed phase, where snapshots are received from an upstream crate. + fn mock_snapshot( + witness: WitnessData, + ) -> ( + Vec, + Vec<(T::AccountId, VoteWeight, Vec)>, + ) + where + ExtendedBalance: From>>, + { + let targets: Vec = (0..witness.targets) + .map(|i| account("Targets", i, SEED)) + .collect(); + let mut voters = (0..(witness.voters - witness.targets)) + .map(|i| { + let mut rng = thread_rng(); + let stake = 1000_000u64; + let to_vote = rand::random::() % >::LIMIT + 1; + let votes = targets + .as_slice() + .choose_multiple(&mut rng, to_vote) + .cloned() + .collect::>(); + let voter = account::("Voter", i, SEED); + (voter, stake, votes) }) - }; - let stake_of = |who: &AccountId| -> crate::VoteWeight { - voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - }; - use sp_npos_elections::{seq_phragmen, to_without_backing, ElectionResult}; - let ElectionResult { - winners, - assignments, - } = seq_phragmen::<_, OffchainAccuracy>(desired, targets.clone(), voters.clone(), None) - .unwrap(); - let winners = to_without_backing(winners); - let score = { - let staked = - sp_npos_elections::assignment_ratio_to_staked(assignments.clone(), &stake_of); - let support = sp_npos_elections::build_support_map(&winners, &staked).unwrap(); - sp_npos_elections::evaluate_support(&support) - }; - let compact = - CompactAssignments::from_assignment(assignments, &voter_index, &target_index) - .unwrap(); - let winners = winners - .into_iter() - .map(|w| target_index(&w).unwrap()) .collect::>(); - RawSolution { - winners, - compact, - score, - } + voters.extend( + targets + .iter() + .map(|t| (t.clone(), 1000_000_0u64, <[_]>::into_vec(box [t.clone()]))), + ); + (targets, voters) } - pub struct Origin { - caller: OriginCaller, - filter: ::frame_support::sp_std::rc::Rc< - Box::Call) -> bool>, - >, + fn put_mock_snapshot(witness: WitnessData, desired_targets: u32) + where + ExtendedBalance: From>>, + { + let (targets, voters) = mock_snapshot::(witness); + >::put(targets); + >::put(voters); + DesiredTargets::put(desired_targets); } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Origin { - #[inline] - fn clone(&self) -> Origin { - match *self { - Origin { - caller: ref __self_0_0, - filter: ref __self_0_1, - } => Origin { - caller: ::core::clone::Clone::clone(&(*__self_0_0)), - filter: ::core::clone::Clone::clone(&(*__self_0_1)), - }, - } + #[allow(non_camel_case_types)] + struct submit_signed; + #[allow(unused_variables)] + impl ::frame_benchmarking::BenchmarkingSetup for submit_signed + where + ExtendedBalance: From>>, + { + fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { + ::alloc::vec::Vec::new() } - } - #[cfg(feature = "std")] - impl ::frame_support::sp_std::fmt::Debug for Origin { - fn fmt( + fn instance( &self, - fmt: &mut ::frame_support::sp_std::fmt::Formatter, - ) -> ::frame_support::sp_std::result::Result<(), ::frame_support::sp_std::fmt::Error> { - fmt.debug_struct("Origin") - .field("caller", &self.caller) - .field("filter", &"[function ptr]") - .finish() + components: &[(::frame_benchmarking::BenchmarkParameter, u32)], + verify: bool, + ) -> Result Result<(), &'static str>>, &'static str> { + Ok(Box::new(move || -> Result<(), &'static str> { + {}; + if verify { + {}; + } + Ok(()) + })) } } - impl ::frame_support::traits::OriginTrait for Origin { - type Call = ::Call; - type PalletsOrigin = OriginCaller; - type AccountId = ::AccountId; - fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static) { - let f = self.filter.clone(); - self.filter = ::frame_support::sp_std::rc::Rc::new(Box::new(move |call| { - f(call) && filter(call) - })); - } - fn reset_filter(&mut self) { - let filter = < < Runtime as frame_system :: Trait > :: BaseCallFilter as :: frame_support :: traits :: Filter < < Runtime as frame_system :: Trait > :: Call > > :: filter ; - self.filter = ::frame_support::sp_std::rc::Rc::new(Box::new(filter)); - } - fn set_caller_from(&mut self, other: impl Into) { - self.caller = other.into().caller - } - fn filter_call(&self, call: &Self::Call) -> bool { - (self.filter)(call) - } - fn caller(&self) -> &Self::PalletsOrigin { - &self.caller - } - /// Create with system none origin and `frame-system::Trait::BaseCallFilter`. - fn none() -> Self { - frame_system::RawOrigin::None.into() + fn test_benchmark_submit_signed() -> Result<(), &'static str> + where + T: frame_system::Trait, + ExtendedBalance: From>>, + { + let selected_benchmark = SelectedBenchmark::submit_signed; + let components = + >::components( + &selected_benchmark, + ); + let execute_benchmark = | c : Vec < ( :: frame_benchmarking :: BenchmarkParameter , u32 ) > | -> Result < ( ) , & 'static str > { let closure_to_verify = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T , _ > > :: instance ( & selected_benchmark , & c , true ) ? ; if :: frame_benchmarking :: Zero :: is_zero ( & frame_system :: Module :: < T > :: block_number ( ) ) { frame_system :: Module :: < T > :: set_block_number ( 1 . into ( ) ) ; } closure_to_verify ( ) ? ; :: frame_benchmarking :: benchmarking :: wipe_db ( ) ; Ok ( ( ) ) } ; + if components.is_empty() { + execute_benchmark(Default::default())?; + } else { + for (_, (name, low, high)) in components.iter().enumerate() { + for component_value in <[_]>::into_vec(box [low, high]) { + let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = components + .iter() + .enumerate() + .map(|(_, (n, _, h))| { + if n == name { + (*n, *component_value) + } else { + (*n, *h) + } + }) + .collect(); + execute_benchmark(c)?; + } + } } - /// Create with system root origin and no filter. - fn root() -> Self { - frame_system::RawOrigin::Root.into() + Ok(()) + } + #[allow(non_camel_case_types)] + struct submit_unsigned; + #[allow(unused_variables)] + impl ::frame_benchmarking::BenchmarkingSetup for submit_unsigned + where + ExtendedBalance: From>>, + { + fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { + ::alloc::vec::Vec::new() } - /// Create with system signed origin and `frame-system::Trait::BaseCallFilter`. - fn signed(by: ::AccountId) -> Self { - frame_system::RawOrigin::Signed(by).into() + fn instance( + &self, + components: &[(::frame_benchmarking::BenchmarkParameter, u32)], + verify: bool, + ) -> Result Result<(), &'static str>>, &'static str> { + Ok(Box::new(move || -> Result<(), &'static str> { + {}; + if verify { + {}; + } + Ok(()) + })) } } - #[allow(non_camel_case_types)] - pub enum OriginCaller { - system(frame_system::Origin), - #[allow(dead_code)] - Void(::frame_support::Void), + fn test_benchmark_submit_unsigned() -> Result<(), &'static str> + where + T: frame_system::Trait, + ExtendedBalance: From>>, + { + let selected_benchmark = SelectedBenchmark::submit_unsigned; + let components = + >::components( + &selected_benchmark, + ); + let execute_benchmark = | c : Vec < ( :: frame_benchmarking :: BenchmarkParameter , u32 ) > | -> Result < ( ) , & 'static str > { let closure_to_verify = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T , _ > > :: instance ( & selected_benchmark , & c , true ) ? ; if :: frame_benchmarking :: Zero :: is_zero ( & frame_system :: Module :: < T > :: block_number ( ) ) { frame_system :: Module :: < T > :: set_block_number ( 1 . into ( ) ) ; } closure_to_verify ( ) ? ; :: frame_benchmarking :: benchmarking :: wipe_db ( ) ; Ok ( ( ) ) } ; + if components.is_empty() { + execute_benchmark(Default::default())?; + } else { + for (_, (name, low, high)) in components.iter().enumerate() { + for component_value in <[_]>::into_vec(box [low, high]) { + let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = components + .iter() + .enumerate() + .map(|(_, (n, _, h))| { + if n == name { + (*n, *component_value) + } else { + (*n, *h) + } + }) + .collect(); + execute_benchmark(c)?; + } + } + } + Ok(()) } - #[automatically_derived] - #[allow(unused_qualifications)] #[allow(non_camel_case_types)] - impl ::core::clone::Clone for OriginCaller { - #[inline] - fn clone(&self) -> OriginCaller { - match (&*self,) { - (&OriginCaller::system(ref __self_0),) => { - OriginCaller::system(::core::clone::Clone::clone(&(*__self_0))) + struct open_signed_phase; + #[allow(unused_variables)] + impl ::frame_benchmarking::BenchmarkingSetup for open_signed_phase + where + ExtendedBalance: From>>, + { + fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { + ::alloc::vec::Vec::new() + } + fn instance( + &self, + components: &[(::frame_benchmarking::BenchmarkParameter, u32)], + verify: bool, + ) -> Result Result<(), &'static str>>, &'static str> { + Ok(Box::new(move || -> Result<(), &'static str> { + {}; + if verify { + {}; } - (&OriginCaller::Void(ref __self_0),) => { - OriginCaller::Void(::core::clone::Clone::clone(&(*__self_0))) + Ok(()) + })) + } + } + fn test_benchmark_open_signed_phase() -> Result<(), &'static str> + where + T: frame_system::Trait, + ExtendedBalance: From>>, + { + let selected_benchmark = SelectedBenchmark::open_signed_phase; + let components = + >::components( + &selected_benchmark, + ); + let execute_benchmark = | c : Vec < ( :: frame_benchmarking :: BenchmarkParameter , u32 ) > | -> Result < ( ) , & 'static str > { let closure_to_verify = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T , _ > > :: instance ( & selected_benchmark , & c , true ) ? ; if :: frame_benchmarking :: Zero :: is_zero ( & frame_system :: Module :: < T > :: block_number ( ) ) { frame_system :: Module :: < T > :: set_block_number ( 1 . into ( ) ) ; } closure_to_verify ( ) ? ; :: frame_benchmarking :: benchmarking :: wipe_db ( ) ; Ok ( ( ) ) } ; + if components.is_empty() { + execute_benchmark(Default::default())?; + } else { + for (_, (name, low, high)) in components.iter().enumerate() { + for component_value in <[_]>::into_vec(box [low, high]) { + let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = components + .iter() + .enumerate() + .map(|(_, (n, _, h))| { + if n == name { + (*n, *component_value) + } else { + (*n, *h) + } + }) + .collect(); + execute_benchmark(c)?; } } } + Ok(()) } #[allow(non_camel_case_types)] - impl ::core::marker::StructuralPartialEq for OriginCaller {} - #[automatically_derived] - #[allow(unused_qualifications)] - #[allow(non_camel_case_types)] - impl ::core::cmp::PartialEq for OriginCaller { - #[inline] - fn eq(&self, other: &OriginCaller) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &OriginCaller::system(ref __self_0), - &OriginCaller::system(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - ( - &OriginCaller::Void(ref __self_0), - &OriginCaller::Void(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - _ => unsafe { ::core::intrinsics::unreachable() }, - } - } else { - false + struct close_signed_phase; + #[allow(unused_variables)] + impl ::frame_benchmarking::BenchmarkingSetup for close_signed_phase + where + ExtendedBalance: From>>, + { + fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { + ::alloc::vec::Vec::new() + } + fn instance( + &self, + components: &[(::frame_benchmarking::BenchmarkParameter, u32)], + verify: bool, + ) -> Result Result<(), &'static str>>, &'static str> { + Ok(Box::new(move || -> Result<(), &'static str> { + {}; + if verify { + {}; } - } + Ok(()) + })) } - #[inline] - fn ne(&self, other: &OriginCaller) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &OriginCaller::system(ref __self_0), - &OriginCaller::system(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - ( - &OriginCaller::Void(ref __self_0), - &OriginCaller::Void(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - _ => unsafe { ::core::intrinsics::unreachable() }, - } - } else { - true + } + fn test_benchmark_close_signed_phase() -> Result<(), &'static str> + where + T: frame_system::Trait, + ExtendedBalance: From>>, + { + let selected_benchmark = SelectedBenchmark::close_signed_phase; + let components = + >::components( + &selected_benchmark, + ); + let execute_benchmark = | c : Vec < ( :: frame_benchmarking :: BenchmarkParameter , u32 ) > | -> Result < ( ) , & 'static str > { let closure_to_verify = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T , _ > > :: instance ( & selected_benchmark , & c , true ) ? ; if :: frame_benchmarking :: Zero :: is_zero ( & frame_system :: Module :: < T > :: block_number ( ) ) { frame_system :: Module :: < T > :: set_block_number ( 1 . into ( ) ) ; } closure_to_verify ( ) ? ; :: frame_benchmarking :: benchmarking :: wipe_db ( ) ; Ok ( ( ) ) } ; + if components.is_empty() { + execute_benchmark(Default::default())?; + } else { + for (_, (name, low, high)) in components.iter().enumerate() { + for component_value in <[_]>::into_vec(box [low, high]) { + let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = components + .iter() + .enumerate() + .map(|(_, (n, _, h))| { + if n == name { + (*n, *component_value) + } else { + (*n, *h) + } + }) + .collect(); + execute_benchmark(c)?; } } } + Ok(()) } #[allow(non_camel_case_types)] - impl ::core::marker::StructuralEq for OriginCaller {} - #[automatically_derived] - #[allow(unused_qualifications)] - #[allow(non_camel_case_types)] - impl ::core::cmp::Eq for OriginCaller { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { + struct feasibility_check; + #[allow(unused_variables)] + impl ::frame_benchmarking::BenchmarkingSetup for feasibility_check + where + ExtendedBalance: From>>, + { + fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { + <[_]>::into_vec(box [ + (::frame_benchmarking::BenchmarkParameter::v, 200, 300), + (::frame_benchmarking::BenchmarkParameter::t, 50, 80), + (::frame_benchmarking::BenchmarkParameter::a, 20, 80), + (::frame_benchmarking::BenchmarkParameter::d, 20, 40), + ]) + } + fn instance( + &self, + components: &[(::frame_benchmarking::BenchmarkParameter, u32)], + verify: bool, + ) -> Result Result<(), &'static str>>, &'static str> { + let v = components + .iter() + .find(|&c| c.0 == ::frame_benchmarking::BenchmarkParameter::v) + .ok_or("Could not find component in benchmark preparation.")? + .1; + let t = components + .iter() + .find(|&c| c.0 == ::frame_benchmarking::BenchmarkParameter::t) + .ok_or("Could not find component in benchmark preparation.")? + .1; + let a = components + .iter() + .find(|&c| c.0 == ::frame_benchmarking::BenchmarkParameter::a) + .ok_or("Could not find component in benchmark preparation.")? + .1; + let d = components + .iter() + .find(|&c| c.0 == ::frame_benchmarking::BenchmarkParameter::d) + .ok_or("Could not find component in benchmark preparation.")? + .1; + (); + (); + (); + (); { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq<::frame_support::Void>; + ::std::io::_print(::core::fmt::Arguments::new_v1( + &["running v ", ", t ", ", a ", ", d ", "\n"], + &match (&v, &t, &a, &d) { + (arg0, arg1, arg2, arg3) => [ + ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), + ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Display::fmt), + ::core::fmt::ArgumentV1::new(arg2, ::core::fmt::Display::fmt), + ::core::fmt::ArgumentV1::new(arg3, ::core::fmt::Display::fmt), + ], + }, + )); + }; + let witness = WitnessData { + voters: v, + targets: t, + }; + put_mock_snapshot::(witness, d); + let voters = >::snapshot_voters().unwrap(); + let targets = >::snapshot_targets().unwrap(); + let voter_index = + |who: &T::AccountId| -> Option> { + voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < T > > > :: try_into ( i ) . ok ( ) ) + }; + let voter_at = + |i: crate::two_phase::CompactVoterIndexOf| -> Option { + < crate :: two_phase :: CompactVoterIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | voters . get ( i ) . map ( | ( x , _ , _ ) | x ) . cloned ( ) ) + }; + let target_at = + |i: crate::two_phase::CompactTargetIndexOf| -> Option { + < crate :: two_phase :: CompactTargetIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | targets . get ( i ) . cloned ( ) ) + }; + let stake_of = |who: &T::AccountId| -> crate::VoteWeight { + voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + }; + let RawSolution { compact, score: _ } = >::mine_solution(0).unwrap(); + let compact = >::trim_compact(a, compact, voter_index).unwrap(); + { + match (&(compact.len() as u32), &a) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&(compact.unique_targets().len() as u32), &d) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let winners = compact + .unique_targets() + .iter() + .map(|i| target_at(*i).unwrap()) + .collect::>(); + let score = compact + .clone() + .score(&winners, stake_of, voter_at, target_at) + .unwrap(); + let raw_solution = RawSolution { compact, score }; + let compute = ElectionCompute::Unsigned; + Ok(Box::new(move || -> Result<(), &'static str> { + { + let is = >::feasibility_check(raw_solution, compute); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: + ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: + ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + }; + if verify { + {}; + } + Ok(()) + })) + } + } + fn test_benchmark_feasibility_check() -> Result<(), &'static str> + where + T: frame_system::Trait, + ExtendedBalance: From>>, + { + let selected_benchmark = SelectedBenchmark::feasibility_check; + let components = + >::components( + &selected_benchmark, + ); + let execute_benchmark = | c : Vec < ( :: frame_benchmarking :: BenchmarkParameter , u32 ) > | -> Result < ( ) , & 'static str > { let closure_to_verify = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T , _ > > :: instance ( & selected_benchmark , & c , true ) ? ; if :: frame_benchmarking :: Zero :: is_zero ( & frame_system :: Module :: < T > :: block_number ( ) ) { frame_system :: Module :: < T > :: set_block_number ( 1 . into ( ) ) ; } closure_to_verify ( ) ? ; :: frame_benchmarking :: benchmarking :: wipe_db ( ) ; Ok ( ( ) ) } ; + if components.is_empty() { + execute_benchmark(Default::default())?; + } else { + for (_, (name, low, high)) in components.iter().enumerate() { + for component_value in <[_]>::into_vec(box [low, high]) { + let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = components + .iter() + .enumerate() + .map(|(_, (n, _, h))| { + if n == name { + (*n, *component_value) + } else { + (*n, *h) + } + }) + .collect(); + execute_benchmark(c)?; + } } } + Ok(()) } - impl core::fmt::Debug for OriginCaller { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + #[allow(non_camel_case_types)] + enum SelectedBenchmark { + submit_signed, + submit_unsigned, + open_signed_phase, + close_signed_phase, + feasibility_check, + } + impl ::frame_benchmarking::BenchmarkingSetup for SelectedBenchmark + where + ExtendedBalance: From>>, + { + fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { + match self { Self :: submit_signed => < submit_signed as :: frame_benchmarking :: BenchmarkingSetup < T > > :: components ( & submit_signed ) , Self :: submit_unsigned => < submit_unsigned as :: frame_benchmarking :: BenchmarkingSetup < T > > :: components ( & submit_unsigned ) , Self :: open_signed_phase => < open_signed_phase as :: frame_benchmarking :: BenchmarkingSetup < T > > :: components ( & open_signed_phase ) , Self :: close_signed_phase => < close_signed_phase as :: frame_benchmarking :: BenchmarkingSetup < T > > :: components ( & close_signed_phase ) , Self :: feasibility_check => < feasibility_check as :: frame_benchmarking :: BenchmarkingSetup < T > > :: components ( & feasibility_check ) , } + } + fn instance( + &self, + components: &[(::frame_benchmarking::BenchmarkParameter, u32)], + verify: bool, + ) -> Result Result<(), &'static str>>, &'static str> { match self { - Self::system(ref a0) => { - fmt.debug_tuple("OriginCaller::system").field(a0).finish() + Self::submit_signed => { + >::instance( + &submit_signed, + components, + verify, + ) + } + Self::submit_unsigned => { + >::instance( + &submit_unsigned, + components, + verify, + ) + } + Self::open_signed_phase => { + >::instance( + &open_signed_phase, + components, + verify, + ) + } + Self::close_signed_phase => { + >::instance( + &close_signed_phase, + components, + verify, + ) + } + Self::feasibility_check => { + >::instance( + &feasibility_check, + components, + verify, + ) } - Self::Void(ref a0) => fmt.debug_tuple("OriginCaller::Void").field(a0).finish(), - _ => Ok(()), } } } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for OriginCaller { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - OriginCaller::system(ref aa) => { - dest.push_byte(0usize as u8); - dest.push(aa); + impl ::frame_benchmarking::Benchmarking<::frame_benchmarking::BenchmarkResults> + for Module + where + T: frame_system::Trait, + ExtendedBalance: From>>, + { + fn benchmarks(extra: bool) -> Vec<&'static [u8]> { + let mut all = <[_]>::into_vec(box [ + "submit_signed".as_ref(), + "submit_unsigned".as_ref(), + "open_signed_phase".as_ref(), + "close_signed_phase".as_ref(), + "feasibility_check".as_ref(), + ]); + if !extra { + let extra = []; + all.retain(|x| !extra.contains(x)); + } + all + } + fn run_benchmark( + extrinsic: &[u8], + lowest_range_values: &[u32], + highest_range_values: &[u32], + steps: &[u32], + repeat: u32, + whitelist: &[::frame_benchmarking::TrackedStorageKey], + verify: bool, + ) -> Result, &'static str> { + let extrinsic = sp_std::str::from_utf8(extrinsic) + .map_err(|_| "`extrinsic` is not a valid utf8 string!")?; + let selected_benchmark = match extrinsic { + "submit_signed" => SelectedBenchmark::submit_signed, + "submit_unsigned" => SelectedBenchmark::submit_unsigned, + "open_signed_phase" => SelectedBenchmark::open_signed_phase, + "close_signed_phase" => SelectedBenchmark::close_signed_phase, + "feasibility_check" => SelectedBenchmark::feasibility_check, + _ => return Err("Could not find extrinsic."), + }; + let mut results: Vec<::frame_benchmarking::BenchmarkResults> = Vec::new(); + if repeat == 0 { + return Ok(results); + } + let mut whitelist = whitelist.to_vec(); + let whitelisted_caller_key = < frame_system :: Account < T > as frame_support :: storage :: StorageMap < _ , _ > > :: hashed_key_for ( :: frame_benchmarking :: whitelisted_caller :: < T :: AccountId > ( ) ) ; + whitelist.push(whitelisted_caller_key.into()); + ::frame_benchmarking::benchmarking::set_whitelist(whitelist); + ::frame_benchmarking::benchmarking::commit_db(); + ::frame_benchmarking::benchmarking::wipe_db(); + let components = >::components(&selected_benchmark); + let mut prev_steps = 10; + let repeat_benchmark = |repeat: u32, + c: &[(::frame_benchmarking::BenchmarkParameter, u32)], + results: &mut Vec< + ::frame_benchmarking::BenchmarkResults, + >, + verify: bool| + -> Result<(), &'static str> { + for _ in 0..repeat { + let closure_to_benchmark = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T > > :: instance ( & selected_benchmark , c , verify ) ? ; + if ::frame_benchmarking::Zero::is_zero( + &frame_system::Module::::block_number(), + ) { + frame_system::Module::::set_block_number(1.into()); } - OriginCaller::Void(ref aa) => { - dest.push_byte(1usize as u8); - dest.push(aa); + ::frame_benchmarking::benchmarking::commit_db(); + ::frame_benchmarking::benchmarking::reset_read_write_count(); + if verify { + closure_to_benchmark()?; + } else { + { + let lvl = ::log::Level::Trace; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + :: log :: __private_api_log ( :: core :: fmt :: Arguments :: new_v1 ( & [ "Start Benchmark: " ] , & match ( & c , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } ) , lvl , & ( "benchmark" , "frame_election_providers::two_phase::benchmarking" , "frame/election-providers/src/two_phase/benchmarking.rs" , 81u32 ) ) ; + } + }; + let start_extrinsic = + ::frame_benchmarking::benchmarking::current_time(); + closure_to_benchmark()?; + let finish_extrinsic = + ::frame_benchmarking::benchmarking::current_time(); + let elapsed_extrinsic = finish_extrinsic - start_extrinsic; + ::frame_benchmarking::benchmarking::commit_db(); + { + let lvl = ::log::Level::Trace; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + :: log :: __private_api_log ( :: core :: fmt :: Arguments :: new_v1 ( & [ "End Benchmark: " , " ns" ] , & match ( & elapsed_extrinsic , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Display :: fmt ) ] , } ) , lvl , & ( "benchmark" , "frame_election_providers::two_phase::benchmarking" , "frame/election-providers/src/two_phase/benchmarking.rs" , 81u32 ) ) ; + } + }; + let read_write_count = + ::frame_benchmarking::benchmarking::read_write_count(); + { + let lvl = ::log::Level::Trace; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + :: log :: __private_api_log ( :: core :: fmt :: Arguments :: new_v1 ( & [ "Read/Write Count " ] , & match ( & read_write_count , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } ) , lvl , & ( "benchmark" , "frame_election_providers::two_phase::benchmarking" , "frame/election-providers/src/two_phase/benchmarking.rs" , 81u32 ) ) ; + } + }; + let start_storage_root = + ::frame_benchmarking::benchmarking::current_time(); + ::frame_benchmarking::storage_root(); + let finish_storage_root = + ::frame_benchmarking::benchmarking::current_time(); + let elapsed_storage_root = finish_storage_root - start_storage_root; + results.push(::frame_benchmarking::BenchmarkResults { + components: c.to_vec(), + extrinsic_time: elapsed_extrinsic, + storage_root_time: elapsed_storage_root, + reads: read_write_count.0, + repeat_reads: read_write_count.1, + writes: read_write_count.2, + repeat_writes: read_write_count.3, + }); + } + ::frame_benchmarking::benchmarking::wipe_db(); + } + Ok(()) + }; + if components.is_empty() { + if verify { + repeat_benchmark(1, Default::default(), &mut Vec::new(), true)?; + } + repeat_benchmark(repeat, Default::default(), &mut results, false)?; + } else { + for (idx, (name, low, high)) in components.iter().enumerate() { + let steps = steps.get(idx).cloned().unwrap_or(prev_steps); + prev_steps = steps; + if steps == 0 { + continue; + } + let lowest = lowest_range_values.get(idx).cloned().unwrap_or(*low); + let highest = highest_range_values.get(idx).cloned().unwrap_or(*high); + let diff = highest - lowest; + let step_size = (diff / steps).max(1); + let num_of_steps = diff / step_size + 1; + for s in 0..num_of_steps { + let component_value = lowest + step_size * s; + let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = + components + .iter() + .enumerate() + .map(|(idx, (n, _, h))| { + if n == name { + (*n, component_value) + } else { + (*n, *highest_range_values.get(idx).unwrap_or(h)) + } + }) + .collect(); + if verify { + repeat_benchmark(1, &c, &mut Vec::new(), true)?; + } + repeat_benchmark(repeat, &c, &mut results, false)?; } - _ => (), } } + return Ok(results); } - impl _parity_scale_codec::EncodeLike for OriginCaller {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for OriginCaller { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(OriginCaller::system({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err( - "Error decoding field OriginCaller :: system.0".into() - ) - } - Ok(a) => a, - } - })), - x if x == 1usize as u8 => Ok(OriginCaller::Void({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field OriginCaller :: Void.0".into()) + } + #[cfg(test)] + mod test { + use super::*; + use crate::two_phase::mock::*; + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const test_benchmarks: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::benchmarking::test::test_benchmarks"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(test_benchmarks())), + }; + fn test_benchmarks() { + ExtBuilder::default().build_and_execute(|| { + let is = test_benchmark_feasibility_check::(); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) } - Ok(a) => a, } - })), - x => Err("No such variant in enum OriginCaller".into()), - } - } - } - }; - #[allow(dead_code)] - impl Origin { - /// Create with system none origin and `frame-system::Trait::BaseCallFilter`. - pub fn none() -> Self { - ::none() - } - /// Create with system root origin and no filter. - pub fn root() -> Self { - ::root() - } - /// Create with system signed origin and `frame-system::Trait::BaseCallFilter`. - pub fn signed(by: ::AccountId) -> Self { - ::signed(by) - } - } - impl From> for OriginCaller { - fn from(x: frame_system::Origin) -> Self { - OriginCaller::system(x) - } - } - impl From> for Origin { - /// Convert to runtime origin: - /// * root origin is built with no filter - /// * others use `frame-system::Trait::BaseCallFilter` - fn from(x: frame_system::Origin) -> Self { - let o: OriginCaller = x.into(); - o.into() - } - } - impl From for Origin { - fn from(x: OriginCaller) -> Self { - let mut o = Origin { - caller: x, - filter: ::frame_support::sp_std::rc::Rc::new(Box::new(|_| true)), - }; - if !match o.caller { - OriginCaller::system(frame_system::Origin::::Root) => true, - _ => false, - } { - ::frame_support::traits::OriginTrait::reset_filter(&mut o); - } - o - } - } - impl Into<::frame_support::sp_std::result::Result, Origin>> - for Origin - { - /// NOTE: converting to pallet origin loses the origin filter information. - fn into( - self, - ) -> ::frame_support::sp_std::result::Result, Self> { - if let OriginCaller::system(l) = self.caller { - Ok(l) - } else { - Err(self) - } - } - } - impl From::AccountId>> for Origin { - /// Convert to runtime origin with caller being system signed or none and use filter - /// `frame-system::Trait::BaseCallFilter`. - fn from(x: Option<::AccountId>) -> Self { - >::from(x).into() - } - } - impl frame_system::Trait for Runtime { - type BaseCallFilter = (); - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Call = (); - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type Event = (); - type BlockHashCount = (); - type MaximumBlockWeight = (); - type DbWeight = (); - type BlockExecutionWeight = (); - type ExtrinsicBaseWeight = (); - type MaximumExtrinsicWeight = (); - type MaximumBlockLength = (); - type AvailableBlockRatio = (); - type Version = (); - type PalletInfo = (); - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - } - pub struct ExistentialDeposit; - impl ExistentialDeposit { - /// Returns the value of this parameter type. - pub const fn get() -> u64 { - 1 - } - } - impl> ::frame_support::traits::Get for ExistentialDeposit { - fn get() -> I { - I::from(1) + } + }; + }) } } - impl pallet_balances::Trait for Runtime { - type Balance = Balance; - type Event = (); - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type MaxLocks = (); - type WeightInfo = (); - } - use paste::paste; - const SIGNED_PHASE: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(10) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } + } + #[cfg(test)] + mod mock { + use super::*; + pub use frame_support::{assert_noop, assert_ok}; + use frame_support::{parameter_types, traits::OnInitialize}; + use parking_lot::RwLock; + use sp_core::{ + offchain::{ + testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, + OffchainExt, TransactionPoolExt, + }, + H256, }; - const UNSIGNED_PHASE: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(5) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } + use sp_election_providers::ElectionDataProvider; + use sp_npos_elections::{ + assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, to_without_backing, + CompactSolution, ElectionResult, EvaluateSupport, }; - const MAX_SIGNED_SUBMISSIONS: ::std::thread::LocalKey> = { + use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + PerU16, + }; + use std::{cell::RefCell, sync::Arc}; + pub struct Runtime; + impl ::core::marker::StructuralEq for Runtime {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Runtime { #[inline] - fn __init() -> RefCell { - RefCell::new(5) + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + {} } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) + } + impl ::core::marker::StructuralPartialEq for Runtime {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Runtime { + #[inline] + fn eq(&self, other: &Runtime) -> bool { + match *other { + Runtime => match *self { + Runtime => true, + }, } } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const TARGETS: ::std::thread::LocalKey>> = { + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Runtime { #[inline] - fn __init() -> RefCell> { - RefCell::new(<[_]>::into_vec(box [10, 20, 30, 40])) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell>> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner>> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const VOTERS: ::std::thread::LocalKey< - RefCell)>>, - > = { - #[inline] - fn __init() -> RefCell)>> { - RefCell::new(<[_]>::into_vec(box [ - (1, 10, <[_]>::into_vec(box [10, 20])), - (2, 10, <[_]>::into_vec(box [30, 40])), - (3, 10, <[_]>::into_vec(box [40])), - (4, 10, <[_]>::into_vec(box [10, 20, 30, 40])), - (10, 10, <[_]>::into_vec(box [10])), - (20, 20, <[_]>::into_vec(box [20])), - (30, 30, <[_]>::into_vec(box [30])), - (40, 40, <[_]>::into_vec(box [40])), - ])) - } - unsafe fn __getit( - ) -> ::std::option::Option<&'static RefCell)>>> - { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner< - RefCell)>>, - > = ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const DESIRED_TARGETS: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(2) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const SIGNED_DEPOSIT_BASE: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(5) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const SIGNED_REWARD_BASE: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(7) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - pub struct SignedPhase; - impl Get for SignedPhase { - fn get() -> u64 { - SIGNED_PHASE.with(|v| v.borrow().clone()) - } - } - pub struct UnsignedPhase; - impl Get for UnsignedPhase { - fn get() -> u64 { - UNSIGNED_PHASE.with(|v| v.borrow().clone()) - } - } - pub struct MaxSignedSubmissions; - impl Get for MaxSignedSubmissions { - fn get() -> u32 { - MAX_SIGNED_SUBMISSIONS.with(|v| v.borrow().clone()) - } - } - pub struct Targets; - impl Get> for Targets { - fn get() -> Vec { - TARGETS.with(|v| v.borrow().clone()) - } - } - pub struct Voters; - impl Get)>> for Voters { - fn get() -> Vec<(AccountId, VoteWeight, Vec)> { - VOTERS.with(|v| v.borrow().clone()) - } - } - pub struct DesiredTargets; - impl Get for DesiredTargets { - fn get() -> u32 { - DESIRED_TARGETS.with(|v| v.borrow().clone()) - } - } - pub struct SignedDepositBase; - impl Get for SignedDepositBase { - fn get() -> Balance { - SIGNED_DEPOSIT_BASE.with(|v| v.borrow().clone()) - } - } - pub struct SignedRewardBase; - impl Get for SignedRewardBase { - fn get() -> Balance { - SIGNED_REWARD_BASE.with(|v| v.borrow().clone()) - } - } - impl crate::ElectionDataProvider for ExtBuilder { - fn targets() -> Vec { - Targets::get() - } - fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { - Voters::get() - } - fn desired_targets() -> u32 { - DesiredTargets::get() - } - fn feasibility_check_assignment( - _: &AccountId, - _: &[(AccountId, P)], - ) -> bool { - true - } - fn next_election_prediction(now: u64) -> u64 { - now + 20 - now % 20 - } - } - impl crate::two_phase::Trait for Runtime { - type Event = (); - type Currency = Balances; - type SignedPhase = SignedPhase; - type UnsignedPhase = UnsignedPhase; - type MaxSignedSubmissions = MaxSignedSubmissions; - type SignedRewardBase = SignedRewardBase; - type SignedRewardFactor = (); - type SignedDepositBase = SignedDepositBase; - type SignedDepositByte = (); - type SignedDepositWeight = (); - type SolutionImprovementThreshold = (); - type SlashHandler = (); - type RewardHandler = (); - type ElectionDataProvider = ExtBuilder; - type WeightInfo = (); - } - pub struct ExtBuilder { - signed_phase: u64, - unsigned_phase: u64, - } - impl Default for ExtBuilder { - fn default() -> Self { - Self { - signed_phase: SignedPhase::get(), - unsigned_phase: UnsignedPhase::get(), - } - } - } - impl ExtBuilder { - fn set_constants(&self) {} - pub fn build_and_execute(self, test: impl FnOnce() -> ()) { - self.set_constants(); - let mut storage = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - let _ = pallet_balances::GenesisConfig:: { - balances: <[_]>::into_vec(box [(99, 100)]), - } - .assimilate_storage(&mut storage); - sp_io::TestExternalities::from(storage).execute_with(test) + fn clone(&self) -> Runtime { + match *self { + Runtime => Runtime, + } } } - } - pub mod signed { - use crate::two_phase::*; - use codec::Encode; - use sp_arithmetic::traits::SaturatedConversion; - use sp_npos_elections::is_score_better; - impl Module { - /// Start the signed phase. - /// - /// Upon calling this, auxillary data for election is stored and signed solutions will be - /// accepted. - /// - /// The signed phase must always start before the unsigned phase. - pub fn start_signed_phase() { - let targets = T::ElectionDataProvider::targets(); - let voters = T::ElectionDataProvider::voters(); - let desired_targets = T::ElectionDataProvider::desired_targets(); - >::put(targets); - >::put(voters); - DesiredTargets::put(desired_targets); - } - /// Finish the singed phase. - /// - /// Returns true if we have a good solution in the signed phase. - pub fn finalize_signed_phase() -> bool { - let mut all_submission: Vec> = - >::take(); - let mut found_solution = false; - while let Some(best) = all_submission.pop() { - let SignedSubmission { - solution, - who, - deposit, - reward, - } = best; - match Self::feasibility_check(solution) { - Ok(ready_solution) => { - >::put(ready_solution); - let _remaining = T::Currency::unreserve(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic( - "assertion failed: _remaining.is_zero()", - ) - } - }; - }; - let positive_imbalance = T::Currency::deposit_creating(&who, reward); - T::RewardHandler::on_unbalanced(positive_imbalance); - found_solution = true; - break; - } - Err(_) => { - let (negative_imbalance, _remaining) = - T::Currency::slash_reserved(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic( - "assertion failed: _remaining.is_zero()", - ) - } - }; - }; - T::SlashHandler::on_unbalanced(negative_imbalance); - } - } - } - all_submission.into_iter().for_each(|not_processed| { - let SignedSubmission { who, deposit, .. } = not_processed; - let _remaining = T::Currency::unreserve(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic("assertion failed: _remaining.is_zero()") - } - }; - }; - }); - found_solution - } - /// Find a proper position in the queue for the signed queue, whilst maintaining the order of - /// solution quality. - pub fn insert_submission( - who: &T::AccountId, - queue: &mut Vec>>, - solution: RawSolution, - ) -> Option { - let outcome = queue + pub(crate) type Balances = pallet_balances::Module; + pub(crate) type System = frame_system::Module; + pub(crate) type TwoPhase = super::Module; + pub(crate) type Balance = u64; + pub(crate) type AccountId = u64; + extern crate sp_npos_elections as _npos; + /// A struct to encode a election assignment in a compact way. + impl _npos::codec::Encode for TestCompact { + fn encode(&self) -> Vec { + let mut r = ::alloc::vec::Vec::new(); + let votes1 = self + .votes1 .iter() - .enumerate() - .rev() - .find_map(|(i, s)| { - if is_score_better( - solution.score, - s.solution.score, - T::SolutionImprovementThreshold::get(), - ) { - Some(i + 1) - } else { - None - } + .map(|(v, t)| { + ( + _npos::codec::Compact(v.clone()), + _npos::codec::Compact(t.clone()), + ) }) - .or(Some(0)) - .and_then(|at| { - if at == 0 && queue.len() as u32 >= T::MaxSignedSubmissions::get() { - None - } else { - let reward = Self::reward_for(&solution); - let deposit = Self::deposit_for(&solution); - let submission = SignedSubmission { - who: who.clone(), - deposit, - reward, - solution, - }; - queue.insert(at, submission); - if queue.len() as u32 >= T::MaxSignedSubmissions::get() { - queue.remove(0); - Some(at - 1) - } else { - Some(at) - } - } - }); - if true { - if !(queue.len() as u32 <= T::MaxSignedSubmissions::get()) { - { - :: std :: rt :: begin_panic ( "assertion failed: queue.len() as u32 <= T::MaxSignedSubmissions::get()" ) - } - }; - }; - outcome - } - pub fn deposit_for(solution: &RawSolution) -> BalanceOf { - let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); - T::SignedDepositBase::get() + T::SignedDepositByte::get() * encoded_len - } - pub fn reward_for(solution: &RawSolution) -> BalanceOf { - T::SignedRewardBase::get() - + T::SignedRewardFactor::get() - * solution.score[0].saturated_into::>() - } - } - #[cfg(test)] - mod tests { - use super::{mock::*, *}; - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const cannot_submit_too_early: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::signed::tests::cannot_submit_too_early"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(cannot_submit_too_early())), - }; - fn cannot_submit_too_early() { - ExtBuilder::default().build_and_execute(|| { - roll_to(2); - { - match (&TwoPhase::current_phase(), &Phase::Off) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - TwoPhase::start_signed_phase(); - let solution = raw_solution(); - let h = ::frame_support::storage_root(); - { - match ( - &TwoPhase::submit(Origin::signed(10), solution), - &Err(PalletError::::EarlySubmission.into()), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&h, &::frame_support::storage_root()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const should_pay_deposit: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::signed::tests::should_pay_deposit"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(should_pay_deposit())), - }; - fn should_pay_deposit() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let solution = raw_solution(); - { - match (&balances(&99), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - { - match (&balances(&99), &(95, 5)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&TwoPhase::signed_submissions().first().unwrap().deposit, &5) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const good_solution_is_rewarded: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::good_solution_is_rewarded", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn( - || test::assert_test_result(good_solution_is_rewarded()), - ), - }; - fn good_solution_is_rewarded() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let mut solution = raw_solution(); - { - match (&balances(&99), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - { - match (&balances(&99), &(95, 5)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::finalize_signed_phase() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::finalize_signed_phase()", - ) - } - }; - { - match (&balances(&99), &(100 + 7, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const bad_solution_is_slashed: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::signed::tests::bad_solution_is_slashed"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(bad_solution_is_slashed())), - }; - fn bad_solution_is_slashed() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let mut solution = raw_solution(); - { - match (&balances(&99), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - solution.score[0] += 1; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - { - match (&balances(&99), &(95, 5)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !!TwoPhase::finalize_signed_phase() { - { - ::std::rt::begin_panic( - "assertion failed: !TwoPhase::finalize_signed_phase()", - ) - } - }; - { - match (&balances(&99), &(95, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const queue_is_always_sorted: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::signed::tests::queue_is_always_sorted"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(queue_is_always_sorted())), - }; - fn queue_is_always_sorted() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let solution = RawSolution { - winners: <[_]>::into_vec(box [1u16]), - score: [5, 0, 0], - ..Default::default() - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - let solution = RawSolution { - winners: <[_]>::into_vec(box [2u16]), - score: [4, 0, 0], - ..Default::default() - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - let solution = RawSolution { - winners: <[_]>::into_vec(box [3u16]), - score: [6, 0, 0], - ..Default::default() - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - { - match ( - &TwoPhase::signed_submissions() - .iter() - .map(|x| x.solution.winners[0]) - .collect::>(), - &<[_]>::into_vec(box [2, 1, 3]), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; + .collect::>(); + votes1.encode_to(&mut r); + let votes2 = self + .votes2 + .iter() + .map(|(v, (t1, w), t2)| { + ( + _npos::codec::Compact(v.clone()), + ( + _npos::codec::Compact(t1.clone()), + _npos::codec::Compact(w.clone()), + ), + _npos::codec::Compact(t2.clone()), + ) + }) + .collect::>(); + votes2.encode_to(&mut r); + let votes3 = self + .votes3 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes3.encode_to(&mut r); + let votes4 = self + .votes4 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes4.encode_to(&mut r); + let votes5 = self + .votes5 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes5.encode_to(&mut r); + let votes6 = self + .votes6 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes6.encode_to(&mut r); + let votes7 = self + .votes7 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes7.encode_to(&mut r); + let votes8 = self + .votes8 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes8.encode_to(&mut r); + let votes9 = self + .votes9 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes9.encode_to(&mut r); + let votes10 = self + .votes10 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes10.encode_to(&mut r); + let votes11 = self + .votes11 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes11.encode_to(&mut r); + let votes12 = self + .votes12 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes12.encode_to(&mut r); + let votes13 = self + .votes13 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes13.encode_to(&mut r); + let votes14 = self + .votes14 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[12usize].0.clone()), + _npos::codec::Compact(inner[12usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes14.encode_to(&mut r); + let votes15 = self + .votes15 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[12usize].0.clone()), + _npos::codec::Compact(inner[12usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[13usize].0.clone()), + _npos::codec::Compact(inner[13usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes15.encode_to(&mut r); + let votes16 = self + .votes16 + .iter() + .map(|(v, inner, t_last)| { + ( + _npos::codec::Compact(v.clone()), + [ + ( + _npos::codec::Compact(inner[0usize].0.clone()), + _npos::codec::Compact(inner[0usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[1usize].0.clone()), + _npos::codec::Compact(inner[1usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[2usize].0.clone()), + _npos::codec::Compact(inner[2usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[3usize].0.clone()), + _npos::codec::Compact(inner[3usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[4usize].0.clone()), + _npos::codec::Compact(inner[4usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[5usize].0.clone()), + _npos::codec::Compact(inner[5usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[6usize].0.clone()), + _npos::codec::Compact(inner[6usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[7usize].0.clone()), + _npos::codec::Compact(inner[7usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[8usize].0.clone()), + _npos::codec::Compact(inner[8usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[9usize].0.clone()), + _npos::codec::Compact(inner[9usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[10usize].0.clone()), + _npos::codec::Compact(inner[10usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[11usize].0.clone()), + _npos::codec::Compact(inner[11usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[12usize].0.clone()), + _npos::codec::Compact(inner[12usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[13usize].0.clone()), + _npos::codec::Compact(inner[13usize].1.clone()), + ), + ( + _npos::codec::Compact(inner[14usize].0.clone()), + _npos::codec::Compact(inner[14usize].1.clone()), + ), + ], + _npos::codec::Compact(t_last.clone()), + ) + }) + .collect::>(); + votes16.encode_to(&mut r); + r + } + } + impl _npos::codec::Decode for TestCompact { + fn decode(value: &mut I) -> Result { + let votes1 = < Vec < ( _npos :: codec :: Compact < u32 > , _npos :: codec :: Compact < u16 > ) > as _npos :: codec :: Decode > :: decode ( value ) ? ; + let votes1 = votes1 + .into_iter() + .map(|(v, t)| (v.0, t.0)) + .collect::>(); + let votes2 = , + (_npos::codec::Compact, _npos::codec::Compact), + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes2 = votes2 + .into_iter() + .map(|(v, (t1, w), t2)| (v.0, (t1.0, w.0), t2.0)) + .collect::>(); + let votes3 = , + [(_npos::codec::Compact, _npos::codec::Compact); 3usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes3 = votes3 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes4 = , + [(_npos::codec::Compact, _npos::codec::Compact); 4usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes4 = votes4 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes5 = , + [(_npos::codec::Compact, _npos::codec::Compact); 5usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes5 = votes5 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes6 = , + [(_npos::codec::Compact, _npos::codec::Compact); 6usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes6 = votes6 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes7 = , + [(_npos::codec::Compact, _npos::codec::Compact); 7usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes7 = votes7 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes8 = , + [(_npos::codec::Compact, _npos::codec::Compact); 8usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes8 = votes8 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes9 = , + [(_npos::codec::Compact, _npos::codec::Compact); 9usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes9 = votes9 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes10 = , + [(_npos::codec::Compact, _npos::codec::Compact); 10usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes10 = votes10 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes11 = , + [(_npos::codec::Compact, _npos::codec::Compact); 11usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes11 = votes11 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes12 = , + [(_npos::codec::Compact, _npos::codec::Compact); 12usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes12 = votes12 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes13 = , + [(_npos::codec::Compact, _npos::codec::Compact); 13usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes13 = votes13 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes14 = , + [(_npos::codec::Compact, _npos::codec::Compact); 14usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes14 = votes14 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ((inner[12usize].0).0, (inner[12usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes15 = , + [(_npos::codec::Compact, _npos::codec::Compact); 15usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes15 = votes15 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ((inner[12usize].0).0, (inner[12usize].1).0), + ((inner[13usize].0).0, (inner[13usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + let votes16 = , + [(_npos::codec::Compact, _npos::codec::Compact); 16usize - 1], + _npos::codec::Compact, + )> as _npos::codec::Decode>::decode(value)?; + let votes16 = votes16 + .into_iter() + .map(|(v, inner, t_last)| { + ( + v.0, + [ + ((inner[0usize].0).0, (inner[0usize].1).0), + ((inner[1usize].0).0, (inner[1usize].1).0), + ((inner[2usize].0).0, (inner[2usize].1).0), + ((inner[3usize].0).0, (inner[3usize].1).0), + ((inner[4usize].0).0, (inner[4usize].1).0), + ((inner[5usize].0).0, (inner[5usize].1).0), + ((inner[6usize].0).0, (inner[6usize].1).0), + ((inner[7usize].0).0, (inner[7usize].1).0), + ((inner[8usize].0).0, (inner[8usize].1).0), + ((inner[9usize].0).0, (inner[9usize].1).0), + ((inner[10usize].0).0, (inner[10usize].1).0), + ((inner[11usize].0).0, (inner[11usize].1).0), + ((inner[12usize].0).0, (inner[12usize].1).0), + ((inner[13usize].0).0, (inner[13usize].1).0), + ((inner[14usize].0).0, (inner[14usize].1).0), + ], + t_last.0, + ) + }) + .collect::>(); + Ok(TestCompact { + votes1, + votes2, + votes3, + votes4, + votes5, + votes6, + votes7, + votes8, + votes9, + votes10, + votes11, + votes12, + votes13, + votes14, + votes15, + votes16, }) } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const can_submit_until_queue_full: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::can_submit_until_queue_full", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(can_submit_until_queue_full()) - }), - }; - fn can_submit_until_queue_full() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - for s in 0..MaxSignedSubmissions::get() { - let solution = RawSolution { - winners: <[_]>::into_vec(box [1u16]), - score: [(5 + s).into(), 0, 0], - ..Default::default() - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: - ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: - ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - } - let solution = RawSolution { - winners: <[_]>::into_vec(box [1u16]), - score: [4, 0, 0], - ..Default::default() - }; - let h = ::frame_support::storage_root(); - { - match ( - &TwoPhase::submit(Origin::signed(99), solution), - &Err(PalletError::::QueueFull.into()), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } + } + pub struct TestCompact { + votes1: Vec<(u32, u16)>, + votes2: Vec<(u32, (u16, PerU16), u16)>, + votes3: Vec<(u32, [(u16, PerU16); 2usize], u16)>, + votes4: Vec<(u32, [(u16, PerU16); 3usize], u16)>, + votes5: Vec<(u32, [(u16, PerU16); 4usize], u16)>, + votes6: Vec<(u32, [(u16, PerU16); 5usize], u16)>, + votes7: Vec<(u32, [(u16, PerU16); 6usize], u16)>, + votes8: Vec<(u32, [(u16, PerU16); 7usize], u16)>, + votes9: Vec<(u32, [(u16, PerU16); 8usize], u16)>, + votes10: Vec<(u32, [(u16, PerU16); 9usize], u16)>, + votes11: Vec<(u32, [(u16, PerU16); 10usize], u16)>, + votes12: Vec<(u32, [(u16, PerU16); 11usize], u16)>, + votes13: Vec<(u32, [(u16, PerU16); 12usize], u16)>, + votes14: Vec<(u32, [(u16, PerU16); 13usize], u16)>, + votes15: Vec<(u32, [(u16, PerU16); 14usize], u16)>, + votes16: Vec<(u32, [(u16, PerU16); 15usize], u16)>, + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for TestCompact { + #[inline] + fn default() -> TestCompact { + TestCompact { + votes1: ::core::default::Default::default(), + votes2: ::core::default::Default::default(), + votes3: ::core::default::Default::default(), + votes4: ::core::default::Default::default(), + votes5: ::core::default::Default::default(), + votes6: ::core::default::Default::default(), + votes7: ::core::default::Default::default(), + votes8: ::core::default::Default::default(), + votes9: ::core::default::Default::default(), + votes10: ::core::default::Default::default(), + votes11: ::core::default::Default::default(), + votes12: ::core::default::Default::default(), + votes13: ::core::default::Default::default(), + votes14: ::core::default::Default::default(), + votes15: ::core::default::Default::default(), + votes16: ::core::default::Default::default(), + } + } + } + impl ::core::marker::StructuralPartialEq for TestCompact {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for TestCompact { + #[inline] + fn eq(&self, other: &TestCompact) -> bool { + match *other { + TestCompact { + votes1: ref __self_1_0, + votes2: ref __self_1_1, + votes3: ref __self_1_2, + votes4: ref __self_1_3, + votes5: ref __self_1_4, + votes6: ref __self_1_5, + votes7: ref __self_1_6, + votes8: ref __self_1_7, + votes9: ref __self_1_8, + votes10: ref __self_1_9, + votes11: ref __self_1_10, + votes12: ref __self_1_11, + votes13: ref __self_1_12, + votes14: ref __self_1_13, + votes15: ref __self_1_14, + votes16: ref __self_1_15, + } => { + match *self { + TestCompact { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) && (*__self_0_2) == (*__self_1_2) + && (*__self_0_3) == (*__self_1_3) && (*__self_0_4) == (*__self_1_4) + && (*__self_0_5) == (*__self_1_5) && (*__self_0_6) == (*__self_1_6) + && (*__self_0_7) == (*__self_1_7) && (*__self_0_8) == (*__self_1_8) + && (*__self_0_9) == (*__self_1_9) && (*__self_0_10) + == (*__self_1_10) && (*__self_0_11) == (*__self_1_11) + && (*__self_0_12) == (*__self_1_12) && (*__self_0_13) + == (*__self_1_13) && (*__self_0_14) == (*__self_1_14) + && (*__self_0_15) == (*__self_1_15) } } - }; - { - match (&h, &::frame_support::storage_root()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } + } + } + } + #[inline] + fn ne(&self, other: &TestCompact) -> bool { + match *other { + TestCompact { + votes1: ref __self_1_0, + votes2: ref __self_1_1, + votes3: ref __self_1_2, + votes4: ref __self_1_3, + votes5: ref __self_1_4, + votes6: ref __self_1_5, + votes7: ref __self_1_6, + votes8: ref __self_1_7, + votes9: ref __self_1_8, + votes10: ref __self_1_9, + votes11: ref __self_1_10, + votes12: ref __self_1_11, + votes13: ref __self_1_12, + votes14: ref __self_1_13, + votes15: ref __self_1_14, + votes16: ref __self_1_15, + } => { + match *self { + TestCompact { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) || (*__self_0_2) != (*__self_1_2) + || (*__self_0_3) != (*__self_1_3) || (*__self_0_4) != (*__self_1_4) + || (*__self_0_5) != (*__self_1_5) || (*__self_0_6) != (*__self_1_6) + || (*__self_0_7) != (*__self_1_7) || (*__self_0_8) != (*__self_1_8) + || (*__self_0_9) != (*__self_1_9) || (*__self_0_10) + != (*__self_1_10) || (*__self_0_11) != (*__self_1_11) + || (*__self_0_12) != (*__self_1_12) || (*__self_0_13) + != (*__self_1_13) || (*__self_0_14) != (*__self_1_14) + || (*__self_0_15) != (*__self_1_15) } } - }; - }) + } + } } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const weakest_is_removed_if_better_provided: test::TestDescAndFn = - test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::weakest_is_removed_if_better_provided", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(weakest_is_removed_if_better_provided()) - }), - }; - fn weakest_is_removed_if_better_provided() {} - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const cannot_submit_worse_with_full_queue: test::TestDescAndFn = - test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::cannot_submit_worse_with_full_queue", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(cannot_submit_worse_with_full_queue()) - }), - }; - fn cannot_submit_worse_with_full_queue() {} - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const suppressed_solution_gets_bond_back: test::TestDescAndFn = - test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::suppressed_solution_gets_bond_back", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, + } + impl ::core::marker::StructuralEq for TestCompact {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for TestCompact { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq>; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for TestCompact { + #[inline] + fn clone(&self) -> TestCompact { + match *self { + TestCompact { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => TestCompact { + votes1: ::core::clone::Clone::clone(&(*__self_0_0)), + votes2: ::core::clone::Clone::clone(&(*__self_0_1)), + votes3: ::core::clone::Clone::clone(&(*__self_0_2)), + votes4: ::core::clone::Clone::clone(&(*__self_0_3)), + votes5: ::core::clone::Clone::clone(&(*__self_0_4)), + votes6: ::core::clone::Clone::clone(&(*__self_0_5)), + votes7: ::core::clone::Clone::clone(&(*__self_0_6)), + votes8: ::core::clone::Clone::clone(&(*__self_0_7)), + votes9: ::core::clone::Clone::clone(&(*__self_0_8)), + votes10: ::core::clone::Clone::clone(&(*__self_0_9)), + votes11: ::core::clone::Clone::clone(&(*__self_0_10)), + votes12: ::core::clone::Clone::clone(&(*__self_0_11)), + votes13: ::core::clone::Clone::clone(&(*__self_0_12)), + votes14: ::core::clone::Clone::clone(&(*__self_0_13)), + votes15: ::core::clone::Clone::clone(&(*__self_0_14)), + votes16: ::core::clone::Clone::clone(&(*__self_0_15)), }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(suppressed_solution_gets_bond_back()) - }), - }; - fn suppressed_solution_gets_bond_back() {} - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const solutions_are_sorted: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::signed::tests::solutions_are_sorted"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(solutions_are_sorted())), - }; - fn solutions_are_sorted() {} - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const all_in_one_singed_submission: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::all_in_one_singed_submission", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(all_in_one_singed_submission()) - }), - }; - fn all_in_one_singed_submission() {} + } + } } - } - pub mod unsigned {} - type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - type PositiveImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::PositiveImbalance; - type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::NegativeImbalance; - /// Accuracy used for on-chain election. - pub type ChainAccuracy = Perbill; - /// Accuracy used for off-chain election. This better be small. - pub type OffchainAccuracy = PerU16; - /// Data type used to index nominators in the compact type. - pub type VoterIndex = u32; - /// Data type used to index validators in the compact type. - pub type TargetIndex = u16; - #[allow(unknown_lints, eq_op)] - const _: [(); 0 - !{ - const ASSERT: bool = size_of::() <= size_of::(); - ASSERT - } as usize] = []; - #[allow(unknown_lints, eq_op)] - const _: [(); 0 - !{ - const ASSERT: bool = size_of::() <= size_of::(); - ASSERT - } as usize] = []; - #[allow(unknown_lints, eq_op)] - const _: [(); 0 - !{ - const ASSERT: bool = size_of::() <= size_of::(); - ASSERT - } as usize] = []; - #[allow(unknown_lints, eq_op)] - const _: [(); 0 - !{ - const ASSERT: bool = size_of::() <= size_of::(); - ASSERT - } as usize] = []; - extern crate sp_npos_elections as _npos; - /// A struct to encode a election assignment in a compact way. - impl _npos::codec::Encode for CompactAssignments { - fn encode(&self) -> Vec { - let mut r = ::alloc::vec::Vec::new(); - let votes1 = self - .votes1 - .iter() - .map(|(v, t)| { - ( - _npos::codec::Compact(v.clone()), - _npos::codec::Compact(t.clone()), - ) - }) - .collect::>(); - votes1.encode_to(&mut r); - let votes2 = self - .votes2 - .iter() - .map(|(v, (t1, w), t2)| { - ( - _npos::codec::Compact(v.clone()), - ( - _npos::codec::Compact(t1.clone()), - _npos::codec::Compact(w.clone()), - ), - _npos::codec::Compact(t2.clone()), - ) - }) - .collect::>(); - votes2.encode_to(&mut r); - let votes3 = self - .votes3 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes3.encode_to(&mut r); - let votes4 = self - .votes4 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes4.encode_to(&mut r); - let votes5 = self - .votes5 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes5.encode_to(&mut r); - let votes6 = self - .votes6 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes6.encode_to(&mut r); - let votes7 = self - .votes7 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes7.encode_to(&mut r); - let votes8 = self - .votes8 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes8.encode_to(&mut r); - let votes9 = self - .votes9 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes9.encode_to(&mut r); - let votes10 = self - .votes10 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes10.encode_to(&mut r); - let votes11 = self - .votes11 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes11.encode_to(&mut r); - let votes12 = self - .votes12 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes12.encode_to(&mut r); - let votes13 = self - .votes13 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::fmt::Debug for TestCompact { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match *self { + TestCompact { + votes1: ref __self_0_0, + votes2: ref __self_0_1, + votes3: ref __self_0_2, + votes4: ref __self_0_3, + votes5: ref __self_0_4, + votes6: ref __self_0_5, + votes7: ref __self_0_6, + votes8: ref __self_0_7, + votes9: ref __self_0_8, + votes10: ref __self_0_9, + votes11: ref __self_0_10, + votes12: ref __self_0_11, + votes13: ref __self_0_12, + votes14: ref __self_0_13, + votes15: ref __self_0_14, + votes16: ref __self_0_15, + } => { + let mut debug_trait_builder = f.debug_struct("TestCompact"); + let _ = debug_trait_builder.field("votes1", &&(*__self_0_0)); + let _ = debug_trait_builder.field("votes2", &&(*__self_0_1)); + let _ = debug_trait_builder.field("votes3", &&(*__self_0_2)); + let _ = debug_trait_builder.field("votes4", &&(*__self_0_3)); + let _ = debug_trait_builder.field("votes5", &&(*__self_0_4)); + let _ = debug_trait_builder.field("votes6", &&(*__self_0_5)); + let _ = debug_trait_builder.field("votes7", &&(*__self_0_6)); + let _ = debug_trait_builder.field("votes8", &&(*__self_0_7)); + let _ = debug_trait_builder.field("votes9", &&(*__self_0_8)); + let _ = debug_trait_builder.field("votes10", &&(*__self_0_9)); + let _ = debug_trait_builder.field("votes11", &&(*__self_0_10)); + let _ = debug_trait_builder.field("votes12", &&(*__self_0_11)); + let _ = debug_trait_builder.field("votes13", &&(*__self_0_12)); + let _ = debug_trait_builder.field("votes14", &&(*__self_0_13)); + let _ = debug_trait_builder.field("votes15", &&(*__self_0_14)); + let _ = debug_trait_builder.field("votes16", &&(*__self_0_15)); + debug_trait_builder.finish() + } + } + } + } + use _npos::__OrInvalidIndex; + impl _npos::CompactSolution for TestCompact { + const LIMIT: usize = 16usize; + type Voter = u32; + type Target = u16; + type VoteWeight = PerU16; + fn len(&self) -> usize { + let mut all_len = 0usize; + all_len = all_len.saturating_add(self.votes1.len()); + all_len = all_len.saturating_add(self.votes2.len()); + all_len = all_len.saturating_add(self.votes3.len()); + all_len = all_len.saturating_add(self.votes4.len()); + all_len = all_len.saturating_add(self.votes5.len()); + all_len = all_len.saturating_add(self.votes6.len()); + all_len = all_len.saturating_add(self.votes7.len()); + all_len = all_len.saturating_add(self.votes8.len()); + all_len = all_len.saturating_add(self.votes9.len()); + all_len = all_len.saturating_add(self.votes10.len()); + all_len = all_len.saturating_add(self.votes11.len()); + all_len = all_len.saturating_add(self.votes12.len()); + all_len = all_len.saturating_add(self.votes13.len()); + all_len = all_len.saturating_add(self.votes14.len()); + all_len = all_len.saturating_add(self.votes15.len()); + all_len = all_len.saturating_add(self.votes16.len()); + all_len + } + fn edge_count(&self) -> usize { + let mut all_edges = 0usize; + all_edges = + all_edges.saturating_add(self.votes1.len().saturating_mul(1usize as usize)); + all_edges = + all_edges.saturating_add(self.votes2.len().saturating_mul(2usize as usize)); + all_edges = + all_edges.saturating_add(self.votes3.len().saturating_mul(3usize as usize)); + all_edges = + all_edges.saturating_add(self.votes4.len().saturating_mul(4usize as usize)); + all_edges = + all_edges.saturating_add(self.votes5.len().saturating_mul(5usize as usize)); + all_edges = + all_edges.saturating_add(self.votes6.len().saturating_mul(6usize as usize)); + all_edges = + all_edges.saturating_add(self.votes7.len().saturating_mul(7usize as usize)); + all_edges = + all_edges.saturating_add(self.votes8.len().saturating_mul(8usize as usize)); + all_edges = + all_edges.saturating_add(self.votes9.len().saturating_mul(9usize as usize)); + all_edges = + all_edges.saturating_add(self.votes10.len().saturating_mul(10usize as usize)); + all_edges = + all_edges.saturating_add(self.votes11.len().saturating_mul(11usize as usize)); + all_edges = + all_edges.saturating_add(self.votes12.len().saturating_mul(12usize as usize)); + all_edges = + all_edges.saturating_add(self.votes13.len().saturating_mul(13usize as usize)); + all_edges = + all_edges.saturating_add(self.votes14.len().saturating_mul(14usize as usize)); + all_edges = + all_edges.saturating_add(self.votes15.len().saturating_mul(15usize as usize)); + all_edges = + all_edges.saturating_add(self.votes16.len().saturating_mul(16usize as usize)); + all_edges + } + fn unique_targets(&self) -> Vec { + let mut all_targets: Vec = + Vec::with_capacity(self.average_edge_count()); + let mut maybe_insert_target = |t: Self::Target| match all_targets.binary_search(&t) + { + Ok(_) => (), + Err(pos) => all_targets.insert(pos, t), + }; + self.votes1.iter().for_each(|(_, t)| { + maybe_insert_target(*t); + }); + self.votes2.iter().for_each(|(_, (t1, _), t2)| { + maybe_insert_target(*t1); + maybe_insert_target(*t2); + }); + self.votes3.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes4.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes5.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes6.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes7.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes8.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes9.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes10.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes11.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes12.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes13.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes14.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes15.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + self.votes16.iter().for_each(|(_, inners, t_last)| { + inners.iter().for_each(|(t, _)| { + maybe_insert_target(*t); + }); + maybe_insert_target(*t_last); + }); + all_targets + } + fn remove_voter(&mut self, to_remove: Self::Voter) -> bool { + if let Some(idx) = self.votes1.iter().position(|(x, _)| *x == to_remove) { + self.votes1.remove(idx); + return true; + } + if let Some(idx) = self.votes2.iter().position(|(x, _, _)| *x == to_remove) { + self.votes2.remove(idx); + return true; + } + if let Some(idx) = self.votes3.iter().position(|(x, _, _)| *x == to_remove) { + self.votes3.remove(idx); + return true; + } + if let Some(idx) = self.votes4.iter().position(|(x, _, _)| *x == to_remove) { + self.votes4.remove(idx); + return true; + } + if let Some(idx) = self.votes5.iter().position(|(x, _, _)| *x == to_remove) { + self.votes5.remove(idx); + return true; + } + if let Some(idx) = self.votes6.iter().position(|(x, _, _)| *x == to_remove) { + self.votes6.remove(idx); + return true; + } + if let Some(idx) = self.votes7.iter().position(|(x, _, _)| *x == to_remove) { + self.votes7.remove(idx); + return true; + } + if let Some(idx) = self.votes8.iter().position(|(x, _, _)| *x == to_remove) { + self.votes8.remove(idx); + return true; + } + if let Some(idx) = self.votes9.iter().position(|(x, _, _)| *x == to_remove) { + self.votes9.remove(idx); + return true; + } + if let Some(idx) = self.votes10.iter().position(|(x, _, _)| *x == to_remove) { + self.votes10.remove(idx); + return true; + } + if let Some(idx) = self.votes11.iter().position(|(x, _, _)| *x == to_remove) { + self.votes11.remove(idx); + return true; + } + if let Some(idx) = self.votes12.iter().position(|(x, _, _)| *x == to_remove) { + self.votes12.remove(idx); + return true; + } + if let Some(idx) = self.votes13.iter().position(|(x, _, _)| *x == to_remove) { + self.votes13.remove(idx); + return true; + } + if let Some(idx) = self.votes14.iter().position(|(x, _, _)| *x == to_remove) { + self.votes14.remove(idx); + return true; + } + if let Some(idx) = self.votes15.iter().position(|(x, _, _)| *x == to_remove) { + self.votes15.remove(idx); + return true; + } + if let Some(idx) = self.votes16.iter().position(|(x, _, _)| *x == to_remove) { + self.votes16.remove(idx); + return true; + } + return false; + } + fn from_assignment( + assignments: Vec<_npos::Assignment>, + index_of_voter: FV, + index_of_target: FT, + ) -> Result + where + A: _npos::IdentifierT, + for<'r> FV: Fn(&'r A) -> Option, + for<'r> FT: Fn(&'r A) -> Option, + { + let mut compact: TestCompact = Default::default(); + for _npos::Assignment { who, distribution } in assignments { + match distribution.len() { + 0 => continue, + 1 => compact.votes1.push(( + index_of_voter(&who).or_invalid_index()?, + index_of_target(&distribution[0].0).or_invalid_index()?, + )), + 2 => compact.votes2.push(( + index_of_voter(&who).or_invalid_index()?, + ( + index_of_target(&distribution[0].0).or_invalid_index()?, + distribution[0].1, + ), + index_of_target(&distribution[1].0).or_invalid_index()?, + )), + 3usize => compact.votes3.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ], + index_of_target(&distribution[2usize].0).or_invalid_index()?, + )), + 4usize => compact.votes4.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ], + index_of_target(&distribution[3usize].0).or_invalid_index()?, + )), + 5usize => compact.votes5.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ], + index_of_target(&distribution[4usize].0).or_invalid_index()?, + )), + 6usize => compact.votes6.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ], + index_of_target(&distribution[5usize].0).or_invalid_index()?, + )), + 7usize => compact.votes7.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ], + index_of_target(&distribution[6usize].0).or_invalid_index()?, + )), + 8usize => compact.votes8.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ], + index_of_target(&distribution[7usize].0).or_invalid_index()?, + )), + 9usize => compact.votes9.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ], + index_of_target(&distribution[8usize].0).or_invalid_index()?, + )), + 10usize => compact.votes10.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ], + index_of_target(&distribution[9usize].0).or_invalid_index()?, + )), + 11usize => compact.votes11.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ], + index_of_target(&distribution[10usize].0).or_invalid_index()?, + )), + 12usize => compact.votes12.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ], + index_of_target(&distribution[11usize].0).or_invalid_index()?, + )), + 13usize => compact.votes13.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ], + index_of_target(&distribution[12usize].0).or_invalid_index()?, + )), + 14usize => compact.votes14.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ( + index_of_target(&distribution[12usize].0).or_invalid_index()?, + distribution[12usize].1, + ), + ], + index_of_target(&distribution[13usize].0).or_invalid_index()?, + )), + 15usize => compact.votes15.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ( + index_of_target(&distribution[12usize].0).or_invalid_index()?, + distribution[12usize].1, + ), + ( + index_of_target(&distribution[13usize].0).or_invalid_index()?, + distribution[13usize].1, + ), + ], + index_of_target(&distribution[14usize].0).or_invalid_index()?, + )), + 16usize => compact.votes16.push(( + index_of_voter(&who).or_invalid_index()?, + [ + ( + index_of_target(&distribution[0usize].0).or_invalid_index()?, + distribution[0usize].1, + ), + ( + index_of_target(&distribution[1usize].0).or_invalid_index()?, + distribution[1usize].1, + ), + ( + index_of_target(&distribution[2usize].0).or_invalid_index()?, + distribution[2usize].1, + ), + ( + index_of_target(&distribution[3usize].0).or_invalid_index()?, + distribution[3usize].1, + ), + ( + index_of_target(&distribution[4usize].0).or_invalid_index()?, + distribution[4usize].1, + ), + ( + index_of_target(&distribution[5usize].0).or_invalid_index()?, + distribution[5usize].1, + ), + ( + index_of_target(&distribution[6usize].0).or_invalid_index()?, + distribution[6usize].1, + ), + ( + index_of_target(&distribution[7usize].0).or_invalid_index()?, + distribution[7usize].1, + ), + ( + index_of_target(&distribution[8usize].0).or_invalid_index()?, + distribution[8usize].1, + ), + ( + index_of_target(&distribution[9usize].0).or_invalid_index()?, + distribution[9usize].1, + ), + ( + index_of_target(&distribution[10usize].0).or_invalid_index()?, + distribution[10usize].1, + ), + ( + index_of_target(&distribution[11usize].0).or_invalid_index()?, + distribution[11usize].1, + ), + ( + index_of_target(&distribution[12usize].0).or_invalid_index()?, + distribution[12usize].1, + ), + ( + index_of_target(&distribution[13usize].0).or_invalid_index()?, + distribution[13usize].1, + ), + ( + index_of_target(&distribution[14usize].0).or_invalid_index()?, + distribution[14usize].1, + ), + ], + index_of_target(&distribution[15usize].0).or_invalid_index()?, + )), + _ => { + return Err(_npos::Error::CompactTargetOverflow); + } + } + } + Ok(compact) + } + fn into_assignment( + self, + voter_at: impl Fn(Self::Voter) -> Option, + target_at: impl Fn(Self::Target) -> Option, + ) -> Result>, _npos::Error> { + let mut assignments: Vec<_npos::Assignment> = Default::default(); + for (voter_index, target_index) in self.votes1 { + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: <[_]>::into_vec(box [( + target_at(target_index).or_invalid_index()?, + PerU16::one(), + )]), + }) + } + for (voter_index, (t1_idx, p1), t2_idx) in self.votes2 { + if p1 >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p2 = + _npos::sp_arithmetic::traits::Saturating::saturating_sub(PerU16::one(), p1); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: <[_]>::into_vec(box [ + (target_at(t1_idx).or_invalid_index()?, p1), + (target_at(t2_idx).or_invalid_index()?, p2), + ]), + }); + } + for (voter_index, inners, t_last_idx) in self.votes3 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes4 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes5 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes6 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes7 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes8 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes9 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes10 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes11 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes12 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes13 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes14 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes15 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + for (voter_index, inners, t_last_idx) in self.votes16 { + let mut sum = PerU16::zero(); + let mut inners_parsed = inners + .iter() + .map(|(ref t_idx, p)| { + sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); + let target = target_at(*t_idx).or_invalid_index()?; + Ok((target, *p)) + }) + .collect::, _npos::Error>>()?; + if sum >= PerU16::one() { + return Err(_npos::Error::CompactStakeOverflow); + } + let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( + PerU16::one(), + sum, + ); + inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); + assignments.push(_npos::Assignment { + who: voter_at(voter_index).or_invalid_index()?, + distribution: inners_parsed, + }); + } + Ok(assignments) + } + } + /// To from `now` to block `n`. + pub fn roll_to(n: u64) { + let now = System::block_number(); + for i in now + 1..=n { + System::set_block_number(i); + TwoPhase::on_initialize(i); + } + } + /// Get the free and reserved balance of some account. + pub fn balances(who: &AccountId) -> (Balance, Balance) { + (Balances::free_balance(who), Balances::reserved_balance(who)) + } + /// Spit out a verifiable raw solution. + /// + /// This is a good example of what an offchain miner would do. + pub fn raw_solution() -> RawSolution> { + let voters = TwoPhase::snapshot_voters().unwrap(); + let targets = TwoPhase::snapshot_targets().unwrap(); + let desired = TwoPhase::desired_targets() as usize; + let voter_index = + |who: &AccountId| -> Option> { + voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < Runtime > > > :: try_into ( i ) . ok ( ) ) + }; + let target_index = + |who: &AccountId| -> Option> { + targets . iter ( ) . position ( | x | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactTargetIndexOf < Runtime > > > :: try_into ( i ) . ok ( ) ) + }; + let stake_of = |who: &AccountId| -> crate::VoteWeight { + voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + }; + let ElectionResult { + winners, + assignments, + } = seq_phragmen::<_, CompactAccuracyOf>( + desired, + targets.clone(), + voters.clone(), + None, + ) + .unwrap(); + let winners = to_without_backing(winners); + let score = { + let staked = + assignment_ratio_to_staked_normalized(assignments.clone(), &stake_of).unwrap(); + to_supports(&winners, &staked).unwrap().evaluate() + }; + let compact = + >::from_assignment(assignments, &voter_index, &target_index) + .unwrap(); + RawSolution { compact, score } + } + /// Creates a **valid** solution with exactly the given size. + /// + /// The snapshot size must be bigger, otherwise this will panic. + pub fn solution_with_size( + active_voters: u32, + winners_count: u32, + ) -> RawSolution> { + use rand::seq::SliceRandom; + let voters = TwoPhase::snapshot_voters().unwrap(); + let targets = TwoPhase::snapshot_targets().unwrap(); + if !(active_voters >= winners_count) { + { + ::std::rt::begin_panic("assertion failed: active_voters >= winners_count") + } + }; + if !(voters.len() >= active_voters as usize) { + { + ::std::rt::begin_panic( + "assertion failed: voters.len() >= active_voters as usize", ) - }) - .collect::>(); - votes13.encode_to(&mut r); - let votes14 = self - .votes14 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[12usize].0.clone()), - _npos::codec::Compact(inner[12usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), + } + }; + if !(targets.len() >= winners_count as usize) { + { + ::std::rt::begin_panic( + "assertion failed: targets.len() >= winners_count as usize", ) - }) + } + }; + let voter_index = + |who: &AccountId| -> Option> { + voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < Runtime > > > :: try_into ( i ) . ok ( ) ) + }; + let voter_at = + |i: crate::two_phase::CompactVoterIndexOf| -> Option { + < crate :: two_phase :: CompactVoterIndexOf < Runtime > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | voters . get ( i ) . map ( | ( x , _ , _ ) | x ) . cloned ( ) ) + }; + let target_at = + |i: crate::two_phase::CompactTargetIndexOf| -> Option { + < crate :: two_phase :: CompactTargetIndexOf < Runtime > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | targets . get ( i ) . cloned ( ) ) + }; + let stake_of = |who: &AccountId| -> crate::VoteWeight { + voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + }; + let mut rng = rand::thread_rng(); + let winners = targets + .as_slice() + .choose_multiple(&mut rng, winners_count as usize) + .cloned() .collect::>(); - votes14.encode_to(&mut r); - let votes15 = self - .votes15 + let mut assignments = winners .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[12usize].0.clone()), - _npos::codec::Compact(inner[12usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[13usize].0.clone()), - _npos::codec::Compact(inner[13usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) + .map(|w| sp_npos_elections::Assignment { + who: w, + distribution: <[_]>::into_vec(box [(w, PerU16::one())]), }) .collect::>(); - votes15.encode_to(&mut r); - let votes16 = self - .votes16 + let mut voters_pool = voters .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[12usize].0.clone()), - _npos::codec::Compact(inner[12usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[13usize].0.clone()), - _npos::codec::Compact(inner[13usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[14usize].0.clone()), - _npos::codec::Compact(inner[14usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) + .filter(|(x, _, z)| *x != z[0]) + .cloned() .collect::>(); - votes16.encode_to(&mut r); - r + while assignments.len() < active_voters as usize { + let voter = voters_pool.remove(rand::random::() % voters_pool.len()); + } + { + ::std::rt::begin_panic("not implemented") + } } - } - impl _npos::codec::Decode for CompactAssignments { - fn decode(value: &mut I) -> Result { - let votes1 = , - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes1 = votes1 - .into_iter() - .map(|(v, t)| (v.0, t.0)) - .collect::>(); - let votes2 = , - ( - _npos::codec::Compact, - _npos::codec::Compact, - ), - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes2 = votes2 - .into_iter() - .map(|(v, (t1, w), t2)| (v.0, (t1.0, w.0), t2.0)) - .collect::>(); - let votes3 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 3usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes3 = votes3 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes4 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 4usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes4 = votes4 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes5 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 5usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes5 = votes5 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes6 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 6usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes6 = votes6 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes7 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 7usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes7 = votes7 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes8 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 8usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes8 = votes8 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes9 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 9usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes9 = votes9 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes10 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 10usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes10 = votes10 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes11 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 11usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes11 = votes11 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes12 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 12usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes12 = votes12 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes13 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 13usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes13 = votes13 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes14 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 14usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes14 = votes14 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ((inner[12usize].0).0, (inner[12usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes15 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 15usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes15 = votes15 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ((inner[12usize].0).0, (inner[12usize].1).0), - ((inner[13usize].0).0, (inner[13usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes16 = , - [( - _npos::codec::Compact, - _npos::codec::Compact, - ); 16usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes16 = votes16 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ((inner[12usize].0).0, (inner[12usize].1).0), - ((inner[13usize].0).0, (inner[13usize].1).0), - ((inner[14usize].0).0, (inner[14usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - Ok(CompactAssignments { - votes1, - votes2, - votes3, - votes4, - votes5, - votes6, - votes7, - votes8, - votes9, - votes10, - votes11, - votes12, - votes13, - votes14, - votes15, - votes16, - }) + pub enum OuterCall { + TwoPhase(::frame_support::dispatch::CallableCallFor), + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for OuterCall { + #[inline] + fn clone(&self) -> OuterCall { + match (&*self,) { + (&OuterCall::TwoPhase(ref __self_0),) => { + OuterCall::TwoPhase(::core::clone::Clone::clone(&(*__self_0))) + } + } + } + } + impl ::core::marker::StructuralPartialEq for OuterCall {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for OuterCall { + #[inline] + fn eq(&self, other: &OuterCall) -> bool { + match (&*self, &*other) { + (&OuterCall::TwoPhase(ref __self_0), &OuterCall::TwoPhase(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + } + } + #[inline] + fn ne(&self, other: &OuterCall) -> bool { + match (&*self, &*other) { + (&OuterCall::TwoPhase(ref __self_0), &OuterCall::TwoPhase(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + } + } } - } - pub struct CompactAssignments { - votes1: Vec<(VoterIndex, TargetIndex)>, - votes2: Vec<(VoterIndex, (TargetIndex, OffchainAccuracy), TargetIndex)>, - votes3: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 2usize], - TargetIndex, - )>, - votes4: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 3usize], - TargetIndex, - )>, - votes5: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 4usize], - TargetIndex, - )>, - votes6: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 5usize], - TargetIndex, - )>, - votes7: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 6usize], - TargetIndex, - )>, - votes8: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 7usize], - TargetIndex, - )>, - votes9: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 8usize], - TargetIndex, - )>, - votes10: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 9usize], - TargetIndex, - )>, - votes11: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 10usize], - TargetIndex, - )>, - votes12: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 11usize], - TargetIndex, - )>, - votes13: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 12usize], - TargetIndex, - )>, - votes14: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 13usize], - TargetIndex, - )>, - votes15: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 14usize], - TargetIndex, - )>, - votes16: Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 15usize], - TargetIndex, - )>, - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for CompactAssignments { - #[inline] - fn default() -> CompactAssignments { - CompactAssignments { - votes1: ::core::default::Default::default(), - votes2: ::core::default::Default::default(), - votes3: ::core::default::Default::default(), - votes4: ::core::default::Default::default(), - votes5: ::core::default::Default::default(), - votes6: ::core::default::Default::default(), - votes7: ::core::default::Default::default(), - votes8: ::core::default::Default::default(), - votes9: ::core::default::Default::default(), - votes10: ::core::default::Default::default(), - votes11: ::core::default::Default::default(), - votes12: ::core::default::Default::default(), - votes13: ::core::default::Default::default(), - votes14: ::core::default::Default::default(), - votes15: ::core::default::Default::default(), - votes16: ::core::default::Default::default(), - } - } - } - impl ::core::marker::StructuralPartialEq for CompactAssignments {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for CompactAssignments { - #[inline] - fn eq(&self, other: &CompactAssignments) -> bool { - match *other { - CompactAssignments { - votes1: ref __self_1_0, - votes2: ref __self_1_1, - votes3: ref __self_1_2, - votes4: ref __self_1_3, - votes5: ref __self_1_4, - votes6: ref __self_1_5, - votes7: ref __self_1_6, - votes8: ref __self_1_7, - votes9: ref __self_1_8, - votes10: ref __self_1_9, - votes11: ref __self_1_10, - votes12: ref __self_1_11, - votes13: ref __self_1_12, - votes14: ref __self_1_13, - votes15: ref __self_1_14, - votes16: ref __self_1_15, - } => match *self { - CompactAssignments { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - && (*__self_0_3) == (*__self_1_3) - && (*__self_0_4) == (*__self_1_4) - && (*__self_0_5) == (*__self_1_5) - && (*__self_0_6) == (*__self_1_6) - && (*__self_0_7) == (*__self_1_7) - && (*__self_0_8) == (*__self_1_8) - && (*__self_0_9) == (*__self_1_9) - && (*__self_0_10) == (*__self_1_10) - && (*__self_0_11) == (*__self_1_11) - && (*__self_0_12) == (*__self_1_12) - && (*__self_0_13) == (*__self_1_13) - && (*__self_0_14) == (*__self_1_14) - && (*__self_0_15) == (*__self_1_15) + impl ::core::marker::StructuralEq for OuterCall {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for OuterCall { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq< + ::frame_support::dispatch::CallableCallFor, + >; + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for OuterCall { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + OuterCall::TwoPhase(ref aa) => { + dest.push_byte(0usize as u8); + dest.push(aa); + } + _ => (), } - }, + } + } + impl _parity_scale_codec::EncodeLike for OuterCall {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for OuterCall { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(OuterCall::TwoPhase({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err( + "Error decoding field OuterCall :: TwoPhase.0".into() + ) + } + Ok(a) => a, + } + })), + x => Err("No such variant in enum OuterCall".into()), + } + } + } + }; + impl core::fmt::Debug for OuterCall { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::TwoPhase(ref a0) => { + fmt.debug_tuple("OuterCall::TwoPhase").field(a0).finish() + } + _ => Ok(()), + } } } - #[inline] - fn ne(&self, other: &CompactAssignments) -> bool { - match *other { - CompactAssignments { - votes1: ref __self_1_0, - votes2: ref __self_1_1, - votes3: ref __self_1_2, - votes4: ref __self_1_3, - votes5: ref __self_1_4, - votes6: ref __self_1_5, - votes7: ref __self_1_6, - votes8: ref __self_1_7, - votes9: ref __self_1_8, - votes10: ref __self_1_9, - votes11: ref __self_1_10, - votes12: ref __self_1_11, - votes13: ref __self_1_12, - votes14: ref __self_1_13, - votes15: ref __self_1_14, - votes16: ref __self_1_15, - } => match *self { - CompactAssignments { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) - || (*__self_0_2) != (*__self_1_2) - || (*__self_0_3) != (*__self_1_3) - || (*__self_0_4) != (*__self_1_4) - || (*__self_0_5) != (*__self_1_5) - || (*__self_0_6) != (*__self_1_6) - || (*__self_0_7) != (*__self_1_7) - || (*__self_0_8) != (*__self_1_8) - || (*__self_0_9) != (*__self_1_9) - || (*__self_0_10) != (*__self_1_10) - || (*__self_0_11) != (*__self_1_11) - || (*__self_0_12) != (*__self_1_12) - || (*__self_0_13) != (*__self_1_13) - || (*__self_0_14) != (*__self_1_14) - || (*__self_0_15) != (*__self_1_15) + impl ::frame_support::dispatch::GetDispatchInfo for OuterCall { + fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { + match self { + OuterCall::TwoPhase(call) => call.get_dispatch_info(), + } + } + } + impl ::frame_support::dispatch::GetCallMetadata for OuterCall { + fn get_call_metadata(&self) -> ::frame_support::dispatch::CallMetadata { + use ::frame_support::dispatch::GetCallName; + match self { + OuterCall::TwoPhase(call) => { + let function_name = call.get_call_name(); + let pallet_name = "TwoPhase"; + ::frame_support::dispatch::CallMetadata { + function_name, + pallet_name, + } } - }, + } + } + fn get_module_names() -> &'static [&'static str] { + &["TwoPhase"] + } + fn get_call_names(module: &str) -> &'static [&'static str] { + use ::frame_support::dispatch::{Callable, GetCallName}; + match module { + "TwoPhase" => { + <>::Call as GetCallName>::get_call_names() + } + _ => ::std::rt::begin_panic("internal error: entered unreachable code"), + } } } - } - impl ::core::marker::StructuralEq for CompactAssignments {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for CompactAssignments { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq< - Vec<(VoterIndex, (TargetIndex, OffchainAccuracy), TargetIndex)>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 2usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 3usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 4usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 5usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 6usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 7usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 8usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 9usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 10usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 11usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 12usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 13usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 14usize], - TargetIndex, - )>, - >; - let _: ::core::cmp::AssertParamIsEq< - Vec<( - VoterIndex, - [(TargetIndex, OffchainAccuracy); 15usize], - TargetIndex, - )>, - >; + impl ::frame_support::dispatch::Dispatchable for OuterCall { + type Origin = Origin; + type Trait = OuterCall; + type Info = ::frame_support::weights::DispatchInfo; + type PostInfo = ::frame_support::weights::PostDispatchInfo; + fn dispatch( + self, + origin: Origin, + ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { + if !::filter_call( + &origin, &self, + ) { + return ::frame_support::sp_std::result::Result::Err( + ::frame_support::dispatch::DispatchError::BadOrigin.into(), + ); + } + ::frame_support::traits::UnfilteredDispatchable::dispatch_bypass_filter( + self, origin, + ) } } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for CompactAssignments { - #[inline] - fn clone(&self) -> CompactAssignments { - match *self { - CompactAssignments { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => CompactAssignments { - votes1: ::core::clone::Clone::clone(&(*__self_0_0)), - votes2: ::core::clone::Clone::clone(&(*__self_0_1)), - votes3: ::core::clone::Clone::clone(&(*__self_0_2)), - votes4: ::core::clone::Clone::clone(&(*__self_0_3)), - votes5: ::core::clone::Clone::clone(&(*__self_0_4)), - votes6: ::core::clone::Clone::clone(&(*__self_0_5)), - votes7: ::core::clone::Clone::clone(&(*__self_0_6)), - votes8: ::core::clone::Clone::clone(&(*__self_0_7)), - votes9: ::core::clone::Clone::clone(&(*__self_0_8)), - votes10: ::core::clone::Clone::clone(&(*__self_0_9)), - votes11: ::core::clone::Clone::clone(&(*__self_0_10)), - votes12: ::core::clone::Clone::clone(&(*__self_0_11)), - votes13: ::core::clone::Clone::clone(&(*__self_0_12)), - votes14: ::core::clone::Clone::clone(&(*__self_0_13)), - votes15: ::core::clone::Clone::clone(&(*__self_0_14)), - votes16: ::core::clone::Clone::clone(&(*__self_0_15)), - }, + impl ::frame_support::traits::UnfilteredDispatchable for OuterCall { + type Origin = Origin; + fn dispatch_bypass_filter( + self, + origin: Origin, + ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { + match self { + OuterCall::TwoPhase(call) => { + ::frame_support::traits::UnfilteredDispatchable::dispatch_bypass_filter( + call, origin, + ) + } + } } } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::fmt::Debug for CompactAssignments { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match *self { - CompactAssignments { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => { - let mut debug_trait_builder = f.debug_struct("CompactAssignments"); - let _ = debug_trait_builder.field("votes1", &&(*__self_0_0)); - let _ = debug_trait_builder.field("votes2", &&(*__self_0_1)); - let _ = debug_trait_builder.field("votes3", &&(*__self_0_2)); - let _ = debug_trait_builder.field("votes4", &&(*__self_0_3)); - let _ = debug_trait_builder.field("votes5", &&(*__self_0_4)); - let _ = debug_trait_builder.field("votes6", &&(*__self_0_5)); - let _ = debug_trait_builder.field("votes7", &&(*__self_0_6)); - let _ = debug_trait_builder.field("votes8", &&(*__self_0_7)); - let _ = debug_trait_builder.field("votes9", &&(*__self_0_8)); - let _ = debug_trait_builder.field("votes10", &&(*__self_0_9)); - let _ = debug_trait_builder.field("votes11", &&(*__self_0_10)); - let _ = debug_trait_builder.field("votes12", &&(*__self_0_11)); - let _ = debug_trait_builder.field("votes13", &&(*__self_0_12)); - let _ = debug_trait_builder.field("votes14", &&(*__self_0_13)); - let _ = debug_trait_builder.field("votes15", &&(*__self_0_14)); - let _ = debug_trait_builder.field("votes16", &&(*__self_0_15)); - debug_trait_builder.finish() - } - } - } - } - impl _npos::VotingLimit for CompactAssignments { - const LIMIT: usize = 16usize; - } - impl CompactAssignments { - /// Get the length of all the assignments that this type is encoding. This is basically - /// the same as the number of assignments, or the number of voters in total. - pub fn len(&self) -> usize { - let mut all_len = 0usize; - all_len = all_len.saturating_add(self.votes1.len()); - all_len = all_len.saturating_add(self.votes2.len()); - all_len = all_len.saturating_add(self.votes3.len()); - all_len = all_len.saturating_add(self.votes4.len()); - all_len = all_len.saturating_add(self.votes5.len()); - all_len = all_len.saturating_add(self.votes6.len()); - all_len = all_len.saturating_add(self.votes7.len()); - all_len = all_len.saturating_add(self.votes8.len()); - all_len = all_len.saturating_add(self.votes9.len()); - all_len = all_len.saturating_add(self.votes10.len()); - all_len = all_len.saturating_add(self.votes11.len()); - all_len = all_len.saturating_add(self.votes12.len()); - all_len = all_len.saturating_add(self.votes13.len()); - all_len = all_len.saturating_add(self.votes14.len()); - all_len = all_len.saturating_add(self.votes15.len()); - all_len = all_len.saturating_add(self.votes16.len()); - all_len - } - /// Get the total count of edges. - pub fn edge_count(&self) -> usize { - let mut all_edges = 0usize; - all_edges = all_edges.saturating_add(self.votes1.len().saturating_mul(1usize as usize)); - all_edges = all_edges.saturating_add(self.votes2.len().saturating_mul(2usize as usize)); - all_edges = all_edges.saturating_add(self.votes3.len().saturating_mul(3usize as usize)); - all_edges = all_edges.saturating_add(self.votes4.len().saturating_mul(4usize as usize)); - all_edges = all_edges.saturating_add(self.votes5.len().saturating_mul(5usize as usize)); - all_edges = all_edges.saturating_add(self.votes6.len().saturating_mul(6usize as usize)); - all_edges = all_edges.saturating_add(self.votes7.len().saturating_mul(7usize as usize)); - all_edges = all_edges.saturating_add(self.votes8.len().saturating_mul(8usize as usize)); - all_edges = all_edges.saturating_add(self.votes9.len().saturating_mul(9usize as usize)); - all_edges = - all_edges.saturating_add(self.votes10.len().saturating_mul(10usize as usize)); - all_edges = - all_edges.saturating_add(self.votes11.len().saturating_mul(11usize as usize)); - all_edges = - all_edges.saturating_add(self.votes12.len().saturating_mul(12usize as usize)); - all_edges = - all_edges.saturating_add(self.votes13.len().saturating_mul(13usize as usize)); - all_edges = - all_edges.saturating_add(self.votes14.len().saturating_mul(14usize as usize)); - all_edges = - all_edges.saturating_add(self.votes15.len().saturating_mul(15usize as usize)); - all_edges = - all_edges.saturating_add(self.votes16.len().saturating_mul(16usize as usize)); - all_edges - } - /// 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. - /// - /// The resulting indices are sorted. - pub fn unique_targets(&self) -> Vec { - let mut all_targets: Vec = Vec::with_capacity(self.average_edge_count()); - let mut maybe_insert_target = |t: TargetIndex| match all_targets.binary_search(&t) { - Ok(_) => (), - Err(pos) => all_targets.insert(pos, t), - }; - self.votes1.iter().for_each(|(_, t)| { - maybe_insert_target(*t); - }); - self.votes2.iter().for_each(|(_, (t1, _), t2)| { - maybe_insert_target(*t1); - maybe_insert_target(*t2); - }); - self.votes3.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes4.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes5.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes6.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes7.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes8.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes9.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes10.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes11.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes12.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes13.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes14.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes15.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes16.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - all_targets + impl + ::frame_support::dispatch::IsSubType< + ::frame_support::dispatch::CallableCallFor, + > for OuterCall + { + #[allow(unreachable_patterns)] + fn is_sub_type( + &self, + ) -> Option<&::frame_support::dispatch::CallableCallFor> { + match *self { + OuterCall::TwoPhase(ref r) => Some(r), + _ => None, + } + } + } + impl From<::frame_support::dispatch::CallableCallFor> for OuterCall { + fn from(call: ::frame_support::dispatch::CallableCallFor) -> Self { + OuterCall::TwoPhase(call) + } + } + pub struct Origin { + caller: OriginCaller, + filter: ::frame_support::sp_std::rc::Rc< + Box::Call) -> bool>, + >, } - /// Get the average edge count. - pub fn average_edge_count(&self) -> usize { - self.edge_count().checked_div(self.len()).unwrap_or(0) + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Origin { + #[inline] + fn clone(&self) -> Origin { + match *self { + Origin { + caller: ref __self_0_0, + filter: ref __self_0_1, + } => Origin { + caller: ::core::clone::Clone::clone(&(*__self_0_0)), + filter: ::core::clone::Clone::clone(&(*__self_0_1)), + }, + } + } } - /// 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 from - /// `self.len()`. - pub fn remove_voter(&mut self, to_remove: VoterIndex) -> bool { - if let Some(idx) = self.votes1.iter().position(|(x, _)| *x == to_remove) { - self.votes1.remove(idx); - return true; - } - if let Some(idx) = self.votes2.iter().position(|(x, _, _)| *x == to_remove) { - self.votes2.remove(idx); - return true; - } - if let Some(idx) = self.votes3.iter().position(|(x, _, _)| *x == to_remove) { - self.votes3.remove(idx); - return true; - } - if let Some(idx) = self.votes4.iter().position(|(x, _, _)| *x == to_remove) { - self.votes4.remove(idx); - return true; - } - if let Some(idx) = self.votes5.iter().position(|(x, _, _)| *x == to_remove) { - self.votes5.remove(idx); - return true; - } - if let Some(idx) = self.votes6.iter().position(|(x, _, _)| *x == to_remove) { - self.votes6.remove(idx); - return true; - } - if let Some(idx) = self.votes7.iter().position(|(x, _, _)| *x == to_remove) { - self.votes7.remove(idx); - return true; - } - if let Some(idx) = self.votes8.iter().position(|(x, _, _)| *x == to_remove) { - self.votes8.remove(idx); - return true; - } - if let Some(idx) = self.votes9.iter().position(|(x, _, _)| *x == to_remove) { - self.votes9.remove(idx); - return true; - } - if let Some(idx) = self.votes10.iter().position(|(x, _, _)| *x == to_remove) { - self.votes10.remove(idx); - return true; - } - if let Some(idx) = self.votes11.iter().position(|(x, _, _)| *x == to_remove) { - self.votes11.remove(idx); - return true; - } - if let Some(idx) = self.votes12.iter().position(|(x, _, _)| *x == to_remove) { - self.votes12.remove(idx); - return true; - } - if let Some(idx) = self.votes13.iter().position(|(x, _, _)| *x == to_remove) { - self.votes13.remove(idx); - return true; - } - if let Some(idx) = self.votes14.iter().position(|(x, _, _)| *x == to_remove) { - self.votes14.remove(idx); - return true; - } - if let Some(idx) = self.votes15.iter().position(|(x, _, _)| *x == to_remove) { - self.votes15.remove(idx); - return true; - } - if let Some(idx) = self.votes16.iter().position(|(x, _, _)| *x == to_remove) { - self.votes16.remove(idx); - return true; - } - return false; - } - } - use _npos::__OrInvalidIndex; - impl CompactAssignments { - pub fn from_assignment( - assignments: Vec<_npos::Assignment>, - index_of_voter: FV, - index_of_target: FT, - ) -> Result - where - A: _npos::IdentifierT, - for<'r> FV: Fn(&'r A) -> Option, - for<'r> FT: Fn(&'r A) -> Option, - { - let mut compact: CompactAssignments = Default::default(); - for _npos::Assignment { who, distribution } in assignments { - match distribution.len() { - 0 => continue, - 1 => compact.votes1.push(( - index_of_voter(&who).or_invalid_index()?, - index_of_target(&distribution[0].0).or_invalid_index()?, - )), - 2 => compact.votes2.push(( - index_of_voter(&who).or_invalid_index()?, - ( - index_of_target(&distribution[0].0).or_invalid_index()?, - distribution[0].1, - ), - index_of_target(&distribution[1].0).or_invalid_index()?, - )), - 3usize => compact.votes3.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ], - index_of_target(&distribution[2usize].0).or_invalid_index()?, - )), - 4usize => compact.votes4.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ], - index_of_target(&distribution[3usize].0).or_invalid_index()?, - )), - 5usize => compact.votes5.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ], - index_of_target(&distribution[4usize].0).or_invalid_index()?, - )), - 6usize => compact.votes6.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ], - index_of_target(&distribution[5usize].0).or_invalid_index()?, - )), - 7usize => compact.votes7.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ], - index_of_target(&distribution[6usize].0).or_invalid_index()?, - )), - 8usize => compact.votes8.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ], - index_of_target(&distribution[7usize].0).or_invalid_index()?, - )), - 9usize => compact.votes9.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ], - index_of_target(&distribution[8usize].0).or_invalid_index()?, - )), - 10usize => compact.votes10.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ], - index_of_target(&distribution[9usize].0).or_invalid_index()?, - )), - 11usize => compact.votes11.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ], - index_of_target(&distribution[10usize].0).or_invalid_index()?, - )), - 12usize => compact.votes12.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ], - index_of_target(&distribution[11usize].0).or_invalid_index()?, - )), - 13usize => compact.votes13.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), - ], - index_of_target(&distribution[12usize].0).or_invalid_index()?, - )), - 14usize => compact.votes14.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), - ( - index_of_target(&distribution[12usize].0).or_invalid_index()?, - distribution[12usize].1, - ), - ], - index_of_target(&distribution[13usize].0).or_invalid_index()?, - )), - 15usize => compact.votes15.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), - ( - index_of_target(&distribution[12usize].0).or_invalid_index()?, - distribution[12usize].1, - ), - ( - index_of_target(&distribution[13usize].0).or_invalid_index()?, - distribution[13usize].1, - ), - ], - index_of_target(&distribution[14usize].0).or_invalid_index()?, - )), - 16usize => compact.votes16.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), + #[cfg(feature = "std")] + impl ::frame_support::sp_std::fmt::Debug for Origin { + fn fmt( + &self, + fmt: &mut ::frame_support::sp_std::fmt::Formatter, + ) -> ::frame_support::sp_std::result::Result<(), ::frame_support::sp_std::fmt::Error> { + fmt.debug_struct("Origin") + .field("caller", &self.caller) + .field("filter", &"[function ptr]") + .finish() + } + } + impl ::frame_support::traits::OriginTrait for Origin { + type Call = ::Call; + type PalletsOrigin = OriginCaller; + type AccountId = ::AccountId; + fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static) { + let f = self.filter.clone(); + self.filter = ::frame_support::sp_std::rc::Rc::new(Box::new(move |call| { + f(call) && filter(call) + })); + } + fn reset_filter(&mut self) { + let filter = < < Runtime as frame_system :: Trait > :: BaseCallFilter as :: frame_support :: traits :: Filter < < Runtime as frame_system :: Trait > :: Call > > :: filter ; + self.filter = ::frame_support::sp_std::rc::Rc::new(Box::new(filter)); + } + fn set_caller_from(&mut self, other: impl Into) { + self.caller = other.into().caller + } + fn filter_call(&self, call: &Self::Call) -> bool { + (self.filter)(call) + } + fn caller(&self) -> &Self::PalletsOrigin { + &self.caller + } + /// Create with system none origin and `frame-system::Trait::BaseCallFilter`. + fn none() -> Self { + frame_system::RawOrigin::None.into() + } + /// Create with system root origin and no filter. + fn root() -> Self { + frame_system::RawOrigin::Root.into() + } + /// Create with system signed origin and `frame-system::Trait::BaseCallFilter`. + fn signed(by: ::AccountId) -> Self { + frame_system::RawOrigin::Signed(by).into() + } + } + #[allow(non_camel_case_types)] + pub enum OriginCaller { + system(frame_system::Origin), + #[allow(dead_code)] + Void(::frame_support::Void), + } + #[automatically_derived] + #[allow(unused_qualifications)] + #[allow(non_camel_case_types)] + impl ::core::clone::Clone for OriginCaller { + #[inline] + fn clone(&self) -> OriginCaller { + match (&*self,) { + (&OriginCaller::system(ref __self_0),) => { + OriginCaller::system(::core::clone::Clone::clone(&(*__self_0))) + } + (&OriginCaller::Void(ref __self_0),) => { + OriginCaller::Void(::core::clone::Clone::clone(&(*__self_0))) + } + } + } + } + #[allow(non_camel_case_types)] + impl ::core::marker::StructuralPartialEq for OriginCaller {} + #[automatically_derived] + #[allow(unused_qualifications)] + #[allow(non_camel_case_types)] + impl ::core::cmp::PartialEq for OriginCaller { + #[inline] + fn eq(&self, other: &OriginCaller) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), + &OriginCaller::system(ref __self_0), + &OriginCaller::system(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), ( - index_of_target(&distribution[12usize].0).or_invalid_index()?, - distribution[12usize].1, - ), + &OriginCaller::Void(ref __self_0), + &OriginCaller::Void(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => unsafe { ::core::intrinsics::unreachable() }, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &OriginCaller) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { ( - index_of_target(&distribution[13usize].0).or_invalid_index()?, - distribution[13usize].1, - ), + &OriginCaller::system(ref __self_0), + &OriginCaller::system(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), ( - index_of_target(&distribution[14usize].0).or_invalid_index()?, - distribution[14usize].1, - ), - ], - index_of_target(&distribution[15usize].0).or_invalid_index()?, - )), - _ => { - return Err(_npos::Error::CompactTargetOverflow); + &OriginCaller::Void(ref __self_0), + &OriginCaller::Void(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => unsafe { ::core::intrinsics::unreachable() }, + } + } else { + true + } + } + } + } + #[allow(non_camel_case_types)] + impl ::core::marker::StructuralEq for OriginCaller {} + #[automatically_derived] + #[allow(unused_qualifications)] + #[allow(non_camel_case_types)] + impl ::core::cmp::Eq for OriginCaller { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq<::frame_support::Void>; + } + } + } + impl core::fmt::Debug for OriginCaller { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::system(ref a0) => { + fmt.debug_tuple("OriginCaller::system").field(a0).finish() + } + Self::Void(ref a0) => fmt.debug_tuple("OriginCaller::Void").field(a0).finish(), + _ => Ok(()), + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for OriginCaller { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + OriginCaller::system(ref aa) => { + dest.push_byte(0usize as u8); + dest.push(aa); + } + OriginCaller::Void(ref aa) => { + dest.push_byte(1usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for OriginCaller {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for OriginCaller { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(OriginCaller::system({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err( + "Error decoding field OriginCaller :: system.0".into() + ) + } + Ok(a) => a, + } + })), + x if x == 1usize as u8 => Ok(OriginCaller::Void({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field OriginCaller :: Void.0".into()) + } + Ok(a) => a, + } + })), + x => Err("No such variant in enum OriginCaller".into()), + } + } + } + }; + #[allow(dead_code)] + impl Origin { + /// Create with system none origin and `frame-system::Trait::BaseCallFilter`. + pub fn none() -> Self { + ::none() + } + /// Create with system root origin and no filter. + pub fn root() -> Self { + ::root() + } + /// Create with system signed origin and `frame-system::Trait::BaseCallFilter`. + pub fn signed(by: ::AccountId) -> Self { + ::signed(by) + } + } + impl From> for OriginCaller { + fn from(x: frame_system::Origin) -> Self { + OriginCaller::system(x) + } + } + impl From> for Origin { + /// Convert to runtime origin: + /// * root origin is built with no filter + /// * others use `frame-system::Trait::BaseCallFilter` + fn from(x: frame_system::Origin) -> Self { + let o: OriginCaller = x.into(); + o.into() + } + } + impl From for Origin { + fn from(x: OriginCaller) -> Self { + let mut o = Origin { + caller: x, + filter: ::frame_support::sp_std::rc::Rc::new(Box::new(|_| true)), + }; + if !match o.caller { + OriginCaller::system(frame_system::Origin::::Root) => true, + _ => false, + } { + ::frame_support::traits::OriginTrait::reset_filter(&mut o); + } + o + } + } + impl Into<::frame_support::sp_std::result::Result, Origin>> + for Origin + { + /// NOTE: converting to pallet origin loses the origin filter information. + fn into( + self, + ) -> ::frame_support::sp_std::result::Result, Self> { + if let OriginCaller::system(l) = self.caller { + Ok(l) + } else { + Err(self) + } + } + } + impl From::AccountId>> for Origin { + /// Convert to runtime origin with caller being system signed or none and use filter + /// `frame-system::Trait::BaseCallFilter`. + fn from(x: Option<::AccountId>) -> Self { + >::from(x).into() + } + } + impl frame_system::Trait for Runtime { + type BaseCallFilter = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = OuterCall; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = (); + type MaximumBlockWeight = (); + type DbWeight = (); + type BlockExecutionWeight = (); + type ExtrinsicBaseWeight = (); + type MaximumExtrinsicWeight = (); + type MaximumBlockLength = (); + type AvailableBlockRatio = (); + type Version = (); + type PalletInfo = (); + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + } + pub struct ExistentialDeposit; + impl ExistentialDeposit { + /// Returns the value of this parameter type. + pub const fn get() -> u64 { + 1 + } + } + impl> ::frame_support::traits::Get for ExistentialDeposit { + fn get() -> I { + I::from(1) + } + } + impl pallet_balances::Trait for Runtime { + type Balance = Balance; + type Event = (); + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type MaxLocks = (); + type WeightInfo = (); + } + use paste::paste; + const SIGNED_PHASE: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(10) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const UNSIGNED_PHASE: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(5) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const MAX_SIGNED_SUBMISSIONS: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(5) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const TARGETS: ::std::thread::LocalKey>> = { + #[inline] + fn __init() -> RefCell> { + RefCell::new(<[_]>::into_vec(box [10, 20, 30, 40])) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell>> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner>> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const VOTERS: ::std::thread::LocalKey< + RefCell)>>, + > = { + #[inline] + fn __init() -> RefCell)>> { + RefCell::new(<[_]>::into_vec(box [ + (1, 10, <[_]>::into_vec(box [10, 20])), + (2, 10, <[_]>::into_vec(box [30, 40])), + (3, 10, <[_]>::into_vec(box [40])), + (4, 10, <[_]>::into_vec(box [10, 20, 30, 40])), + (10, 10, <[_]>::into_vec(box [10])), + (20, 20, <[_]>::into_vec(box [20])), + (30, 30, <[_]>::into_vec(box [30])), + (40, 40, <[_]>::into_vec(box [40])), + ])) + } + unsafe fn __getit( + ) -> ::std::option::Option<&'static RefCell)>>> + { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner< + RefCell)>>, + > = ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const DESIRED_TARGETS: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(2) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const SIGNED_DEPOSIT_BASE: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(5) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const SIGNED_REWARD_BASE: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(7) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const MAX_UNSIGNED_ITERATIONS: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(5) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const UNSIGNED_PRIORITY: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(100) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + const SOLUTION_IMPROVEMENT_THRESHOLD: ::std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(Perbill::zero()) + } + unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { + #[thread_local] + #[cfg(all( + target_thread_local, + not(all(target_arch = "wasm32", not(target_feature = "atomics"))), + ))] + static __KEY: ::std::thread::__FastLocalKeyInner> = + ::std::thread::__FastLocalKeyInner::new(); + #[allow(unused_unsafe)] + unsafe { + __KEY.get(__init) + } + } + unsafe { ::std::thread::LocalKey::new(__getit) } + }; + pub struct SignedPhase; + impl Get for SignedPhase { + fn get() -> u64 { + SIGNED_PHASE.with(|v| v.borrow().clone()) + } + } + pub struct UnsignedPhase; + impl Get for UnsignedPhase { + fn get() -> u64 { + UNSIGNED_PHASE.with(|v| v.borrow().clone()) + } + } + pub struct MaxSignedSubmissions; + impl Get for MaxSignedSubmissions { + fn get() -> u32 { + MAX_SIGNED_SUBMISSIONS.with(|v| v.borrow().clone()) + } + } + pub struct Targets; + impl Get> for Targets { + fn get() -> Vec { + TARGETS.with(|v| v.borrow().clone()) + } + } + pub struct Voters; + impl Get)>> for Voters { + fn get() -> Vec<(AccountId, VoteWeight, Vec)> { + VOTERS.with(|v| v.borrow().clone()) + } + } + pub struct DesiredTargets; + impl Get for DesiredTargets { + fn get() -> u32 { + DESIRED_TARGETS.with(|v| v.borrow().clone()) + } + } + pub struct SignedDepositBase; + impl Get for SignedDepositBase { + fn get() -> Balance { + SIGNED_DEPOSIT_BASE.with(|v| v.borrow().clone()) + } + } + pub struct SignedRewardBase; + impl Get for SignedRewardBase { + fn get() -> Balance { + SIGNED_REWARD_BASE.with(|v| v.borrow().clone()) + } + } + pub struct MaxUnsignedIterations; + impl Get for MaxUnsignedIterations { + fn get() -> u32 { + MAX_UNSIGNED_ITERATIONS.with(|v| v.borrow().clone()) + } + } + pub struct UnsignedPriority; + impl Get for UnsignedPriority { + fn get() -> u64 { + UNSIGNED_PRIORITY.with(|v| v.borrow().clone()) + } + } + pub struct SolutionImprovementThreshold; + impl Get for SolutionImprovementThreshold { + fn get() -> Perbill { + SOLUTION_IMPROVEMENT_THRESHOLD.with(|v| v.borrow().clone()) + } + } + impl crate::two_phase::Trait for Runtime { + type Event = (); + type Currency = Balances; + type SignedPhase = SignedPhase; + type UnsignedPhase = UnsignedPhase; + type MaxSignedSubmissions = MaxSignedSubmissions; + type SignedRewardBase = SignedRewardBase; + type SignedRewardFactor = (); + type SignedRewardMax = (); + type SignedDepositBase = SignedDepositBase; + type SignedDepositByte = (); + type SignedDepositWeight = (); + type SolutionImprovementThreshold = SolutionImprovementThreshold; + type SlashHandler = (); + type RewardHandler = (); + type UnsignedMaxIterations = MaxUnsignedIterations; + type UnsignedPriority = UnsignedPriority; + type ElectionDataProvider = StakingMock; + type WeightInfo = (); + } + impl frame_system::offchain::SendTransactionTypes for Runtime + where + OuterCall: From, + { + type OverarchingCall = OuterCall; + type Extrinsic = Extrinsic; + } + pub type Extrinsic = sp_runtime::testing::TestXt; + pub struct ExtBuilder {} + impl Default for ExtBuilder { + fn default() -> Self { + Self {} + } + } + pub struct StakingMock; + impl ElectionDataProvider for StakingMock { + type CompactSolution = TestCompact; + fn targets() -> Vec { + Targets::get() + } + fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { + Voters::get() + } + fn desired_targets() -> u32 { + DesiredTargets::get() + } + fn feasibility_check_assignment( + _: &AccountId, + _: &[(AccountId, P)], + ) -> bool { + true + } + fn next_election_prediction(now: u64) -> u64 { + now + 20 - now % 20 + } + } + impl ExtBuilder { + pub fn max_signed_submission(self, count: u32) -> Self { + MAX_SIGNED_SUBMISSIONS.with(|v| *v.borrow_mut() = count); + self + } + pub fn unsigned_priority(self, p: u64) -> Self { + UNSIGNED_PRIORITY.with(|v| *v.borrow_mut() = p); + self + } + pub fn solution_improvement_threshold(self, p: Perbill) -> Self { + SOLUTION_IMPROVEMENT_THRESHOLD.with(|v| *v.borrow_mut() = p); + self + } + pub fn desired_targets(self, t: u32) -> Self { + DESIRED_TARGETS.with(|v| *v.borrow_mut() = t); + self + } + pub fn add_voter( + self, + who: AccountId, + stake: Balance, + targets: Vec, + ) -> Self { + VOTERS.with(|v| v.borrow_mut().push((who, stake, targets))); + self + } + pub fn build(self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut storage = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + let _ = pallet_balances::GenesisConfig:: { + balances: <[_]>::into_vec(box [(99, 100), (999, 100), (9999, 100)]), + } + .assimilate_storage(&mut storage); + sp_io::TestExternalities::from(storage) + } + pub fn build_offchainify( + self, + iters: u32, + ) -> (sp_io::TestExternalities, Arc>) { + let mut ext = self.build(); + let (offchain, offchain_state) = TestOffchainExt::new(); + let (pool, pool_state) = TestTransactionPoolExt::new(); + let mut seed = [0_u8; 32]; + seed[0..4].copy_from_slice(&iters.to_le_bytes()); + offchain_state.write().seed = seed; + ext.register_extension(OffchainExt::new(offchain)); + ext.register_extension(TransactionPoolExt::new(pool)); + (ext, pool_state) + } + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(test) + } + } + } + #[macro_use] + pub(crate) mod macros { + //! Some helper macros for this crate. + } + pub mod signed { + //! The signed phase implementation. + use crate::two_phase::*; + use codec::Encode; + use sp_arithmetic::traits::SaturatedConversion; + use sp_npos_elections::is_score_better; + use sp_runtime::Perbill; + impl Module + where + ExtendedBalance: From>>, + { + /// Start the signed phase. + /// + /// Upon calling this, auxillary data for election is stored and signed solutions will be + /// accepted. + /// + /// The signed phase must always start before the unsigned phase. + pub fn start_signed_phase() { + let targets = T::ElectionDataProvider::targets(); + let voters = T::ElectionDataProvider::voters(); + let desired_targets = T::ElectionDataProvider::desired_targets(); + >::put(targets); + >::put(voters); + DesiredTargets::put(desired_targets); + } + /// Finish the singed phase. Process the signed submissions from best to worse until a valid one + /// is found, rewarding the best oen and slashing the invalid ones along the way. + /// + /// Returns true if we have a good solution in the signed phase. + /// + /// This drains the [`SignedSubmissions`], potentially storing the best valid one in + /// [`QueuedSolution`]. + pub fn finalize_signed_phase() -> bool { + let mut all_submission: Vec> = + >::take(); + let mut found_solution = false; + while let Some(best) = all_submission.pop() { + let SignedSubmission { + solution, + who, + deposit, + reward, + } = best; + match Self::feasibility_check(solution, ElectionCompute::Signed) { + Ok(ready_solution) => { + >::put(ready_solution); + let _remaining = T::Currency::unreserve(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic( + "assertion failed: _remaining.is_zero()", + ) + } + }; + }; + let positive_imbalance = T::Currency::deposit_creating(&who, reward); + T::RewardHandler::on_unbalanced(positive_imbalance); + found_solution = true; + break; + } + Err(_) => { + let (negative_imbalance, _remaining) = + T::Currency::slash_reserved(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic( + "assertion failed: _remaining.is_zero()", + ) + } + }; + }; + T::SlashHandler::on_unbalanced(negative_imbalance); + } + } + } + all_submission.into_iter().for_each(|not_processed| { + let SignedSubmission { who, deposit, .. } = not_processed; + let _remaining = T::Currency::unreserve(&who, deposit); + if true { + if !_remaining.is_zero() { + { + ::std::rt::begin_panic("assertion failed: _remaining.is_zero()") + } + }; + }; + }); + found_solution + } + /// Find a proper position in the queue for the signed queue, whilst maintaining the order of + /// solution quality. + /// + /// The length of the queue will always be kept less than or equal to `T::MaxSignedSubmissions`. + pub fn insert_submission( + who: &T::AccountId, + queue: &mut Vec, CompactOf>>, + solution: RawSolution>, + ) -> Option { + let outcome = queue + .iter() + .enumerate() + .rev() + .find_map(|(i, s)| { + if is_score_better::( + solution.score, + s.solution.score, + T::SolutionImprovementThreshold::get(), + ) { + Some(i + 1) + } else { + None + } + }) + .or(Some(0)) + .and_then(|at| { + if at == 0 && queue.len() as u32 >= T::MaxSignedSubmissions::get() { + None + } else { + let reward = Self::reward_for(&solution); + let deposit = Self::deposit_for(&solution); + let submission = SignedSubmission { + who: who.clone(), + deposit, + reward, + solution, + }; + queue.insert(at, submission); + if queue.len() as u32 > T::MaxSignedSubmissions::get() { + queue.remove(0); + Some(at - 1) + } else { + Some(at) + } + } + }); + if true { + if !(queue.len() as u32 <= T::MaxSignedSubmissions::get()) { + { + :: std :: rt :: begin_panic ( "assertion failed: queue.len() as u32 <= T::MaxSignedSubmissions::get()" ) + } + }; + }; + outcome + } + /// Collect sufficient deposit to store this solution this chain. + /// + /// The deposit is composed of 3 main elements: + /// + /// 1. base deposit, fixed for all submissions. + /// 2. a per-byte deposit, for renting the state usage. + /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize + pub fn deposit_for(solution: &RawSolution>) -> BalanceOf { + let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); + let feasibility_weight = T::WeightInfo::feasibility_check(); + let len_deposit = T::SignedDepositByte::get() * encoded_len; + let weight_deposit = + T::SignedDepositWeight::get() * feasibility_weight.saturated_into(); + T::SignedDepositBase::get() + len_deposit + weight_deposit + } + /// The reward for this solution, if successfully chosen as the best one at the end of the + /// signed phase. + pub fn reward_for(solution: &RawSolution>) -> BalanceOf { + T::SignedRewardBase::get() + + T::SignedRewardFactor::get() + * solution.score[0].saturated_into::>() + } + } + #[cfg(test)] + mod tests { + use super::{mock::*, *}; + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const cannot_submit_too_early: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::signed::tests::cannot_submit_too_early"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(cannot_submit_too_early())), + }; + fn cannot_submit_too_early() { + ExtBuilder::default().build_and_execute(|| { + roll_to(2); + { + match (&TwoPhase::current_phase(), &Phase::Off) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + TwoPhase::start_signed_phase(); + let solution = raw_solution(); + let h = ::frame_support::storage_root(); + { + match ( + &TwoPhase::submit(Origin::signed(10), solution), + &Err(PalletError::::EarlySubmission.into()), + ) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&h, &::frame_support::storage_root()) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const should_pay_deposit: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::signed::tests::should_pay_deposit"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(should_pay_deposit())), + }; + fn should_pay_deposit() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let solution = raw_solution(); + { + match (&balances(&99), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + { + match (&balances(&99), &(95, 5)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&TwoPhase::signed_submissions().first().unwrap().deposit, &5) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const good_solution_is_rewarded: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::good_solution_is_rewarded", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn( + || test::assert_test_result(good_solution_is_rewarded()), + ), + }; + fn good_solution_is_rewarded() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let solution = raw_solution(); + { + match (&balances(&99), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + { + match (&balances(&99), &(95, 5)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::finalize_signed_phase() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::finalize_signed_phase()", + ) + } + }; + { + match (&balances(&99), &(100 + 7, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const bad_solution_is_slashed: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::signed::tests::bad_solution_is_slashed"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(bad_solution_is_slashed())), + }; + fn bad_solution_is_slashed() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let mut solution = raw_solution(); + { + match (&balances(&99), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + solution.score[0] += 1; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + { + match (&balances(&99), &(95, 5)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !!TwoPhase::finalize_signed_phase() { + { + ::std::rt::begin_panic( + "assertion failed: !TwoPhase::finalize_signed_phase()", + ) + } + }; + { + match (&balances(&99), &(95, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const suppressed_solution_gets_bond_back: test::TestDescAndFn = + test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::suppressed_solution_gets_bond_back", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(suppressed_solution_gets_bond_back()) + }), + }; + fn suppressed_solution_gets_bond_back() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let mut solution = raw_solution(); + { + match (&balances(&99), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&balances(&999), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let is = TwoPhase::submit(Origin::signed(99), solution.clone()); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + solution.score[0] -= 1; + let is = TwoPhase::submit(Origin::signed(999), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + { + match (&balances(&99), &(95, 5)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&balances(&999), &(95, 5)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::finalize_signed_phase() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::finalize_signed_phase()", + ) + } + }; + { + match (&balances(&99), &(100 + 7, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&balances(&999), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const queue_is_always_sorted: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::signed::tests::queue_is_always_sorted"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(queue_is_always_sorted())), + }; + fn queue_is_always_sorted() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let solution = RawSolution { + score: [5, 0, 0], + ..Default::default() + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + let solution = RawSolution { + score: [4, 0, 0], + ..Default::default() + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + let solution = RawSolution { + score: [6, 0, 0], + ..Default::default() + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + { + match ( + &TwoPhase::signed_submissions() + .iter() + .map(|x| x.solution.score[0]) + .collect::>(), + &<[_]>::into_vec(box [4, 5, 6]), + ) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const cannot_submit_worse_with_full_queue: test::TestDescAndFn = + test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::cannot_submit_worse_with_full_queue", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(cannot_submit_worse_with_full_queue()) + }), + }; + fn cannot_submit_worse_with_full_queue() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + for s in 0..MaxSignedSubmissions::get() { + let solution = RawSolution { + score: [(5 + s).into(), 0, 0], + ..Default::default() + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: + ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: + ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + } + let solution = RawSolution { + score: [4, 0, 0], + ..Default::default() + }; + let h = ::frame_support::storage_root(); + { + match ( + &TwoPhase::submit(Origin::signed(99), solution), + &Err("QueueFull".into()), + ) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&h, &::frame_support::storage_root()) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const weakest_is_removed_if_better_provided: test::TestDescAndFn = + test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::weakest_is_removed_if_better_provided", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(weakest_is_removed_if_better_provided()) + }), + }; + fn weakest_is_removed_if_better_provided() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + for s in 0..MaxSignedSubmissions::get() { + let solution = RawSolution { + score: [(5 + s).into(), 0, 0], + ..Default::default() + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: + ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: + ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + } + { + match ( + &TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + &<[_]>::into_vec(box [5, 6, 7, 8, 9]), + ) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let solution = RawSolution { + score: [20, 0, 0], + ..Default::default() + }; + let is = TwoPhase::submit(Origin::signed(99), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + { + match ( + &TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + &<[_]>::into_vec(box [6, 7, 8, 9, 20]), + ) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const equally_good_is_not_accepted: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::equally_good_is_not_accepted", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(equally_good_is_not_accepted()) + }), + }; + fn equally_good_is_not_accepted() { + ExtBuilder :: default ( ) . max_signed_submission ( 3 ) . build_and_execute ( | | { roll_to ( 5 ) ; for i in 0 .. MaxSignedSubmissions :: get ( ) { let solution = RawSolution { score : [ ( 5 + i ) . into ( ) , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; } { match ( & TwoPhase :: signed_submissions ( ) . into_iter ( ) . map ( | s | s . solution . score [ 0 ] ) . collect :: < Vec < _ > > ( ) , & < [ _ ] > :: into_vec ( box [ 5 , 6 , 7 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 5 , 0 , 0 ] , .. Default :: default ( ) } ; let h = :: frame_support :: storage_root ( ) ; { match ( & TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) , & Err ( "QueueFull" . into ( ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; { match ( & h , & :: frame_support :: storage_root ( ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; } ) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const solutions_are_always_sorted: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::solutions_are_always_sorted", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(solutions_are_always_sorted()) + }), + }; + fn solutions_are_always_sorted() { + ExtBuilder :: default ( ) . max_signed_submission ( 3 ) . build_and_execute ( | | { let scores = | | TwoPhase :: signed_submissions ( ) . into_iter ( ) . map ( | s | s . solution . score [ 0 ] ) . collect :: < Vec < _ > > ( ) ; roll_to ( 5 ) ; let solution = RawSolution { score : [ 5 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 5 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 8 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 5 , 8 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 3 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 3 , 5 , 8 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 6 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 5 , 6 , 8 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 6 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 6 , 6 , 8 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 10 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 6 , 8 , 10 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 12 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 8 , 10 , 12 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; } ) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const all_in_one_singed_submission_scenario: test::TestDescAndFn = + test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::signed::tests::all_in_one_singed_submission_scenario", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(all_in_one_singed_submission_scenario()) + }), + }; + fn all_in_one_singed_submission_scenario() { + ExtBuilder::default().build_and_execute(|| { + roll_to(5); + { + match (&TwoPhase::current_phase(), &Phase::Signed) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&balances(&99), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&balances(&999), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&balances(&9999), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let mut solution = raw_solution(); + let is = TwoPhase::submit(Origin::signed(99), solution.clone()); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + solution.score[0] += 1; + let is = TwoPhase::submit(Origin::signed(999), solution.clone()); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + solution.score[0] -= 1; + let is = TwoPhase::submit(Origin::signed(9999), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + { + match ( + &TwoPhase::signed_submissions() + .iter() + .map(|x| x.who) + .collect::>(), + &<[_]>::into_vec(box [9999, 99, 999]), + ) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::finalize_signed_phase() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::finalize_signed_phase()", + ) + } + }; + { + match (&balances(&99), &(100 + 7, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&balances(&999), &(95, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + { + match (&balances(&9999), &(100, 0)) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + }) + } + } + } + pub mod unsigned { + //! The unsigned phase implementation. + use crate::two_phase::*; + use frame_support::{dispatch::DispatchResult, unsigned::ValidateUnsigned}; + use frame_system::offchain::SubmitTransaction; + use sp_npos_elections::{seq_phragmen, CompactSolution, ElectionResult}; + use sp_runtime::{ + offchain::storage::StorageValueRef, + traits::TrailingZeroInput, + transaction_validity::{ + InvalidTransaction, TransactionSource, TransactionValidity, + TransactionValidityError, ValidTransaction, + }, + SaturatedConversion, + }; + use sp_std::cmp::Ordering; + /// Storage key used to store the persistent offchain worker status. + pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; + /// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice + /// within a window of 5 blocks. + pub(crate) const OFFCHAIN_REPEAT: u32 = 5; + /// Default number of blocks for which the unsigned transaction should stay in the pool + pub(crate) const DEFAULT_LONGEVITY: u64 = 25; + impl Module + where + ExtendedBalance: From>>, + { + /// Min a new npos solution. + pub fn mine_solution(iters: usize) -> Result>, Error> { + let desired_targets = Self::desired_targets() as usize; + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + seq_phragmen::<_, CompactAccuracyOf>( + desired_targets, + targets, + voters, + Some((iters, 0)), + ) + .map_err(Into::into) + .and_then(Self::prepare_election_result) + } + /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which + /// is ready to be submitted to the chain. + /// + /// Will always reduce the solution as well. + pub fn prepare_election_result( + election_result: ElectionResult>, + ) -> Result>, Error> { + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + let voter_index = + |who: &T::AccountId| -> Option> { + voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < T > > > :: try_into ( i ) . ok ( ) ) + }; + let target_index = + |who: &T::AccountId| -> Option> { + targets . iter ( ) . position ( | x | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactTargetIndexOf < T > > > :: try_into ( i ) . ok ( ) ) + }; + let voter_at = + |i: crate::two_phase::CompactVoterIndexOf| -> Option { + < crate :: two_phase :: CompactVoterIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | voters . get ( i ) . map ( | ( x , _ , _ ) | x ) . cloned ( ) ) + }; + let target_at = + |i: crate::two_phase::CompactTargetIndexOf| -> Option { + < crate :: two_phase :: CompactTargetIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | targets . get ( i ) . cloned ( ) ) + }; + let stake_of = |who: &T::AccountId| -> crate::VoteWeight { + voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + }; + let ElectionResult { + assignments, + winners, + } = election_result; + let mut staked = sp_npos_elections::assignment_ratio_to_staked_normalized( + assignments, + &stake_of, + ) + .map_err::(Into::into)?; + sp_npos_elections::reduce(&mut staked); + let ratio = sp_npos_elections::assignment_staked_to_ratio_normalized(staked)?; + let compact = >::from_assignment(ratio, &voter_index, &target_index)?; + let maximum_allowed_voters = + Self::maximum_compact_len::(0, Default::default(), 0); + let compact = Self::trim_compact(compact.len() as u32, compact, &voter_index)?; + let winners = sp_npos_elections::to_without_backing(winners); + let score = compact + .clone() + .score(&winners, stake_of, voter_at, target_at)?; + Ok(RawSolution { compact, score }) + } + /// Get a random number of iterations to run the balancing in the OCW. + /// + /// Uses the offchain seed to generate a random number, maxed with `T::UnsignedMaxIterations`. + pub fn get_balancing_iters() -> usize { + match T::UnsignedMaxIterations::get() { + 0 => 0, + max @ _ => { + let seed = sp_io::offchain::random_seed(); + let random = ::decode(&mut TrailingZeroInput::new(seed.as_ref())) + .expect("input is padded with zeroes; qed") + % max.saturating_add(1); + random as usize + } + } + } + /// Greedily reduce the size of the a solution to fit into the block, w.r.t. weight. + /// + /// The weight of the solution is foremost a function of the number of voters (i.e. + /// `compact.len()`). Aside from this, the other components of the weight are invariant. The + /// number of winners shall not be changed (otherwise the solution is invalid) and the + /// `ElectionSize` is merely a representation of the total number of stakers. + /// + /// Thus, we reside to stripping away some voters. This means only changing the `compact` + /// struct. + /// + /// Note that the solution is already computed, and the winners are elected based on the merit + /// of teh entire stake in the system. Nonetheless, some of the voters will be removed further + /// down the line. + /// + /// Indeed, the score must be computed **after** this step. If this step reduces the score too + /// much, then the solution will be discarded. + pub fn trim_compact( + maximum_allowed_voters: u32, + mut compact: CompactOf, + nominator_index: FN, + ) -> Result, Error> + where + for<'r> FN: Fn(&'r T::AccountId) -> Option>, + { + match compact.len().checked_sub(maximum_allowed_voters as usize) { + Some(to_remove) if to_remove > 0 => { + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let mut voters_sorted = voters + .into_iter() + .map(|(who, stake, _)| (who.clone(), stake)) + .collect::>(); + voters_sorted.sort_by_key(|(_, y)| *y); + let mut removed = 0; + for (maybe_index, _stake) in voters_sorted + .iter() + .map(|(who, stake)| (nominator_index(&who), stake)) + { + let index = maybe_index.ok_or(Error::SnapshotUnAvailable)?; + if compact.remove_voter(index) { + removed += 1 + } + if removed >= to_remove { + break; + } + } + Ok(compact) + } + _ => Ok(compact), + } + } + /// Find the maximum `len` that a compact can have in order to fit into the block weight. + /// + /// This only returns a value between zero and `size.nominators`. + pub fn maximum_compact_len( + _winners_len: u32, + witness: WitnessData, + max_weight: Weight, + ) -> u32 { + if witness.voters < 1 { + return witness.voters; + } + let max_voters = witness.voters.max(1); + let mut voters = max_voters; + let weight_with = |_voters: u32| -> Weight { W::submit_unsigned() }; + let next_voters = + |current_weight: Weight, voters: u32, step: u32| -> Result { + match current_weight.cmp(&max_weight) { + Ordering::Less => { + let next_voters = voters.checked_add(step); + match next_voters { + Some(voters) if voters < max_voters => Ok(voters), + _ => Err(()), + } + } + Ordering::Greater => voters.checked_sub(step).ok_or(()), + Ordering::Equal => Ok(voters), + } + }; + let mut step = voters / 2; + let mut current_weight = weight_with(voters); + while step > 0 { + match next_voters(current_weight, voters, step) { + Ok(next) if next != voters => { + voters = next; + } + Err(()) => { + break; + } + Ok(next) => return next, + } + step = step / 2; + current_weight = weight_with(voters); + } + while voters + 1 <= max_voters && weight_with(voters + 1) < max_weight { + voters += 1; + } + while voters.checked_sub(1).is_some() && weight_with(voters) > max_weight { + voters -= 1; + } + if true { + if !(weight_with(voters.min(witness.voters)) <= max_weight) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &["weight_with(", ") <= "], + &match (&voters.min(witness.voters), &max_weight) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Display::fmt, + ), + ], + }, + )) + } + }; + }; + voters.min(witness.voters) + } + /// Checks if an execution of the offchain worker is permitted at the given block number, or not. + /// + /// This essentially makes sure that we don't run on previous blocks in case of a re-org, and we + /// don't run twice within a window of length [`OFFCHAIN_REPEAT`]. + /// + /// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise. + pub(crate) fn set_check_offchain_execution_status( + now: T::BlockNumber, + ) -> Result<(), &'static str> { + let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); + let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); + let mutate_stat = storage.mutate::<_, &'static str, _>( + |maybe_head: Option>| match maybe_head { + Some(Some(head)) if now < head => Err("fork."), + Some(Some(head)) if now >= head && now <= head + threshold => { + Err("recently executed.") + } + Some(Some(head)) if now > head + threshold => Ok(now), + _ => Ok(now), + }, + ); + match mutate_stat { + Ok(Ok(_)) => Ok(()), + Ok(Err(_)) => Err("failed to write to offchain db."), + Err(why) => Err(why), + } + } + /// Mine a new solution, and submit it back to the chian as an unsigned transaction. + pub(crate) fn mine_and_submit() -> Result<(), Error> { + let balancing = Self::get_balancing_iters(); + Self::mine_solution(balancing).and_then(|raw_solution| { + let call = Call::submit_unsigned(raw_solution).into(); + SubmitTransaction::>::submit_unsigned_transaction(call) + .map_err(|_| Error::PoolSubmissionFailed) + }) + } + pub(crate) fn pre_dispatch_checks( + solution: &RawSolution>, + ) -> DispatchResult { + { + if !Self::current_phase().is_unsigned_open() { + { + return Err(PalletError::::EarlySubmission.into()); + }; + } + }; + { + if !Self::queued_solution().map_or(true, |q: ReadySolution<_>| { + is_score_better::( + solution.score, + q.score, + T::SolutionImprovementThreshold::get(), + ) + }) { + { + return Err(PalletError::::WeakSubmission.into()); + }; + } + }; + Ok(()) + } + } + #[allow(deprecated)] + impl ValidateUnsigned for Module + where + ExtendedBalance: From>>, + { + type Call = Call; + fn validate_unsigned( + source: TransactionSource, + call: &Self::Call, + ) -> TransactionValidity { + if let Call::submit_unsigned(solution) = call { + match source { + TransactionSource::Local | TransactionSource::InBlock => {} + _ => { + return InvalidTransaction::Call.into(); + } + } + if let Err(_why) = Self::pre_dispatch_checks(solution) { + return InvalidTransaction::Custom(99).into(); } + ValidTransaction::with_tag_prefix("OffchainElection") + .priority( + T::UnsignedPriority::get() + .saturating_add(solution.score[0].saturated_into()), + ) + .longevity(DEFAULT_LONGEVITY) + .propagate(false) + .build() + } else { + InvalidTransaction::Call.into() + } + } + fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { + if let Call::submit_unsigned(solution) = call { + Self::pre_dispatch_checks(solution) + .map_err(|_| InvalidTransaction::Custom(99).into()) + } else { + Err(InvalidTransaction::Call.into()) } } - Ok(compact) } - pub fn into_assignment( - self, - voter_at: impl Fn(VoterIndex) -> Option, - target_at: impl Fn(TargetIndex) -> Option, - ) -> Result>, _npos::Error> { - let mut assignments: Vec<_npos::Assignment> = Default::default(); - for (voter_index, target_index) in self.votes1 { - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: <[_]>::into_vec(box [( - target_at(target_index).or_invalid_index()?, - OffchainAccuracy::one(), - )]), + #[cfg(test)] + mod tests { + use super::{mock::*, *}; + use frame_support::traits::OffchainWorker; + use sp_runtime::PerU16; + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const validate_unsigned_retracts_wrong_phase: test::TestDescAndFn = + test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::unsigned::tests::validate_unsigned_retracts_wrong_phase", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(validate_unsigned_retracts_wrong_phase()) + }), + }; + fn validate_unsigned_retracts_wrong_phase() { + ExtBuilder :: default ( ) . build_and_execute ( | | { let solution = RawSolution :: < TestCompact > { score : [ 5 , 0 , 0 ] , .. Default :: default ( ) } ; let call = Call :: submit_unsigned ( solution . clone ( ) ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Off ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; match < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; match < TwoPhase as ValidateUnsigned > :: pre_dispatch ( & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; roll_to ( 5 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Signed ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; match < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; match < TwoPhase as ValidateUnsigned > :: pre_dispatch ( & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; roll_to ( 15 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Unsigned ( ( true , 15 ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; if ! < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: ::validate_unsigned(TransactionSource::Local,\n &call).is_ok()" ) } } ; if ! < TwoPhase as ValidateUnsigned > :: pre_dispatch ( & call ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: ::pre_dispatch(&call).is_ok()" ) } } ; } ) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const validate_unsigned_retracts_low_score: test::TestDescAndFn = + test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::unsigned::tests::validate_unsigned_retracts_low_score", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(validate_unsigned_retracts_low_score()) + }), + }; + fn validate_unsigned_retracts_low_score() { + ExtBuilder :: default ( ) . build_and_execute ( | | { roll_to ( 15 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Unsigned ( ( true , 15 ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution :: < TestCompact > { score : [ 5 , 0 , 0 ] , .. Default :: default ( ) } ; let call = Call :: submit_unsigned ( solution . clone ( ) ) ; if ! < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: ::validate_unsigned(TransactionSource::Local,\n &call).is_ok()" ) } } ; if ! < TwoPhase as ValidateUnsigned > :: pre_dispatch ( & call ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: ::pre_dispatch(&call).is_ok()" ) } } ; let ready = ReadySolution { score : [ 10 , 0 , 0 ] , .. Default :: default ( ) } ; < QueuedSolution < Runtime > > :: put ( ready ) ; match < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; match < TwoPhase as ValidateUnsigned > :: pre_dispatch ( & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; } ) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const priority_is_set: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::unsigned::tests::priority_is_set"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(priority_is_set())), + }; + fn priority_is_set() { + ExtBuilder :: default ( ) . unsigned_priority ( 20 ) . build_and_execute ( | | { roll_to ( 15 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Unsigned ( ( true , 15 ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution :: < TestCompact > { score : [ 5 , 0 , 0 ] , .. Default :: default ( ) } ; let call = Call :: submit_unsigned ( solution . clone ( ) ) ; { match ( & < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . unwrap ( ) . priority , & 25 ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; } ) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const invalid_solution_panics : test :: TestDescAndFn = test :: TestDescAndFn { desc : test :: TestDesc { name : test :: StaticTestName ( "two_phase::unsigned::tests::invalid_solution_panics" ) , ignore : false , allow_fail : false , should_panic : test :: ShouldPanic :: YesWithMessage ( "Invalid unsigned submission must produce invalid block and deprive validator from their authoring reward.: FeasibilityError::WrongWinnerCount" ) , test_type : test :: TestType :: UnitTest , } , testfn : test :: StaticTestFn ( | | test :: assert_test_result ( invalid_solution_panics ( ) ) ) , } ; + #[should_panic( + expected = "Invalid unsigned submission must produce invalid block and deprive \ + validator from their authoring reward.: FeasibilityError::WrongWinnerCount" + )] + fn invalid_solution_panics() { + ExtBuilder::default().build_and_execute(|| { + use frame_support::dispatch::Dispatchable; + roll_to(15); + { + match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let solution = RawSolution:: { + score: [5, 0, 0], + ..Default::default() + }; + let call = Call::submit_unsigned(solution.clone()); + let outer_call: OuterCall = call.into(); + let _ = outer_call.dispatch(Origin::none()); + }) + } + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const miner_works: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName("two_phase::unsigned::tests::miner_works"), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(miner_works())), + }; + fn miner_works() { + ExtBuilder::default().build_and_execute(|| { + roll_to(15); + { + match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + if !TwoPhase::snapshot_voters().is_some() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::snapshot_voters().is_some()", + ) + } + }; + if !TwoPhase::snapshot_targets().is_some() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::snapshot_targets().is_some()", + ) + } + }; + { + match (&TwoPhase::desired_targets(), &2) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let solution = TwoPhase::mine_solution(2).unwrap(); + if !TwoPhase::queued_solution().is_none() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::queued_solution().is_none()", + ) + } + }; + let is = TwoPhase::submit_unsigned(Origin::none(), solution); + match is { + Ok(_) => (), + _ => { + if !false { + { + ::std::rt::begin_panic_fmt( + &::core::fmt::Arguments::new_v1_formatted( + &["Expected Ok(_). Got "], + &match (&is,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + &[::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }], + ), + ) + } + } + } + }; + if !TwoPhase::queued_solution().is_some() { + { + ::std::rt::begin_panic( + "assertion failed: TwoPhase::queued_solution().is_some()", + ) + } + }; }) } - for (voter_index, (t1_idx, p1), t2_idx) in self.votes2 { - if p1 >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p2 = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - p1, - ); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: <[_]>::into_vec(box [ - (target_at(t1_idx).or_invalid_index()?, p1), - (target_at(t2_idx).or_invalid_index()?, p2), - ]), - }); - } - for (voter_index, inners, t_last_idx) in self.votes3 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes4 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes5 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes6 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes7 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes8 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes9 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes10 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes11 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes12 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes13 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const ocw_will_only_submit_if_feasible: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::unsigned::tests::ocw_will_only_submit_if_feasible", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(ocw_will_only_submit_if_feasible()) + }), + }; + fn ocw_will_only_submit_if_feasible() {} + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const can_only_submit_threshold_better: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::unsigned::tests::can_only_submit_threshold_better", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(can_only_submit_threshold_better()) + }), + }; + fn can_only_submit_threshold_better() { + ExtBuilder :: default ( ) . desired_targets ( 1 ) . add_voter ( 7 , 2 , < [ _ ] > :: into_vec ( box [ 10 ] ) ) . add_voter ( 8 , 5 , < [ _ ] > :: into_vec ( box [ 10 ] ) ) . solution_improvement_threshold ( Perbill :: from_percent ( 50 ) ) . build_and_execute ( | | { roll_to ( 15 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Unsigned ( ( true , 15 ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; { match ( & TwoPhase :: desired_targets ( ) , & 1 ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let result = ElectionResult { winners : < [ _ ] > :: into_vec ( box [ ( 10 , 10 ) ] ) , assignments : < [ _ ] > :: into_vec ( box [ Assignment { who : 10 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } ] ) , } ; let is = TwoPhase :: submit_unsigned ( Origin :: none ( ) , TwoPhase :: prepare_election_result ( result ) . unwrap ( ) ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & TwoPhase :: queued_solution ( ) . unwrap ( ) . score [ 0 ] , & 10 ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let result = ElectionResult { winners : < [ _ ] > :: into_vec ( box [ ( 10 , 12 ) ] ) , assignments : < [ _ ] > :: into_vec ( box [ Assignment { who : 10 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } , Assignment { who : 7 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } ] ) , } ; let solution = TwoPhase :: prepare_election_result ( result ) . unwrap ( ) ; { match ( & solution . score [ 0 ] , & 12 ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let h = :: frame_support :: storage_root ( ) ; { match ( & TwoPhase :: submit_unsigned ( Origin :: none ( ) , solution ) , & Err ( PalletError :: < Runtime > :: WeakSubmission . into ( ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; { match ( & h , & :: frame_support :: storage_root ( ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let result = ElectionResult { winners : < [ _ ] > :: into_vec ( box [ ( 10 , 12 ) ] ) , assignments : < [ _ ] > :: into_vec ( box [ Assignment { who : 10 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } , Assignment { who : 7 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } , Assignment { who : 8 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } ] ) , } ; let solution = TwoPhase :: prepare_election_result ( result ) . unwrap ( ) ; { match ( & solution . score [ 0 ] , & 17 ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let is = TwoPhase :: submit_unsigned ( Origin :: none ( ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; } ) } - for (voter_index, inners, t_last_idx) in self.votes14 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const ocw_check_prevent_duplicate: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::unsigned::tests::ocw_check_prevent_duplicate", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(ocw_check_prevent_duplicate()) + }), + }; + fn ocw_check_prevent_duplicate() { + let (mut ext, _) = ExtBuilder::default().build_offchainify(0); + ext . execute_with ( | | { roll_to ( 15 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Unsigned ( ( true , 15 ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; if ! TwoPhase :: set_check_offchain_execution_status ( 15 ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status(15).is_ok()" ) } } ; if ! TwoPhase :: set_check_offchain_execution_status ( 16 ) . is_err ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status(16).is_err()" ) } } ; if ! TwoPhase :: set_check_offchain_execution_status ( ( 16 + OFFCHAIN_REPEAT ) . into ( ) ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status((16 +\n OFFCHAIN_REPEAT).into()).is_ok()" ) } } ; if ! TwoPhase :: set_check_offchain_execution_status ( ( 16 + OFFCHAIN_REPEAT - 3 ) . into ( ) ) . is_err ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status((16 + OFFCHAIN_REPEAT -\n 3).into()).is_err()" ) } } ; if ! TwoPhase :: set_check_offchain_execution_status ( ( 16 + OFFCHAIN_REPEAT - 2 ) . into ( ) ) . is_err ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status((16 + OFFCHAIN_REPEAT -\n 2).into()).is_err()" ) } } ; if ! TwoPhase :: set_check_offchain_execution_status ( ( 16 + OFFCHAIN_REPEAT - 1 ) . into ( ) ) . is_err ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status((16 + OFFCHAIN_REPEAT -\n 1).into()).is_err()" ) } } ; } ) } - for (voter_index, inners, t_last_idx) in self.votes15 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const ocw_only_runs_when_signed_open_now: test::TestDescAndFn = + test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::unsigned::tests::ocw_only_runs_when_signed_open_now", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| { + test::assert_test_result(ocw_only_runs_when_signed_open_now()) + }), + }; + fn ocw_only_runs_when_signed_open_now() { + let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); + ext.execute_with(|| { + roll_to(15); + { + match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + let mut storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); + TwoPhase::offchain_worker(14); + if !pool.read().transactions.len().is_zero() { + { + ::std::rt::begin_panic( + "assertion failed: pool.read().transactions.len().is_zero()", + ) + } + }; + storage.clear(); + TwoPhase::offchain_worker(16); + if !pool.read().transactions.len().is_zero() { + { + ::std::rt::begin_panic( + "assertion failed: pool.read().transactions.len().is_zero()", + ) + } + }; + storage.clear(); + TwoPhase::offchain_worker(15); + if !!pool.read().transactions.len().is_zero() { + { + ::std::rt::begin_panic( + "assertion failed: !pool.read().transactions.len().is_zero()", + ) + } + }; + }) } - for (voter_index, inners, t_last_idx) in self.votes16 { - let mut sum = OffchainAccuracy::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= OffchainAccuracy::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - OffchainAccuracy::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); + extern crate test; + #[cfg(test)] + #[rustc_test_marker] + pub const ocw_can_submit_to_pool: test::TestDescAndFn = test::TestDescAndFn { + desc: test::TestDesc { + name: test::StaticTestName( + "two_phase::unsigned::tests::ocw_can_submit_to_pool", + ), + ignore: false, + allow_fail: false, + should_panic: test::ShouldPanic::No, + test_type: test::TestType::UnitTest, + }, + testfn: test::StaticTestFn(|| test::assert_test_result(ocw_can_submit_to_pool())), + }; + fn ocw_can_submit_to_pool() { + let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); + ext.execute_with(|| { + roll_to(15); + { + match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; + TwoPhase::offchain_worker(15); + let encoded = pool.read().transactions[0].clone(); + let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); + let call = extrinsic.call; + match call { + OuterCall::TwoPhase(Call::submit_unsigned(_)) => true, + _ => false, + }; + }) } - Ok(assignments) } } - pub enum Phase { + /// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] + /// implementer. + pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< + ::AccountId, + ::BlockNumber, + >>::CompactSolution; + /// The voter index. Derived from [`CompactOf`]. + pub type CompactVoterIndexOf = as CompactSolution>::Voter; + /// The target index. Derived from [`CompactOf`]. + pub type CompactTargetIndexOf = as CompactSolution>::Target; + /// The accuracy of the election. Derived from [`CompactOf`]. + pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; + type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + type PositiveImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::PositiveImbalance; + type NegativeImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::NegativeImbalance; + /// Current phase of the pallet. + pub enum Phase { + /// Nothing, the election is not happening. Off, + /// Signed phase is open. Signed, - Unsigned(bool), + /// Unsigned phase is open. + Unsigned((bool, Bn)), } - impl ::core::marker::StructuralPartialEq for Phase {} + impl ::core::marker::StructuralPartialEq for Phase {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Phase { + impl ::core::cmp::PartialEq for Phase { #[inline] - fn eq(&self, other: &Phase) -> bool { + fn eq(&self, other: &Phase) -> bool { { let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; @@ -4786,7 +7495,7 @@ pub mod two_phase { } } #[inline] - fn ne(&self, other: &Phase) -> bool { + fn ne(&self, other: &Phase) -> bool { { let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; @@ -4803,236 +7512,648 @@ pub mod two_phase { } } } - impl ::core::marker::StructuralEq for Phase {} + impl ::core::marker::StructuralEq for Phase {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Phase { + impl ::core::cmp::Eq for Phase { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { - let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq<(bool, Bn)>; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Phase { + #[inline] + fn clone(&self) -> Phase { + match (&*self,) { + (&Phase::Off,) => Phase::Off, + (&Phase::Signed,) => Phase::Signed, + (&Phase::Unsigned(ref __self_0),) => { + Phase::Unsigned(::core::clone::Clone::clone(&(*__self_0))) + } + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for Phase {} + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for Phase + where + Bn: _parity_scale_codec::Encode, + (bool, Bn): _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + Phase::Off => { + dest.push_byte(0usize as u8); + } + Phase::Signed => { + dest.push_byte(1usize as u8); + } + Phase::Unsigned(ref aa) => { + dest.push_byte(2usize as u8); + dest.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for Phase + where + Bn: _parity_scale_codec::Encode, + (bool, Bn): _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for Phase + where + Bn: _parity_scale_codec::Decode, + (bool, Bn): _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(Phase::Off), + x if x == 1usize as u8 => Ok(Phase::Signed), + x if x == 2usize as u8 => Ok(Phase::Unsigned({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field Phase :: Unsigned.0".into()), + Ok(a) => a, + } + })), + x => Err("No such variant in enum Phase".into()), + } + } + } + }; + impl core::fmt::Debug for Phase + where + Bn: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::Off => fmt.debug_tuple("Phase::Off").finish(), + Self::Signed => fmt.debug_tuple("Phase::Signed").finish(), + Self::Unsigned(ref a0) => fmt.debug_tuple("Phase::Unsigned").field(a0).finish(), + _ => Ok(()), + } + } + } + impl Default for Phase { + fn default() -> Self { + Phase::Off + } + } + impl Phase { + /// Weather the phase is signed or not. + pub fn is_signed(&self) -> bool { + match self { + Phase::Signed => true, + _ => false, + } + } + /// Weather the phase is unsigned or not. + pub fn is_unsigned(&self) -> bool { + match self { + Phase::Unsigned(_) => true, + _ => false, + } + } + /// Weather the phase is unsigned and open or not, with specific start. + pub fn is_unsigned_open_at(&self, at: Bn) -> bool { + match self { + Phase::Unsigned((true, real)) if *real == at => true, + _ => false, + } + } + /// Weather the phase is unsigned and open or not. + pub fn is_unsigned_open(&self) -> bool { + match self { + Phase::Unsigned((true, _)) => true, + _ => false, + } + } + /// Weather the phase is off or not. + pub fn is_off(&self) -> bool { + match self { + Phase::Off => true, + _ => false, + } + } + } + /// The type of `Computation` that provided this election data. + pub enum ElectionCompute { + /// Election was computed on-chain. + OnChain, + /// Election was computed with a signed submission. + Signed, + /// Election was computed with an unsigned submission. + Unsigned, + } + impl ::core::marker::StructuralPartialEq for ElectionCompute {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for ElectionCompute { + #[inline] + fn eq(&self, other: &ElectionCompute) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + _ => true, + } + } else { + false + } } } } + impl ::core::marker::StructuralEq for ElectionCompute {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for ElectionCompute { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + {} + } + } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::clone::Clone for Phase { + impl ::core::clone::Clone for ElectionCompute { #[inline] - fn clone(&self) -> Phase { + fn clone(&self) -> ElectionCompute { { - let _: ::core::clone::AssertParamIsClone; *self } } } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for Phase {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for ElectionCompute {} + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for ElectionCompute { + fn encode_to(&self, dest: &mut EncOut) { + match *self { + ElectionCompute::OnChain => { + dest.push_byte(0usize as u8); + } + ElectionCompute::Signed => { + dest.push_byte(1usize as u8); + } + ElectionCompute::Unsigned => { + dest.push_byte(2usize as u8); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for ElectionCompute {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for ElectionCompute { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + match input.read_byte()? { + x if x == 0usize as u8 => Ok(ElectionCompute::OnChain), + x if x == 1usize as u8 => Ok(ElectionCompute::Signed), + x if x == 2usize as u8 => Ok(ElectionCompute::Unsigned), + x => Err("No such variant in enum ElectionCompute".into()), + } + } + } + }; + impl core::fmt::Debug for ElectionCompute { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::OnChain => fmt.debug_tuple("ElectionCompute::OnChain").finish(), + Self::Signed => fmt.debug_tuple("ElectionCompute::Signed").finish(), + Self::Unsigned => fmt.debug_tuple("ElectionCompute::Unsigned").finish(), + _ => Ok(()), + } + } + } + impl Default for ElectionCompute { + fn default() -> Self { + ElectionCompute::OnChain + } + } + /// A raw, unchecked solution. + /// + /// Such a solution should never become effective in anyway before being checked by the + /// [`Module::feasibility_check`] + pub struct RawSolution { + /// Compact election edges. + compact: C, + /// The _claimed_ score of the solution. + score: ElectionScore, + } + impl ::core::marker::StructuralPartialEq for RawSolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for RawSolution { + #[inline] + fn eq(&self, other: &RawSolution) -> bool { + match *other { + RawSolution { + compact: ref __self_1_0, + score: ref __self_1_1, + } => match *self { + RawSolution { + compact: ref __self_0_0, + score: ref __self_0_1, + } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), + }, + } + } + #[inline] + fn ne(&self, other: &RawSolution) -> bool { + match *other { + RawSolution { + compact: ref __self_1_0, + score: ref __self_1_1, + } => match *self { + RawSolution { + compact: ref __self_0_0, + score: ref __self_0_1, + } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), + }, + } + } + } + impl ::core::marker::StructuralEq for RawSolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for RawSolution { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for RawSolution { + #[inline] + fn clone(&self) -> RawSolution { + match *self { + RawSolution { + compact: ref __self_0_0, + score: ref __self_0_1, + } => RawSolution { + compact: ::core::clone::Clone::clone(&(*__self_0_0)), + score: ::core::clone::Clone::clone(&(*__self_0_1)), + }, + } + } + } const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Phase { + impl _parity_scale_codec::Encode for RawSolution + where + C: _parity_scale_codec::Encode, + C: _parity_scale_codec::Encode, + { fn encode_to(&self, dest: &mut EncOut) { - match *self { - Phase::Off => { - dest.push_byte(0usize as u8); - } - Phase::Signed => { - dest.push_byte(1usize as u8); - } - Phase::Unsigned(ref aa) => { - dest.push_byte(2usize as u8); - dest.push(aa); - } - _ => (), - } + dest.push(&self.compact); + dest.push(&self.score); } } - impl _parity_scale_codec::EncodeLike for Phase {} + impl _parity_scale_codec::EncodeLike for RawSolution + where + C: _parity_scale_codec::Encode, + C: _parity_scale_codec::Encode, + { + } }; const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Phase { + impl _parity_scale_codec::Decode for RawSolution + where + C: _parity_scale_codec::Decode, + C: _parity_scale_codec::Decode, + { fn decode( input: &mut DecIn, ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(Phase::Off), - x if x == 1usize as u8 => Ok(Phase::Signed), - x if x == 2usize as u8 => Ok(Phase::Unsigned({ + Ok(RawSolution { + compact: { let res = _parity_scale_codec::Decode::decode(input); match res { - Err(_) => return Err("Error decoding field Phase :: Unsigned.0".into()), + Err(_) => return Err("Error decoding field RawSolution.compact".into()), Ok(a) => a, } - })), - x => Err("No such variant in enum Phase".into()), - } + }, + score: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => return Err("Error decoding field RawSolution.score".into()), + Ok(a) => a, + } + }, + }) } } }; - impl core::fmt::Debug for Phase { + impl core::fmt::Debug for RawSolution + where + C: core::fmt::Debug, + { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::Off => fmt.debug_tuple("Phase::Off").finish(), - Self::Signed => fmt.debug_tuple("Phase::Signed").finish(), - Self::Unsigned(ref a0) => fmt.debug_tuple("Phase::Unsigned").field(a0).finish(), - _ => Ok(()), - } - } - } - impl Default for Phase { - fn default() -> Self { - Phase::Off + fmt.debug_struct("RawSolution") + .field("compact", &self.compact) + .field("score", &self.score) + .finish() } } - impl Phase { - pub fn is_signed(&self) -> bool { - match self { - Phase::Signed => true, - _ => false, - } - } - pub fn is_unsigned(&self) -> bool { - match self { - Phase::Unsigned(_) => true, - _ => false, - } - } - pub fn is_unsigned_open(&self) -> bool { - match self { - Phase::Unsigned(true) => true, - _ => false, - } - } - pub fn is_off(&self) -> bool { - match self { - Phase::Off => true, - _ => false, + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for RawSolution { + #[inline] + fn default() -> RawSolution { + RawSolution { + compact: ::core::default::Default::default(), + score: ::core::default::Default::default(), } } } - pub enum ElectionCompute { - OnChain, - Signed, - Unsigned, + /// A raw, unchecked signed submission. + /// + /// This is just a wrapper around [`RawSolution`] and some additional info. + pub struct SignedSubmission { + /// Who submitted this solution. + who: A, + /// The deposit reserved for storing this solution. + deposit: B, + /// The reward that should be given to this solution, if chosen the as the final one. + reward: B, + /// The raw solution itself. + solution: RawSolution, } - impl ::core::marker::StructuralPartialEq for ElectionCompute {} + impl ::core::marker::StructuralPartialEq for SignedSubmission {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for ElectionCompute { + impl< + A: ::core::cmp::PartialEq, + B: ::core::cmp::PartialEq + HasCompact, + C: ::core::cmp::PartialEq, + > ::core::cmp::PartialEq for SignedSubmission + { #[inline] - fn eq(&self, other: &ElectionCompute) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - _ => true, + fn eq(&self, other: &SignedSubmission) -> bool { + match *other { + SignedSubmission { + who: ref __self_1_0, + deposit: ref __self_1_1, + reward: ref __self_1_2, + solution: ref __self_1_3, + } => match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + && (*__self_0_3) == (*__self_1_3) } - } else { - false - } + }, + } + } + #[inline] + fn ne(&self, other: &SignedSubmission) -> bool { + match *other { + SignedSubmission { + who: ref __self_1_0, + deposit: ref __self_1_1, + reward: ref __self_1_2, + solution: ref __self_1_3, + } => match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) + || (*__self_0_2) != (*__self_1_2) + || (*__self_0_3) != (*__self_1_3) + } + }, } } } - impl ::core::marker::StructuralEq for ElectionCompute {} + impl ::core::marker::StructuralEq for SignedSubmission {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq for ElectionCompute { + impl ::core::cmp::Eq + for SignedSubmission + { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { - {} + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq>; + } } } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::clone::Clone for ElectionCompute { + impl< + A: ::core::clone::Clone, + B: ::core::clone::Clone + HasCompact, + C: ::core::clone::Clone, + > ::core::clone::Clone for SignedSubmission + { #[inline] - fn clone(&self) -> ElectionCompute { - { - *self + fn clone(&self) -> SignedSubmission { + match *self { + SignedSubmission { + who: ref __self_0_0, + deposit: ref __self_0_1, + reward: ref __self_0_2, + solution: ref __self_0_3, + } => SignedSubmission { + who: ::core::clone::Clone::clone(&(*__self_0_0)), + deposit: ::core::clone::Clone::clone(&(*__self_0_1)), + reward: ::core::clone::Clone::clone(&(*__self_0_2)), + solution: ::core::clone::Clone::clone(&(*__self_0_3)), + }, } } } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for ElectionCompute {} const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for ElectionCompute { + impl _parity_scale_codec::Encode for SignedSubmission + where + A: _parity_scale_codec::Encode, + A: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + { fn encode_to(&self, dest: &mut EncOut) { - match *self { - ElectionCompute::OnChain => { - dest.push_byte(0usize as u8); - } - ElectionCompute::Signed => { - dest.push_byte(1usize as u8); - } - ElectionCompute::Unsigned => { - dest.push_byte(2usize as u8); - } - _ => (), - } + dest.push(&self.who); + dest.push(&self.deposit); + dest.push(&self.reward); + dest.push(&self.solution); } } - impl _parity_scale_codec::EncodeLike for ElectionCompute {} + impl _parity_scale_codec::EncodeLike for SignedSubmission + where + A: _parity_scale_codec::Encode, + A: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + { + } }; const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for ElectionCompute { + impl _parity_scale_codec::Decode for SignedSubmission + where + A: _parity_scale_codec::Decode, + A: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + RawSolution: _parity_scale_codec::Decode, + RawSolution: _parity_scale_codec::Decode, + { fn decode( input: &mut DecIn, ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(ElectionCompute::OnChain), - x if x == 1usize as u8 => Ok(ElectionCompute::Signed), - x if x == 2usize as u8 => Ok(ElectionCompute::Unsigned), - x => Err("No such variant in enum ElectionCompute".into()), - } + Ok(SignedSubmission { + who: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.who".into()) + } + Ok(a) => a, + } + }, + deposit: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.deposit".into()) + } + Ok(a) => a, + } + }, + reward: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.reward".into()) + } + Ok(a) => a, + } + }, + solution: { + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field SignedSubmission.solution".into()) + } + Ok(a) => a, + } + }, + }) } } }; - impl core::fmt::Debug for ElectionCompute { + impl core::fmt::Debug for SignedSubmission + where + A: core::fmt::Debug, + B: core::fmt::Debug, + C: core::fmt::Debug, + { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::OnChain => fmt.debug_tuple("ElectionCompute::OnChain").finish(), - Self::Signed => fmt.debug_tuple("ElectionCompute::Signed").finish(), - Self::Unsigned => fmt.debug_tuple("ElectionCompute::Unsigned").finish(), - _ => Ok(()), - } + fmt.debug_struct("SignedSubmission") + .field("who", &self.who) + .field("deposit", &self.deposit) + .field("reward", &self.reward) + .field("solution", &self.solution) + .finish() } } - pub struct RawSolution { - winners: Vec, - compact: CompactAssignments, + /// A checked and parsed solution, ready to be enacted. + pub struct ReadySolution { + /// The final supports of the solution. This is target-major vector, storing each winners, total + /// backing, and each individual backer. + supports: Supports, + /// The score of the solution. + /// + /// This is needed to potentially challenge the solution. score: ElectionScore, + /// How this election was computed. + compute: ElectionCompute, } - impl ::core::marker::StructuralPartialEq for RawSolution {} + impl ::core::marker::StructuralPartialEq for ReadySolution {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for RawSolution { + impl ::core::cmp::PartialEq for ReadySolution { #[inline] - fn eq(&self, other: &RawSolution) -> bool { + fn eq(&self, other: &ReadySolution) -> bool { match *other { - RawSolution { - winners: ref __self_1_0, - compact: ref __self_1_1, - score: ref __self_1_2, + ReadySolution { + supports: ref __self_1_0, + score: ref __self_1_1, + compute: ref __self_1_2, } => match *self { - RawSolution { - winners: ref __self_0_0, - compact: ref __self_0_1, - score: ref __self_0_2, + ReadySolution { + supports: ref __self_0_0, + score: ref __self_0_1, + compute: ref __self_0_2, } => { (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1) @@ -5042,17 +8163,17 @@ pub mod two_phase { } } #[inline] - fn ne(&self, other: &RawSolution) -> bool { + fn ne(&self, other: &ReadySolution) -> bool { match *other { - RawSolution { - winners: ref __self_1_0, - compact: ref __self_1_1, - score: ref __self_1_2, + ReadySolution { + supports: ref __self_1_0, + score: ref __self_1_1, + compute: ref __self_1_2, } => match *self { - RawSolution { - winners: ref __self_0_0, - compact: ref __self_0_1, - score: ref __self_0_2, + ReadySolution { + supports: ref __self_0_0, + score: ref __self_0_1, + compute: ref __self_0_2, } => { (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1) @@ -5062,34 +8183,34 @@ pub mod two_phase { } } } - impl ::core::marker::StructuralEq for RawSolution {} + impl ::core::marker::StructuralEq for ReadySolution {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq for RawSolution { + impl ::core::cmp::Eq for ReadySolution { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq>; let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; } } } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::clone::Clone for RawSolution { + impl ::core::clone::Clone for ReadySolution { #[inline] - fn clone(&self) -> RawSolution { + fn clone(&self) -> ReadySolution { match *self { - RawSolution { - winners: ref __self_0_0, - compact: ref __self_0_1, - score: ref __self_0_2, - } => RawSolution { - winners: ::core::clone::Clone::clone(&(*__self_0_0)), - compact: ::core::clone::Clone::clone(&(*__self_0_1)), - score: ::core::clone::Clone::clone(&(*__self_0_2)), + ReadySolution { + supports: ref __self_0_0, + score: ref __self_0_1, + compute: ref __self_0_2, + } => ReadySolution { + supports: ::core::clone::Clone::clone(&(*__self_0_0)), + score: ::core::clone::Clone::clone(&(*__self_0_1)), + compute: ::core::clone::Clone::clone(&(*__self_0_2)), }, } } @@ -5098,42 +8219,59 @@ pub mod two_phase { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for RawSolution { + impl _parity_scale_codec::Encode for ReadySolution + where + Supports: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, + { fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.winners); - dest.push(&self.compact); + dest.push(&self.supports); dest.push(&self.score); + dest.push(&self.compute); } } - impl _parity_scale_codec::EncodeLike for RawSolution {} + impl _parity_scale_codec::EncodeLike for ReadySolution + where + Supports: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, + { + } }; const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for RawSolution { + impl _parity_scale_codec::Decode for ReadySolution + where + Supports: _parity_scale_codec::Decode, + Supports: _parity_scale_codec::Decode, + { fn decode( input: &mut DecIn, ) -> core::result::Result { - Ok(RawSolution { - winners: { + Ok(ReadySolution { + supports: { let res = _parity_scale_codec::Decode::decode(input); match res { - Err(_) => return Err("Error decoding field RawSolution.winners".into()), + Err(_) => { + return Err("Error decoding field ReadySolution.supports".into()) + } Ok(a) => a, } }, - compact: { + score: { let res = _parity_scale_codec::Decode::decode(input); match res { - Err(_) => return Err("Error decoding field RawSolution.compact".into()), + Err(_) => return Err("Error decoding field ReadySolution.score".into()), Ok(a) => a, } }, - score: { + compute: { let res = _parity_scale_codec::Decode::decode(input); match res { - Err(_) => return Err("Error decoding field RawSolution.score".into()), + Err(_) => { + return Err("Error decoding field ReadySolution.compute".into()) + } Ok(a) => a, } }, @@ -5141,404 +8279,428 @@ pub mod two_phase { } } }; - impl core::fmt::Debug for RawSolution { + impl core::fmt::Debug for ReadySolution + where + A: core::fmt::Debug, + { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("RawSolution") - .field("winners", &self.winners) - .field("compact", &self.compact) + fmt.debug_struct("ReadySolution") + .field("supports", &self.supports) .field("score", &self.score) + .field("compute", &self.compute) .finish() } } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::default::Default for RawSolution { + impl ::core::default::Default for ReadySolution { #[inline] - fn default() -> RawSolution { - RawSolution { - winners: ::core::default::Default::default(), - compact: ::core::default::Default::default(), + fn default() -> ReadySolution { + ReadySolution { + supports: ::core::default::Default::default(), score: ::core::default::Default::default(), + compute: ::core::default::Default::default(), } } } - pub struct SignedSubmission { - who: AccountId, - deposit: Balance, - reward: Balance, - solution: RawSolution, - } - impl ::core::marker::StructuralPartialEq - for SignedSubmission - { + /// Witness data about the size of the election. + /// + /// This is needed for proper weight calculation. + pub struct WitnessData { + /// Number of all voters. + /// + /// This must match the on-chain snapshot. + #[codec(compact)] + voters: u32, + /// Number of all targets. + /// + /// This must match the on-chain snapshot. + #[codec(compact)] + targets: u32, } + impl ::core::marker::StructuralPartialEq for WitnessData {} #[automatically_derived] #[allow(unused_qualifications)] - impl - ::core::cmp::PartialEq for SignedSubmission - { + impl ::core::cmp::PartialEq for WitnessData { #[inline] - fn eq(&self, other: &SignedSubmission) -> bool { + fn eq(&self, other: &WitnessData) -> bool { match *other { - SignedSubmission { - who: ref __self_1_0, - deposit: ref __self_1_1, - reward: ref __self_1_2, - solution: ref __self_1_3, + WitnessData { + voters: ref __self_1_0, + targets: ref __self_1_1, } => match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - && (*__self_0_3) == (*__self_1_3) - } + WitnessData { + voters: ref __self_0_0, + targets: ref __self_0_1, + } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), }, } } #[inline] - fn ne(&self, other: &SignedSubmission) -> bool { + fn ne(&self, other: &WitnessData) -> bool { match *other { - SignedSubmission { - who: ref __self_1_0, - deposit: ref __self_1_1, - reward: ref __self_1_2, - solution: ref __self_1_3, + WitnessData { + voters: ref __self_1_0, + targets: ref __self_1_1, } => match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) - || (*__self_0_2) != (*__self_1_2) - || (*__self_0_3) != (*__self_1_3) - } + WitnessData { + voters: ref __self_0_0, + targets: ref __self_0_1, + } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), }, } } } - impl ::core::marker::StructuralEq - for SignedSubmission - { - } + impl ::core::marker::StructuralEq for WitnessData {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq - for SignedSubmission - { + impl ::core::cmp::Eq for WitnessData { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; } } } #[automatically_derived] #[allow(unused_qualifications)] - impl - ::core::clone::Clone for SignedSubmission - { + impl ::core::clone::Clone for WitnessData { #[inline] - fn clone(&self) -> SignedSubmission { - match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => SignedSubmission { - who: ::core::clone::Clone::clone(&(*__self_0_0)), - deposit: ::core::clone::Clone::clone(&(*__self_0_1)), - reward: ::core::clone::Clone::clone(&(*__self_0_2)), - solution: ::core::clone::Clone::clone(&(*__self_0_3)), - }, + fn clone(&self) -> WitnessData { + { + let _: ::core::clone::AssertParamIsClone; + let _: ::core::clone::AssertParamIsClone; + *self } } } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for WitnessData {} const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode - for SignedSubmission - where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - { + impl _parity_scale_codec::Encode for WitnessData { fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.who); - dest.push(&self.deposit); - dest.push(&self.reward); - dest.push(&self.solution); + { + dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . voters ) ) ; + } + { + dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . targets ) ) ; + } } } - impl _parity_scale_codec::EncodeLike - for SignedSubmission - where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - Balance: _parity_scale_codec::Encode, - { - } + impl _parity_scale_codec::EncodeLike for WitnessData {} }; const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode - for SignedSubmission - where - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - Balance: _parity_scale_codec::Decode, - Balance: _parity_scale_codec::Decode, - Balance: _parity_scale_codec::Decode, - Balance: _parity_scale_codec::Decode, - { + impl _parity_scale_codec::Decode for WitnessData { fn decode( input: &mut DecIn, ) -> core::result::Result { - Ok(SignedSubmission { - who: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.who".into()) - } - Ok(a) => a, - } - }, - deposit: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.deposit".into()) - } - Ok(a) => a, - } - }, - reward: { - let res = _parity_scale_codec::Decode::decode(input); + Ok(WitnessData { + voters: { + let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.reward".into()) - } - Ok(a) => a, + Err(_) => return Err("Error decoding field WitnessData.voters".into()), + Ok(a) => a.into(), } }, - solution: { - let res = _parity_scale_codec::Decode::decode(input); + targets: { + let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.solution".into()) - } - Ok(a) => a, + Err(_) => return Err("Error decoding field WitnessData.targets".into()), + Ok(a) => a.into(), } }, }) } } }; - impl core::fmt::Debug for SignedSubmission - where - AccountId: core::fmt::Debug, - Balance: core::fmt::Debug, - { + impl core::fmt::Debug for WitnessData { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("SignedSubmission") - .field("who", &self.who) - .field("deposit", &self.deposit) - .field("reward", &self.reward) - .field("solution", &self.solution) + fmt.debug_struct("WitnessData") + .field("voters", &self.voters) + .field("targets", &self.targets) .finish() } } - /// A parsed solution, ready to be enacted. - pub struct ReadySolution { - winners: Vec, - supports: Supports, + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for WitnessData { + #[inline] + fn default() -> WitnessData { + WitnessData { + voters: ::core::default::Default::default(), + targets: ::core::default::Default::default(), + } + } + } + /// The crate errors. Note that this is different from the [`PalletError`]. + pub enum Error { + /// A feasibility error. + Feasibility(FeasibilityError), + /// An error in the on-chain fallback. + OnChainFallback(crate::onchain::Error), + /// An internal error in the NPoS elections crate. + NposElections(sp_npos_elections::Error), + /// Snapshot data was unavailable unexpectedly. + SnapshotUnAvailable, + /// Submitting a transaction to the pool failed. + /// + /// This can only happen in the unsigned phase. + PoolSubmissionFailed, + } + impl core::fmt::Debug for Error { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::Feasibility(ref a0) => { + fmt.debug_tuple("Error::Feasibility").field(a0).finish() + } + Self::OnChainFallback(ref a0) => { + fmt.debug_tuple("Error::OnChainFallback").field(a0).finish() + } + Self::NposElections(ref a0) => { + fmt.debug_tuple("Error::NposElections").field(a0).finish() + } + Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), + Self::PoolSubmissionFailed => { + fmt.debug_tuple("Error::PoolSubmissionFailed").finish() + } + _ => Ok(()), + } + } + } + impl ::core::marker::StructuralEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + impl ::core::marker::StructuralPartialEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + ( + &Error::OnChainFallback(ref __self_0), + &Error::OnChainFallback(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + ( + &Error::NposElections(ref __self_0), + &Error::NposElections(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + ( + &Error::OnChainFallback(ref __self_0), + &Error::OnChainFallback(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + ( + &Error::NposElections(ref __self_0), + &Error::NposElections(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => false, + } + } else { + true + } + } + } + } + impl From for Error { + fn from(e: crate::onchain::Error) -> Self { + Error::OnChainFallback(e) + } + } + impl From for Error { + fn from(e: sp_npos_elections::Error) -> Self { + Error::NposElections(e) + } + } + /// Errors that can happen in the feasibility check. + pub enum FeasibilityError { + /// Wrong number of winners presented. + WrongWinnerCount, + /// The snapshot is not available. + /// + /// This must be an internal error of the chain. + SnapshotUnavailable, + /// Internal error from the election crate. + NposElectionError(sp_npos_elections::Error), + /// A vote is invalid. + InvalidVote, + /// A voter is invalid. + InvalidVoter, + /// A winner is invalid. + InvalidWinner, + /// The given score was invalid. + InvalidScore, } - impl ::core::marker::StructuralPartialEq for ReadySolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for ReadySolution { - #[inline] - fn eq(&self, other: &ReadySolution) -> bool { - match *other { - ReadySolution { - winners: ref __self_1_0, - supports: ref __self_1_1, - } => match *self { - ReadySolution { - winners: ref __self_0_0, - supports: ref __self_0_1, - } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), - }, - } - } - #[inline] - fn ne(&self, other: &ReadySolution) -> bool { - match *other { - ReadySolution { - winners: ref __self_1_0, - supports: ref __self_1_1, - } => match *self { - ReadySolution { - winners: ref __self_0_0, - supports: ref __self_0_1, - } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), - }, + impl core::fmt::Debug for FeasibilityError { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::WrongWinnerCount => fmt + .debug_tuple("FeasibilityError::WrongWinnerCount") + .finish(), + Self::SnapshotUnavailable => fmt + .debug_tuple("FeasibilityError::SnapshotUnavailable") + .finish(), + Self::NposElectionError(ref a0) => fmt + .debug_tuple("FeasibilityError::NposElectionError") + .field(a0) + .finish(), + Self::InvalidVote => fmt.debug_tuple("FeasibilityError::InvalidVote").finish(), + Self::InvalidVoter => fmt.debug_tuple("FeasibilityError::InvalidVoter").finish(), + Self::InvalidWinner => fmt.debug_tuple("FeasibilityError::InvalidWinner").finish(), + Self::InvalidScore => fmt.debug_tuple("FeasibilityError::InvalidScore").finish(), + _ => Ok(()), } } } - impl ::core::marker::StructuralEq for ReadySolution {} + impl ::core::marker::StructuralEq for FeasibilityError {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq for ReadySolution { + impl ::core::cmp::Eq for FeasibilityError { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq; } } } + impl ::core::marker::StructuralPartialEq for FeasibilityError {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::clone::Clone for ReadySolution { + impl ::core::cmp::PartialEq for FeasibilityError { #[inline] - fn clone(&self) -> ReadySolution { - match *self { - ReadySolution { - winners: ref __self_0_0, - supports: ref __self_0_1, - } => ReadySolution { - winners: ::core::clone::Clone::clone(&(*__self_0_0)), - supports: ::core::clone::Clone::clone(&(*__self_0_1)), - }, + fn eq(&self, other: &FeasibilityError) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &FeasibilityError::NposElectionError(ref __self_0), + &FeasibilityError::NposElectionError(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => true, + } + } else { + false + } } } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for ReadySolution - where - Vec: _parity_scale_codec::Encode, - Vec: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.winners); - dest.push(&self.supports); + #[inline] + fn ne(&self, other: &FeasibilityError) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &FeasibilityError::NposElectionError(ref __self_0), + &FeasibilityError::NposElectionError(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => false, + } + } else { + true + } } } - impl _parity_scale_codec::EncodeLike for ReadySolution - where - Vec: _parity_scale_codec::Encode, - Vec: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - { + } + impl From for FeasibilityError { + fn from(e: sp_npos_elections::Error) -> Self { + FeasibilityError::NposElectionError(e) } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for ReadySolution - where - Vec: _parity_scale_codec::Decode, - Vec: _parity_scale_codec::Decode, - Supports: _parity_scale_codec::Decode, - Supports: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(ReadySolution { - winners: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field ReadySolution.winners".into()) - } - Ok(a) => a, - } - }, - supports: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field ReadySolution.supports".into()) - } - Ok(a) => a, - } - }, - }) - } + } + /// The weights for this pallet. + pub trait WeightInfo { + fn feasibility_check() -> Weight; + fn submit() -> Weight; + fn submit_unsigned() -> Weight; + } + impl WeightInfo for () { + fn feasibility_check() -> Weight { + Default::default() } - }; - impl core::fmt::Debug for ReadySolution - where - AccountId: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("ReadySolution") - .field("winners", &self.winners) - .field("supports", &self.supports) - .finish() + fn submit() -> Weight { + Default::default() } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for ReadySolution { - #[inline] - fn default() -> ReadySolution { - ReadySolution { - winners: ::core::default::Default::default(), - supports: ::core::default::Default::default(), - } + fn submit_unsigned() -> Weight { + Default::default() } } - pub trait WeightInfo {} - impl WeightInfo for () {} - pub trait Trait: frame_system::Trait { - type Event: From + Into<::Event>; + pub trait Trait: frame_system::Trait + SendTransactionTypes> + where + ExtendedBalance: From>>, + { + /// Event type. + type Event: From> + Into<::Event>; + /// Currency type. type Currency: ReservableCurrency + Currency; + /// Duration of the signed phase. type SignedPhase: Get; + /// Duration of the unsigned phase. type UnsignedPhase: Get; + /// Maximum number of singed submissions that can be queued. type MaxSignedSubmissions: Get; type SignedRewardBase: Get>; type SignedRewardFactor: Get; + type SignedRewardMax: Get>>; type SignedDepositBase: Get>; type SignedDepositByte: Get>; type SignedDepositWeight: Get>; + /// The minimum amount of improvement to the solution score that defines a solution as "better". type SolutionImprovementThreshold: Get; + type UnsignedMaxIterations: Get; + type UnsignedPriority: Get; + /// Handler for the slashed deposits. type SlashHandler: OnUnbalanced>; + /// Handler for the rewards. type RewardHandler: OnUnbalanced>; + /// Something that will provide the election data. type ElectionDataProvider: ElectionDataProvider; + /// The weight of the pallet. type WeightInfo: WeightInfo; } use self::sp_api_hidden_includes_decl_storage::hidden_include::{ @@ -5550,6 +8712,7 @@ pub mod two_phase { pub extern crate frame_support as hidden_include; } trait Store { + type Round; type CurrentPhase; type SignedSubmissions; type QueuedSolution; @@ -5557,45 +8720,102 @@ pub mod two_phase { type SnapshotVoters; type DesiredTargets; } - impl Store for Module { - type CurrentPhase = CurrentPhase; + impl Store for Module + where + ExtendedBalance: From>>, + { + type Round = Round; + type CurrentPhase = CurrentPhase; type SignedSubmissions = SignedSubmissions; type QueuedSolution = QueuedSolution; type SnapshotTargets = SnapshotTargets; type SnapshotVoters = SnapshotVoters; type DesiredTargets = DesiredTargets; } - impl Module { + impl Module + where + ExtendedBalance: From>>, + { + /// Internal counter ofr the number of rounds. + /// + /// This is useful for de-duplication of transactions submitted to the pool, and general + /// diagnostics of the module. + /// + /// This is merely incremented once per every time that signed phase starts. + pub fn round() -> u32 { + < Round < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) + } /// Current phase. - pub fn current_phase() -> Phase { - < CurrentPhase < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase > > :: get ( ) + pub fn current_phase() -> Phase { + < CurrentPhase < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase < T :: BlockNumber > > > :: get ( ) } - /// Sorted list of unchecked, signed solutions. - pub fn signed_submissions() -> Vec>> { - < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > > > > > :: get ( ) + /// Sorted (worse -> best) list of unchecked, signed solutions. + pub fn signed_submissions( + ) -> Vec, CompactOf>> { + < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > > > :: get ( ) } - /// Current, best, unsigned solution. + /// Current best solution, signed or unsigned. pub fn queued_solution() -> Option> { < QueuedSolution < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < ReadySolution < T :: AccountId > > > :: get ( ) } - /// Snapshot of all Voters. The indices if this will be used in election. + /// Snapshot of all Voters. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub fn snapshot_targets() -> Option> { < SnapshotTargets < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < T :: AccountId > > > :: get ( ) } - /// Snapshot of all targets. The indices if this will be used in election. + /// Snapshot of all targets. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub fn snapshot_voters() -> Option)>> { < SnapshotVoters < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < ( T :: AccountId , VoteWeight , Vec < T :: AccountId > ) > > > :: get ( ) } - /// Desired number of targets to elect + /// Desired number of targets to elect. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub fn desired_targets() -> u32 { < DesiredTargets < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) } } #[doc(hidden)] + pub struct __GetByteStructRound( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_Round: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructRound + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_Round + .get_or_init(|| { + let def_val: u32 = 0; + ::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructRound where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructRound where + ExtendedBalance: From>> + { + } + #[doc(hidden)] pub struct __GetByteStructCurrentPhase( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T), @@ -5610,6 +8830,8 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructCurrentPhase + where + ExtendedBalance: From>>, { fn default_byte( &self, @@ -5617,14 +8839,20 @@ pub mod two_phase { use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; __CACHE_GET_BYTE_STRUCT_CurrentPhase .get_or_init(|| { - let def_val: Phase = Phase::Off; - ::encode(&def_val) + let def_val: Phase = Phase::Off; + as Encode>::encode(&def_val) }) .clone() } } - unsafe impl Send for __GetByteStructCurrentPhase {} - unsafe impl Sync for __GetByteStructCurrentPhase {} + unsafe impl Send for __GetByteStructCurrentPhase where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructCurrentPhase where + ExtendedBalance: From>> + { + } #[doc(hidden)] pub struct __GetByteStructSignedSubmissions( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< @@ -5640,22 +8868,24 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructSignedSubmissions + where + ExtendedBalance: From>>, { fn default_byte( &self, ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SignedSubmissions - .get_or_init(|| { - let def_val: Vec>> = - Default::default(); - >> as Encode>::encode(&def_val) - }) - .clone() + __CACHE_GET_BYTE_STRUCT_SignedSubmissions . get_or_init ( | | { let def_val : Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > = Default :: default ( ) ; < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > as Encode > :: encode ( & def_val ) } ) . clone ( ) } } - unsafe impl Send for __GetByteStructSignedSubmissions {} - unsafe impl Sync for __GetByteStructSignedSubmissions {} + unsafe impl Send for __GetByteStructSignedSubmissions where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructSignedSubmissions where + ExtendedBalance: From>> + { + } #[doc(hidden)] pub struct __GetByteStructQueuedSolution( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< @@ -5671,6 +8901,8 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructQueuedSolution + where + ExtendedBalance: From>>, { fn default_byte( &self, @@ -5684,8 +8916,14 @@ pub mod two_phase { .clone() } } - unsafe impl Send for __GetByteStructQueuedSolution {} - unsafe impl Sync for __GetByteStructQueuedSolution {} + unsafe impl Send for __GetByteStructQueuedSolution where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructQueuedSolution where + ExtendedBalance: From>> + { + } #[doc(hidden)] pub struct __GetByteStructSnapshotTargets( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< @@ -5701,6 +8939,8 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructSnapshotTargets + where + ExtendedBalance: From>>, { fn default_byte( &self, @@ -5714,8 +8954,14 @@ pub mod two_phase { .clone() } } - unsafe impl Send for __GetByteStructSnapshotTargets {} - unsafe impl Sync for __GetByteStructSnapshotTargets {} + unsafe impl Send for __GetByteStructSnapshotTargets where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructSnapshotTargets where + ExtendedBalance: From>> + { + } #[doc(hidden)] pub struct __GetByteStructSnapshotVoters( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< @@ -5731,6 +8977,8 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructSnapshotVoters + where + ExtendedBalance: From>>, { fn default_byte( &self, @@ -5747,8 +8995,14 @@ pub mod two_phase { .clone() } } - unsafe impl Send for __GetByteStructSnapshotVoters {} - unsafe impl Sync for __GetByteStructSnapshotVoters {} + unsafe impl Send for __GetByteStructSnapshotVoters where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructSnapshotVoters where + ExtendedBalance: From>> + { + } #[doc(hidden)] pub struct __GetByteStructDesiredTargets( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< @@ -5764,6 +9018,8 @@ pub mod two_phase { #[cfg(feature = "std")] impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructDesiredTargets + where + ExtendedBalance: From>>, { fn default_byte( &self, @@ -5777,13 +9033,22 @@ pub mod two_phase { .clone() } } - unsafe impl Send for __GetByteStructDesiredTargets {} - unsafe impl Sync for __GetByteStructDesiredTargets {} - impl Module { + unsafe impl Send for __GetByteStructDesiredTargets where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructDesiredTargets where + ExtendedBalance: From>> + { + } + impl Module + where + ExtendedBalance: From>>, + { #[doc(hidden)] pub fn storage_metadata( ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::StorageMetadata { - self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current, best, unsigned solution." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters. The indices if this will be used in election." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets. The indices if this will be used in election." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect" ] ) , } ] [ .. ] ) , } + self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Round" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructRound :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Internal counter ofr the number of rounds." , "" , " This is useful for de-duplication of transactions submitted to the pool, and general" , " diagnostics of the module." , "" , " This is merely incremented once per every time that signed phase starts." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec, CompactOf>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted (worse -> best) list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current best solution, signed or unsigned." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } ] [ .. ] ) , } } } /// Hidden instance generated to be internally used when module is used without @@ -5854,41 +9119,79 @@ pub mod two_phase { { const PREFIX: &'static str = "TwoPhaseElectionProvider"; } - /// Current phase. - pub struct CurrentPhase( + /// Internal counter ofr the number of rounds. + /// + /// This is useful for de-duplication of transactions submitted to the pool, and general + /// diagnostics of the module. + /// + /// This is merely incremented once per every time that signed phase starts. + pub struct Round( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, ); impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Phase, - > for CurrentPhase + u32, + > for Round + { + type Query = u32; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"Round" + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + v.unwrap_or_else(|| 0) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + Some(v) + } + } + /// Current phase. + pub struct CurrentPhase( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ) + where + ExtendedBalance: From>>; + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Phase, + > for CurrentPhase + where + ExtendedBalance: From>>, { - type Query = Phase; + type Query = Phase; fn module_prefix() -> &'static [u8] { < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) } fn storage_prefix() -> &'static [u8] { b"CurrentPhase" } - fn from_optional_value_to_query(v: Option) -> Self::Query { + fn from_optional_value_to_query(v: Option>) -> Self::Query { v.unwrap_or_else(|| Phase::Off) } - fn from_query_to_optional_value(v: Self::Query) -> Option { + fn from_query_to_optional_value(v: Self::Query) -> Option> { Some(v) } } - /// Sorted list of unchecked, signed solutions. + /// Sorted (worse -> best) list of unchecked, signed solutions. pub struct SignedSubmissions( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T,), >, - ); + ) + where + ExtendedBalance: From>>; impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec>>, + Vec, CompactOf>>, > for SignedSubmissions + where + ExtendedBalance: From>>, { - type Query = Vec>>; + type Query = Vec, CompactOf>>; fn module_prefix() -> &'static [u8] { < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) } @@ -5896,26 +9199,30 @@ pub mod two_phase { b"SignedSubmissions" } fn from_optional_value_to_query( - v: Option>>>, + v: Option, CompactOf>>>, ) -> Self::Query { v.unwrap_or_else(|| Default::default()) } fn from_query_to_optional_value( v: Self::Query, - ) -> Option>>> { + ) -> Option, CompactOf>>> { Some(v) } } - /// Current, best, unsigned solution. + /// Current best solution, signed or unsigned. pub struct QueuedSolution( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T,), >, - ); + ) + where + ExtendedBalance: From>>; impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< ReadySolution, > for QueuedSolution + where + ExtendedBalance: From>>, { type Query = Option>; fn module_prefix() -> &'static [u8] { @@ -5931,18 +9238,22 @@ pub mod two_phase { v } } - /// Snapshot of all Voters. The indices if this will be used in election. + /// Snapshot of all Voters. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub struct SnapshotTargets( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T,), >, - ); + ) + where + ExtendedBalance: From>>; impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< Vec, > for SnapshotTargets + where + ExtendedBalance: From>>, { type Query = Option>; fn module_prefix() -> &'static [u8] { @@ -5958,18 +9269,22 @@ pub mod two_phase { v } } - /// Snapshot of all targets. The indices if this will be used in election. + /// Snapshot of all targets. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub struct SnapshotVoters( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T,), >, - ); + ) + where + ExtendedBalance: From>>; impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< Vec<(T::AccountId, VoteWeight, Vec)>, > for SnapshotVoters + where + ExtendedBalance: From>>, { type Query = Option)>>; fn module_prefix() -> &'static [u8] { @@ -5989,7 +9304,9 @@ pub mod two_phase { v } } - /// Desired number of targets to elect + /// Desired number of targets to elect. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub struct DesiredTargets( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, ); @@ -6012,46 +9329,73 @@ pub mod two_phase { Some(v) } } + /// [`RawEvent`] specialized for the configuration [`Trait`] + /// + /// [`RawEvent`]: enum.RawEvent.html + /// [`Trait`]: trait.Trait.html + pub type Event = RawEvent<::AccountId>; /// Events for this module. /// - pub enum Event { + pub enum RawEvent { + /// A solution was stored with the given compute. + /// + /// If the solution is signed, this means that it hasn't yet been processed. If the solution + /// is unsigned, this means that it has also been processed. SolutionStored(ElectionCompute), - ElectionFinalized(ElectionCompute), + /// The election has been finalized, with `Some` of the given computation, or else if the + /// election failed, `None`. + ElectionFinalized(Option), + /// An account has been rewarded for their signed submission being finalized. + Rewarded(AccountId), + /// An account has been slashed for submitting an invalid signed submission. + Slashed(AccountId), } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::clone::Clone for Event { + impl ::core::clone::Clone for RawEvent { #[inline] - fn clone(&self) -> Event { + fn clone(&self) -> RawEvent { match (&*self,) { - (&Event::SolutionStored(ref __self_0),) => { - Event::SolutionStored(::core::clone::Clone::clone(&(*__self_0))) + (&RawEvent::SolutionStored(ref __self_0),) => { + RawEvent::SolutionStored(::core::clone::Clone::clone(&(*__self_0))) + } + (&RawEvent::ElectionFinalized(ref __self_0),) => { + RawEvent::ElectionFinalized(::core::clone::Clone::clone(&(*__self_0))) + } + (&RawEvent::Rewarded(ref __self_0),) => { + RawEvent::Rewarded(::core::clone::Clone::clone(&(*__self_0))) } - (&Event::ElectionFinalized(ref __self_0),) => { - Event::ElectionFinalized(::core::clone::Clone::clone(&(*__self_0))) + (&RawEvent::Slashed(ref __self_0),) => { + RawEvent::Slashed(::core::clone::Clone::clone(&(*__self_0))) } } } } - impl ::core::marker::StructuralPartialEq for Event {} + impl ::core::marker::StructuralPartialEq for RawEvent {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Event { + impl ::core::cmp::PartialEq for RawEvent { #[inline] - fn eq(&self, other: &Event) -> bool { + fn eq(&self, other: &RawEvent) -> bool { { let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; if true && __self_vi == __arg_1_vi { match (&*self, &*other) { ( - &Event::SolutionStored(ref __self_0), - &Event::SolutionStored(ref __arg_1_0), + &RawEvent::SolutionStored(ref __self_0), + &RawEvent::SolutionStored(ref __arg_1_0), ) => (*__self_0) == (*__arg_1_0), ( - &Event::ElectionFinalized(ref __self_0), - &Event::ElectionFinalized(ref __arg_1_0), + &RawEvent::ElectionFinalized(ref __self_0), + &RawEvent::ElectionFinalized(ref __arg_1_0), ) => (*__self_0) == (*__arg_1_0), + (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } _ => unsafe { ::core::intrinsics::unreachable() }, } } else { @@ -6060,20 +9404,26 @@ pub mod two_phase { } } #[inline] - fn ne(&self, other: &Event) -> bool { + fn ne(&self, other: &RawEvent) -> bool { { let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; if true && __self_vi == __arg_1_vi { match (&*self, &*other) { ( - &Event::SolutionStored(ref __self_0), - &Event::SolutionStored(ref __arg_1_0), + &RawEvent::SolutionStored(ref __self_0), + &RawEvent::SolutionStored(ref __arg_1_0), ) => (*__self_0) != (*__arg_1_0), ( - &Event::ElectionFinalized(ref __self_0), - &Event::ElectionFinalized(ref __arg_1_0), + &RawEvent::ElectionFinalized(ref __self_0), + &RawEvent::ElectionFinalized(ref __arg_1_0), ) => (*__self_0) != (*__arg_1_0), + (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } _ => unsafe { ::core::intrinsics::unreachable() }, } } else { @@ -6082,16 +9432,18 @@ pub mod two_phase { } } } - impl ::core::marker::StructuralEq for Event {} + impl ::core::marker::StructuralEq for RawEvent {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Event { + impl ::core::cmp::Eq for RawEvent { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; } } } @@ -6099,77 +9451,130 @@ pub mod two_phase { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Event { + impl _parity_scale_codec::Encode for RawEvent + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + { fn encode_to(&self, dest: &mut EncOut) { match *self { - Event::SolutionStored(ref aa) => { + RawEvent::SolutionStored(ref aa) => { dest.push_byte(0usize as u8); dest.push(aa); } - Event::ElectionFinalized(ref aa) => { - dest.push_byte(1usize as u8); + RawEvent::ElectionFinalized(ref aa) => { + dest.push_byte(1usize as u8); + dest.push(aa); + } + RawEvent::Rewarded(ref aa) => { + dest.push_byte(2usize as u8); + dest.push(aa); + } + RawEvent::Slashed(ref aa) => { + dest.push_byte(3usize as u8); dest.push(aa); } _ => (), } } } - impl _parity_scale_codec::EncodeLike for Event {} + impl _parity_scale_codec::EncodeLike for RawEvent + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + { + } }; const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Event { + impl _parity_scale_codec::Decode for RawEvent + where + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + { fn decode( input: &mut DecIn, ) -> core::result::Result { match input.read_byte()? { - x if x == 0usize as u8 => Ok(Event::SolutionStored({ + x if x == 0usize as u8 => Ok(RawEvent::SolutionStored({ let res = _parity_scale_codec::Decode::decode(input); match res { Err(_) => { - return Err("Error decoding field Event :: SolutionStored.0".into()) + return Err( + "Error decoding field RawEvent :: SolutionStored.0".into() + ) } Ok(a) => a, } })), - x if x == 1usize as u8 => Ok(Event::ElectionFinalized({ + x if x == 1usize as u8 => Ok(RawEvent::ElectionFinalized({ let res = _parity_scale_codec::Decode::decode(input); match res { Err(_) => { return Err( - "Error decoding field Event :: ElectionFinalized.0".into() + "Error decoding field RawEvent :: ElectionFinalized.0".into() ) } Ok(a) => a, } })), - x => Err("No such variant in enum Event".into()), + x if x == 2usize as u8 => Ok(RawEvent::Rewarded({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field RawEvent :: Rewarded.0".into()) + } + Ok(a) => a, + } + })), + x if x == 3usize as u8 => Ok(RawEvent::Slashed({ + let res = _parity_scale_codec::Decode::decode(input); + match res { + Err(_) => { + return Err("Error decoding field RawEvent :: Slashed.0".into()) + } + Ok(a) => a, + } + })), + x => Err("No such variant in enum RawEvent".into()), } } } }; - impl core::fmt::Debug for Event { + impl core::fmt::Debug for RawEvent + where + AccountId: core::fmt::Debug, + { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { match self { - Self::SolutionStored(ref a0) => { - fmt.debug_tuple("Event::SolutionStored").field(a0).finish() - } + Self::SolutionStored(ref a0) => fmt + .debug_tuple("RawEvent::SolutionStored") + .field(a0) + .finish(), Self::ElectionFinalized(ref a0) => fmt - .debug_tuple("Event::ElectionFinalized") + .debug_tuple("RawEvent::ElectionFinalized") .field(a0) .finish(), + Self::Rewarded(ref a0) => fmt.debug_tuple("RawEvent::Rewarded").field(a0).finish(), + Self::Slashed(ref a0) => fmt.debug_tuple("RawEvent::Slashed").field(a0).finish(), _ => Ok(()), } } } - impl From for () { - fn from(_: Event) -> () { + impl From> for () { + fn from(_: RawEvent) -> () { () } } - impl Event { + impl RawEvent { #[allow(dead_code)] #[doc(hidden)] pub fn metadata() -> &'static [::frame_support::event::EventMetadata] { @@ -6179,30 +9584,62 @@ pub mod two_phase { arguments: ::frame_support::event::DecodeDifferent::Encode(&[ "ElectionCompute", ]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" A solution was stored with the given compute.", + r"", + r" If the solution is signed, this means that it hasn't yet been processed. If the solution", + r" is unsigned, this means that it has also been processed.", + ]), }, ::frame_support::event::EventMetadata { name: ::frame_support::event::DecodeDifferent::Encode("ElectionFinalized"), arguments: ::frame_support::event::DecodeDifferent::Encode(&[ - "ElectionCompute", + "Option", + ]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" The election has been finalized, with `Some` of the given computation, or else if the", + r" election failed, `None`.", + ]), + }, + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("Rewarded"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" An account has been rewarded for their signed submission being finalized.", + ]), + }, + ::frame_support::event::EventMetadata { + name: ::frame_support::event::DecodeDifferent::Encode("Slashed"), + arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), + documentation: ::frame_support::event::DecodeDifferent::Encode(&[ + r" An account has been slashed for submitting an invalid signed submission.", ]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[]), }, ] } } - pub enum PalletError { + pub enum PalletError + where + ExtendedBalance: From>>, + { #[doc(hidden)] __Ignore( ::frame_support::sp_std::marker::PhantomData<(T,)>, ::frame_support::Never, ), + /// Submission was too early. EarlySubmission, + /// Submission was too weak, score-wise. + WeakSubmission, + /// The queue was full, and the solution was not better than any of the existing ones. QueueFull, - SubmissionQueuedFull, + /// The origin failed to pay the deposit. CannotPayDeposit, } - impl ::frame_support::sp_std::fmt::Debug for PalletError { + impl ::frame_support::sp_std::fmt::Debug for PalletError + where + ExtendedBalance: From>>, + { fn fmt( &self, f: &mut ::frame_support::sp_std::fmt::Formatter<'_>, @@ -6210,7 +9647,10 @@ pub mod two_phase { f.write_str(self.as_str()) } } - impl PalletError { + impl PalletError + where + ExtendedBalance: From>>, + { fn as_u8(&self) -> u8 { match self { PalletError::__Ignore(_, _) => { @@ -6225,8 +9665,8 @@ pub mod two_phase { )) } PalletError::EarlySubmission => 0, - PalletError::QueueFull => 0 + 1, - PalletError::SubmissionQueuedFull => 0 + 1 + 1, + PalletError::WeakSubmission => 0 + 1, + PalletError::QueueFull => 0 + 1 + 1, PalletError::CannotPayDeposit => 0 + 1 + 1 + 1, } } @@ -6244,18 +9684,24 @@ pub mod two_phase { )) } PalletError::EarlySubmission => "EarlySubmission", + PalletError::WeakSubmission => "WeakSubmission", PalletError::QueueFull => "QueueFull", - PalletError::SubmissionQueuedFull => "SubmissionQueuedFull", PalletError::CannotPayDeposit => "CannotPayDeposit", } } } - impl From> for &'static str { + impl From> for &'static str + where + ExtendedBalance: From>>, + { fn from(err: PalletError) -> &'static str { err.as_str() } } - impl From> for ::frame_support::sp_runtime::DispatchError { + impl From> for ::frame_support::sp_runtime::DispatchError + where + ExtendedBalance: From>>, + { fn from(err: PalletError) -> Self { let index = ::index::>() .expect("Every active module has an index in the runtime; qed") as u8; @@ -6266,32 +9712,48 @@ pub mod two_phase { } } } - impl ::frame_support::error::ModuleErrorMetadata for PalletError { + impl ::frame_support::error::ModuleErrorMetadata for PalletError + where + ExtendedBalance: From>>, + { fn metadata() -> &'static [::frame_support::error::ErrorMetadata] { &[ ::frame_support::error::ErrorMetadata { name: ::frame_support::error::DecodeDifferent::Encode("EarlySubmission"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[ + r" Submission was too early.", + ]), }, ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("QueueFull"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + name: ::frame_support::error::DecodeDifferent::Encode("WeakSubmission"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[ + r" Submission was too weak, score-wise.", + ]), }, ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("SubmissionQueuedFull"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + name: ::frame_support::error::DecodeDifferent::Encode("QueueFull"), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[ + r" The queue was full, and the solution was not better than any of the existing ones.", + ]), }, ::frame_support::error::ErrorMetadata { name: ::frame_support::error::DecodeDifferent::Encode("CannotPayDeposit"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[]), + documentation: ::frame_support::error::DecodeDifferent::Encode(&[ + r" The origin failed to pay the deposit.", + ]), }, ] } } - pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>); + pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>) + where + ExtendedBalance: From>>; #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::clone::Clone for Module { + impl ::core::clone::Clone for Module + where + ExtendedBalance: From>>, + { #[inline] fn clone(&self) -> Module { match *self { @@ -6301,11 +9763,20 @@ pub mod two_phase { } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::marker::Copy for Module {} - impl ::core::marker::StructuralPartialEq for Module {} + impl ::core::marker::Copy for Module where + ExtendedBalance: From>> + { + } + impl ::core::marker::StructuralPartialEq for Module where + ExtendedBalance: From>> + { + } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Module { + impl ::core::cmp::PartialEq for Module + where + ExtendedBalance: From>>, + { #[inline] fn eq(&self, other: &Module) -> bool { match *other { @@ -6323,10 +9794,16 @@ pub mod two_phase { } } } - impl ::core::marker::StructuralEq for Module {} + impl ::core::marker::StructuralEq for Module where + ExtendedBalance: From>> + { + } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Module { + impl ::core::cmp::Eq for Module + where + ExtendedBalance: From>>, + { #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { @@ -6339,6 +9816,7 @@ pub mod two_phase { } impl core::fmt::Debug for Module where + ExtendedBalance: From>>, T: core::fmt::Debug, { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { @@ -6347,42 +9825,45 @@ pub mod two_phase { } impl ::frame_support::traits::OnInitialize<::BlockNumber> for Module + where + ExtendedBalance: From>>, { fn on_initialize(now: T::BlockNumber) -> Weight { let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "on_initialize", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(464u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + MacroCallsite::new(&META) + }; + let mut interest = ::tracing::subscriber::Interest::never(); if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + && { + interest = CALLSITE.interest(); + !interest.is_never() + } && CALLSITE.is_enabled(interest) { - use ::tracing::__macro_support::*; - let callsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "on_initialize", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(227u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - static CALLSITE: MacroCallsite = MacroCallsite::new(&META); - CALLSITE.register(); - &CALLSITE - }; - if callsite.is_enabled() { - let meta = callsite.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - ::tracing::Span::none() - } + let meta = CALLSITE.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) } else { - ::tracing::Span::none() + let span = CALLSITE.disabled_span(); + {}; + span } }; let __tracing_guard__ = __within_span__.enter(); @@ -6394,12 +9875,65 @@ pub mod two_phase { let remaining = next_election - now; match Self::current_phase() { Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { - CurrentPhase::put(Phase::Signed); + >::put(Phase::Signed); + Round::mutate(|r| *r += 1); Self::start_signed_phase(); + { + let lvl = ::log::Level::Info; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( + ::core::fmt::Arguments::new_v1( + &["\u{1f3e6} Starting signed phase at #", " , round "], + &match (&now, &Self::round()) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Display::fmt, + ), + ], + }, + ), + lvl, + &( + crate::LOG_TARGET, + "frame_election_providers::two_phase", + "frame/election-providers/src/two_phase/mod.rs", + 488u32, + ), + ); + } + }; } Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { let found_solution = Self::finalize_signed_phase(); - CurrentPhase::put(Phase::Unsigned(!found_solution)); + >::put(Phase::Unsigned((!found_solution, now))); + { + let lvl = ::log::Level::Info; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( + ::core::fmt::Arguments::new_v1( + &["\u{1f3e6} Starting unsigned phase at #"], + &match (&now,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + )], + }, + ), + lvl, + &( + crate::LOG_TARGET, + "frame_election_providers::two_phase", + "frame/election-providers/src/two_phase/mod.rs", + 497u32, + ), + ); + } + }; } _ => {} } @@ -6407,65 +9941,122 @@ pub mod two_phase { } } } - impl ::frame_support::traits::OnRuntimeUpgrade for Module {} + impl ::frame_support::traits::OnRuntimeUpgrade for Module where + ExtendedBalance: From>> + { + } impl ::frame_support::traits::OnFinalize<::BlockNumber> for Module + where + ExtendedBalance: From>>, { } impl ::frame_support::traits::OffchainWorker<::BlockNumber> for Module + where + ExtendedBalance: From>>, { - fn offchain_worker(n: T::BlockNumber) {} + fn offchain_worker(n: T::BlockNumber) { + if Self::set_check_offchain_execution_status(n).is_ok() + && Self::current_phase().is_unsigned_open_at(n) + { + let _ = Self::mine_and_submit().map_err(|e| { + let lvl = ::log::Level::Error; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( + ::core::fmt::Arguments::new_v1( + &["\u{1f3e6} error while submitting transaction in OCW: "], + &match (&e,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + ), + lvl, + &( + crate::LOG_TARGET, + "frame_election_providers::two_phase", + "frame/election-providers/src/two_phase/mod.rs", + 514u32, + ), + ); + } + }); + } + } } - impl Module { + impl Module + where + ExtendedBalance: From>>, + { /// Deposits an event using `frame_system::Module::deposit_event`. fn deposit_event(event: impl Into<::Event>) { >::deposit_event(event.into()) } } #[cfg(feature = "std")] - impl ::frame_support::traits::IntegrityTest for Module {} + impl ::frame_support::traits::IntegrityTest for Module where + ExtendedBalance: From>> + { + } /// Can also be called using [`Call`]. /// /// [`Call`]: enum.Call.html - impl Module { + impl Module + where + ExtendedBalance: From>>, + { + /// Submit a solution for the signed phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// The solution potentially queued, based on the claimed score and processed at the end of + /// the signed phase. + /// + /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution + /// might be rewarded, slashed, or get all or a part of the deposit back. /// /// NOTE: Calling this function will bypass origin filters. - fn submit(origin: T::Origin, solution: RawSolution) -> DispatchResultWithPostInfo { + fn submit( + origin: T::Origin, + solution: RawSolution>, + ) -> DispatchResultWithPostInfo { let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "submit", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(464u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + MacroCallsite::new(&META) + }; + let mut interest = ::tracing::subscriber::Interest::never(); if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + && { + interest = CALLSITE.interest(); + !interest.is_never() + } && CALLSITE.is_enabled(interest) { - use ::tracing::__macro_support::*; - let callsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "submit", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(227u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - static CALLSITE: MacroCallsite = MacroCallsite::new(&META); - CALLSITE.register(); - &CALLSITE - }; - if callsite.is_enabled() { - let meta = callsite.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - ::tracing::Span::none() - } + let meta = CALLSITE.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) } else { - ::tracing::Span::none() + let span = CALLSITE.disabled_span(); + {}; + span } }; let __tracing_guard__ = __within_span__.enter(); @@ -6477,20 +10068,12 @@ pub mod two_phase { }; } }; - let queue_size = >::decode_len().unwrap_or_default() as u32; - { - if !(queue_size <= T::MaxSignedSubmissions::get()) { - { - return Err(PalletError::::SubmissionQueuedFull.into()); - }; - } - }; let mut signed_submissions = Self::signed_submissions(); let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution); { if !maybe_index.is_some() { { - return Err(PalletError::::QueueFull.into()); + return Err("QueueFull".into()); }; } }; @@ -6498,88 +10081,84 @@ pub mod two_phase { let deposit = signed_submissions[index].deposit; T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; if true { - { - match (&(signed_submissions.len() as u32), &(queue_size + 1)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } + if !(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()) { + { + :: std :: rt :: begin_panic ( "assertion failed: signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()" ) } }; }; >::put(signed_submissions); + Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Signed)); Ok(None.into()) } #[allow(unreachable_code)] + /// Submit a solution for the unsigned phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. + /// Moreover, this unsigned solution is only validated when submitted to the pool from the + /// local process. Effectively, this means that only active validators can submit this + /// transaction when authoring a block. + /// + /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will + /// panic if the solution submitted by the validator is invalid, effectively putting their + /// authoring reward at risk. + /// + /// No deposit or reward is associated with this. /// /// NOTE: Calling this function will bypass origin filters. fn submit_unsigned( origin: T::Origin, - solution: RawSolution, + solution: RawSolution>, ) -> ::frame_support::dispatch::DispatchResult { let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "submit_unsigned", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(464u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + MacroCallsite::new(&META) + }; + let mut interest = ::tracing::subscriber::Interest::never(); if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + && { + interest = CALLSITE.interest(); + !interest.is_never() + } && CALLSITE.is_enabled(interest) { - use ::tracing::__macro_support::*; - let callsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "submit_unsigned", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(227u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - static CALLSITE: MacroCallsite = MacroCallsite::new(&META); - CALLSITE.register(); - &CALLSITE - }; - if callsite.is_enabled() { - let meta = callsite.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - ::tracing::Span::none() - } + let meta = CALLSITE.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) } else { - ::tracing::Span::none() + let span = CALLSITE.disabled_span(); + {}; + span } }; let __tracing_guard__ = __within_span__.enter(); { ensure_none(origin)?; - { - ::std::rt::begin_panic("not implemented") - } + let _ = Self::pre_dispatch_checks(&solution)?; + let ready = Self::feasibility_check(solution, ElectionCompute::Unsigned).expect( + "Invalid unsigned submission must produce invalid block and deprive \ + validator from their authoring reward.", + ); + >::put(ready); + Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); } Ok(()) } @@ -6587,7 +10166,10 @@ pub mod two_phase { /// Dispatchable calls. /// /// Each variant of this enum maps to a dispatchable function from the associated module. - pub enum Call { + pub enum Call + where + ExtendedBalance: From>>, + { #[doc(hidden)] #[codec(skip)] __PhantomItem( @@ -6595,15 +10177,45 @@ pub mod two_phase { ::frame_support::Never, ), #[allow(non_camel_case_types)] - submit(RawSolution), + /// Submit a solution for the signed phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// The solution potentially queued, based on the claimed score and processed at the end of + /// the signed phase. + /// + /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution + /// might be rewarded, slashed, or get all or a part of the deposit back. + submit(RawSolution>), #[allow(non_camel_case_types)] - submit_unsigned(RawSolution), + /// Submit a solution for the unsigned phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. + /// Moreover, this unsigned solution is only validated when submitted to the pool from the + /// local process. Effectively, this means that only active validators can submit this + /// transaction when authoring a block. + /// + /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will + /// panic if the solution submitted by the validator is invalid, effectively putting their + /// authoring reward at risk. + /// + /// No deposit or reward is associated with this. + submit_unsigned(RawSolution>), } const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Call { + impl _parity_scale_codec::Encode for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + { fn encode_to(&self, dest: &mut EncOut) { match *self { Call::submit(ref aa) => { @@ -6618,13 +10230,28 @@ pub mod two_phase { } } } - impl _parity_scale_codec::EncodeLike for Call {} + impl _parity_scale_codec::EncodeLike for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + { + } }; const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Call { + impl _parity_scale_codec::Decode for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + { fn decode( input: &mut DecIn, ) -> core::result::Result { @@ -6650,22 +10277,23 @@ pub mod two_phase { } } }; - impl ::frame_support::dispatch::GetDispatchInfo for Call { + impl ::frame_support::dispatch::GetDispatchInfo for Call + where + ExtendedBalance: From>>, + { fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { match *self { Call::submit(ref solution) => { - let base_weight = 0; - let weight = - >::weigh_data( - &base_weight, - (solution,), - ); - let class = < dyn :: frame_support :: dispatch :: ClassifyDispatch < ( & RawSolution , ) > > :: classify_dispatch ( & base_weight , ( solution , ) ) ; - let pays_fee = - >::pays_fee( - &base_weight, - (solution,), - ); + let base_weight = T::WeightInfo::submit(); + let weight = >, + )>>::weigh_data(&base_weight, (solution,)); + let class = >, + )>>::classify_dispatch(&base_weight, (solution,)); + let pays_fee = >, + )>>::pays_fee(&base_weight, (solution,)); ::frame_support::dispatch::DispatchInfo { weight, class, @@ -6673,18 +10301,16 @@ pub mod two_phase { } } Call::submit_unsigned(ref solution) => { - let base_weight = 0; - let weight = - >::weigh_data( - &base_weight, - (solution,), - ); - let class = < dyn :: frame_support :: dispatch :: ClassifyDispatch < ( & RawSolution , ) > > :: classify_dispatch ( & base_weight , ( solution , ) ) ; - let pays_fee = - >::pays_fee( - &base_weight, - (solution,), - ); + let base_weight = T::WeightInfo::submit_unsigned(); + let weight = >, + )>>::weigh_data(&base_weight, (solution,)); + let class = >, + )>>::classify_dispatch(&base_weight, (solution,)); + let pays_fee = >, + )>>::pays_fee(&base_weight, (solution,)); ::frame_support::dispatch::DispatchInfo { weight, class, @@ -6705,7 +10331,10 @@ pub mod two_phase { } } } - impl ::frame_support::dispatch::GetCallName for Call { + impl ::frame_support::dispatch::GetCallName for Call + where + ExtendedBalance: From>>, + { fn get_call_name(&self) -> &'static str { match *self { Call::submit(ref solution) => { @@ -6733,7 +10362,10 @@ pub mod two_phase { &["submit", "submit_unsigned"] } } - impl ::frame_support::dispatch::Clone for Call { + impl ::frame_support::dispatch::Clone for Call + where + ExtendedBalance: From>>, + { fn clone(&self) -> Self { match *self { Call::submit(ref solution) => Call::submit((*solution).clone()), @@ -6742,7 +10374,10 @@ pub mod two_phase { } } } - impl ::frame_support::dispatch::PartialEq for Call { + impl ::frame_support::dispatch::PartialEq for Call + where + ExtendedBalance: From>>, + { fn eq(&self, _other: &Self) -> bool { match *self { Call::submit(ref solution) => { @@ -6775,8 +10410,14 @@ pub mod two_phase { } } } - impl ::frame_support::dispatch::Eq for Call {} - impl ::frame_support::dispatch::fmt::Debug for Call { + impl ::frame_support::dispatch::Eq for Call where + ExtendedBalance: From>> + { + } + impl ::frame_support::dispatch::fmt::Debug for Call + where + ExtendedBalance: From>>, + { fn fmt( &self, _f: &mut ::frame_support::dispatch::fmt::Formatter, @@ -6806,7 +10447,10 @@ pub mod two_phase { } } } - impl ::frame_support::traits::UnfilteredDispatchable for Call { + impl ::frame_support::traits::UnfilteredDispatchable for Call + where + ExtendedBalance: From>>, + { type Origin = T::Origin; fn dispatch_bypass_filter( self, @@ -6833,10 +10477,16 @@ pub mod two_phase { } } } - impl ::frame_support::dispatch::Callable for Module { + impl ::frame_support::dispatch::Callable for Module + where + ExtendedBalance: From>>, + { type Call = Call; } - impl Module { + impl Module + where + ExtendedBalance: From>>, + { #[doc(hidden)] #[allow(dead_code)] pub fn call_functions() -> &'static [::frame_support::dispatch::FunctionMetadata] { @@ -6846,25 +10496,57 @@ pub mod two_phase { arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ ::frame_support::dispatch::FunctionArgumentMetadata { name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), - ty: ::frame_support::dispatch::DecodeDifferent::Encode("RawSolution"), + ty: ::frame_support::dispatch::DecodeDifferent::Encode( + "RawSolution>", + ), }, ]), - documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[]), + documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + r" Submit a solution for the signed phase.", + r"", + r" The dispatch origin fo this call must be __signed__.", + r"", + r" The solution potentially queued, based on the claimed score and processed at the end of", + r" the signed phase.", + r"", + r" A deposit is reserved and recorded for the solution. Based on the outcome, the solution", + r" might be rewarded, slashed, or get all or a part of the deposit back.", + ]), }, ::frame_support::dispatch::FunctionMetadata { name: ::frame_support::dispatch::DecodeDifferent::Encode("submit_unsigned"), arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ ::frame_support::dispatch::FunctionArgumentMetadata { name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), - ty: ::frame_support::dispatch::DecodeDifferent::Encode("RawSolution"), + ty: ::frame_support::dispatch::DecodeDifferent::Encode( + "RawSolution>", + ), }, ]), - documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[]), + documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ + r" Submit a solution for the unsigned phase.", + r"", + r" The dispatch origin fo this call must be __signed__.", + r"", + r" This submission is checked on the fly, thus it is likely yo be more limited and smaller.", + r" Moreover, this unsigned solution is only validated when submitted to the pool from the", + r" local process. Effectively, this means that only active validators can submit this", + r" transaction when authoring a block.", + r"", + r" To prevent any incorrect solution (and thus wasted time/weight), this transaction will", + r" panic if the solution submitted by the validator is invalid, effectively putting their", + r" authoring reward at risk.", + r"", + r" No deposit or reward is associated with this.", + ]), }, ] } } - impl Module { + impl Module + where + ExtendedBalance: From>>, + { #[doc(hidden)] #[allow(dead_code)] pub fn module_constants_metadata( @@ -6872,51 +10554,33 @@ pub mod two_phase { &[] } } - impl ::frame_support::dispatch::ModuleErrorMetadata for Module { - fn metadata() -> &'static [::frame_support::dispatch::ErrorMetadata] { - <&'static str as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() - } - } - pub enum FeasibilityError { - /// Wrong number of winners presented. - WrongWinnerCount, - /// The snapshot is not available. - /// - /// This must be an internal error of the chain. - SnapshotUnavailable, - /// Internal error from the election crate. - NposElectionError(sp_npos_elections::Error), - /// A vote is invalid. - InvalidVote, - /// A voter is invalid. - InvalidVoter, - /// A winner is invalid. - InvalidWinner, - /// The given score was invalid. - InvalidScore, - } - impl From for FeasibilityError { - fn from(e: sp_npos_elections::Error) -> Self { - FeasibilityError::NposElectionError(e) - } - } - impl Module { + impl ::frame_support::dispatch::ModuleErrorMetadata for Module + where + ExtendedBalance: From>>, + { + fn metadata() -> &'static [::frame_support::dispatch::ErrorMetadata] { + as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() + } + } + impl Module + where + ExtendedBalance: From>>, + { /// Checks the feasibility of a solution. + /// + /// This checks the solution for the following: + /// + /// 0. **all** of the used indices must be correct. + /// 1. present correct number of winners. + /// 2. any assignment is checked to match with `SnapshotVoters`. + /// 3. for each assignment, the check of `ElectionDataProvider` is also examined. + /// 4. the claimed score is valid. fn feasibility_check( - solution: RawSolution, + solution: RawSolution>, + compute: ElectionCompute, ) -> Result, FeasibilityError> { - let RawSolution { - winners, - compact, - score, - } = solution; - { - if !(compact.unique_targets().len() == winners.len()) { - { - return Err(FeasibilityError::WrongWinnerCount.into()); - }; - } - }; + let RawSolution { compact, score } = solution; + let winners = compact.unique_targets(); { if !(winners.len() as u32 == Self::desired_targets()) { { @@ -6928,11 +10592,15 @@ pub mod two_phase { Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; let snapshot_targets = Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - let voter_at = |i: VoterIndex| -> Option { - snapshot_voters.get(i as usize).map(|(x, _, _)| x).cloned() + let voter_at = |i: crate::two_phase::CompactVoterIndexOf| -> Option { + as crate::TryInto>::try_into(i) + .ok() + .and_then(|i| snapshot_voters.get(i).map(|(x, _, _)| x).cloned()) }; - let target_at = |i: TargetIndex| -> Option { - snapshot_targets.get(i as usize).cloned() + let target_at = |i: crate::two_phase::CompactTargetIndexOf| -> Option { + as crate::TryInto>::try_into(i) + .ok() + .and_then(|i| snapshot_targets.get(i).cloned()) }; let winners = winners .into_iter() @@ -6949,7 +10617,7 @@ pub mod two_phase { |(_, _, t)| { if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) && T::ElectionDataProvider::feasibility_check_assignment::< - OffchainAccuracy, + CompactAccuracyOf, >(who, distribution) { Ok(()) @@ -6967,12 +10635,161 @@ pub mod two_phase { .map(|(_, x, _)| *x) .unwrap_or_default() }; - use sp_npos_elections::{assignment_ratio_to_staked_normalized, build_support_map}; let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) .map_err::(Into::into)?; - let supports = build_support_map(&winners, &staked_assignments) + let supports = sp_npos_elections::to_supports(&winners, &staked_assignments) .map_err::(Into::into)?; - let known_score = evaluate_support(&supports); + let known_score = supports.evaluate(); + ( + match known_score { + tmp => { + { + ::std::io::_eprint(::core::fmt::Arguments::new_v1_formatted( + &["[", ":", "] ", " = ", "\n"], + &match ( + &"frame/election-providers/src/two_phase/mod.rs", + &674u32, + &"known_score", + &&tmp, + ) { + (arg0, arg1, arg2, arg3) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg2, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new(arg3, ::core::fmt::Debug::fmt), + ], + }, + &[ + ::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 1usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 2usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 3usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ], + )); + }; + tmp + } + }, + match score { + tmp => { + { + ::std::io::_eprint(::core::fmt::Arguments::new_v1_formatted( + &["[", ":", "] ", " = ", "\n"], + &match ( + &"frame/election-providers/src/two_phase/mod.rs", + &674u32, + &"score", + &&tmp, + ) { + (arg0, arg1, arg2, arg3) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg2, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new(arg3, ::core::fmt::Debug::fmt), + ], + }, + &[ + ::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 1usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 2usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 3usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ], + )); + }; + tmp + } + }, + ); { if !(known_score == score) { { @@ -6980,40 +10797,106 @@ pub mod two_phase { }; } }; - let supports = supports.flatten(); - Ok(ReadySolution { winners, supports }) + Ok(ReadySolution { + supports, + compute, + score, + }) } - fn onchain_fallback() -> Result, crate::Error> { + /// On-chain fallback of election. + fn onchain_fallback() -> Result, Error> { let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(crate::Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(crate::Error::SnapshotUnAvailable)?; - >::elect::( + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + >::elect::( desired_targets, targets, voters, ) + .map_err(Into::into) } } - impl crate::ElectionProvider for Module { - fn elect( + impl ElectionProvider for Module + where + ExtendedBalance: From>>, + { + const NEEDS_ELECT_DATA: bool = false; + type Error = Error; + fn elect( _to_elect: usize, _targets: Vec, _voters: Vec<(T::AccountId, VoteWeight, Vec)>, - ) -> Result, crate::Error> + ) -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, - P: sp_std::ops::Mul, { Self::queued_solution() .map_or_else( - || Self::onchain_fallback(), - |ReadySolution { supports, .. }| Ok(supports), + || { + Self::onchain_fallback() + .map(|r| (r, ElectionCompute::OnChain)) + .map_err(Into::into) + }, + |ReadySolution { + supports, compute, .. + }| Ok((supports, compute)), ) - .map(|result| { - CurrentPhase::put(Phase::Off); + .map(|(supports, compute)| { + >::put(Phase::Off); >::kill(); >::kill(); - result + Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); + { + let lvl = ::log::Level::Info; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( + ::core::fmt::Arguments::new_v1( + &["\u{1f3e6} Finalized election round with compute ", "."], + &match (&compute,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + ), + lvl, + &( + crate::LOG_TARGET, + "frame_election_providers::two_phase", + "frame/election-providers/src/two_phase/mod.rs", + 731u32, + ), + ); + } + }; + supports + }) + .map_err(|err| { + Self::deposit_event(RawEvent::ElectionFinalized(None)); + { + let lvl = ::log::Level::Error; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( + ::core::fmt::Arguments::new_v1( + &["\u{1f3e6} Failed to finalize election round. Error = "], + &match (&err,) { + (arg0,) => [::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + )], + }, + ), + lvl, + &( + crate::LOG_TARGET, + "frame_election_providers::two_phase", + "frame/election-providers/src/two_phase/mod.rs", + 736u32, + ), + ); + } + }; + err }) } fn ongoing() -> bool { @@ -7026,8 +10909,7 @@ pub mod two_phase { #[cfg(test)] mod tests { use super::{mock::*, *}; - use crate::ElectionProvider; - use frame_support::traits::OnInitialize; + use sp_election_providers::ElectionProvider; use sp_npos_elections::Support; extern crate test; #[cfg(test)] @@ -7102,6 +10984,35 @@ pub mod two_phase { } } }; + { + match (&TwoPhase::round(), &0) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; roll_to(4); { match (&TwoPhase::current_phase(), &Phase::Off) { @@ -7139,6 +11050,35 @@ pub mod two_phase { ) } }; + { + match (&TwoPhase::round(), &0) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; roll_to(5); { match (&TwoPhase::current_phase(), &Phase::Signed) { @@ -7176,6 +11116,35 @@ pub mod two_phase { ) } }; + { + match (&TwoPhase::round(), &1) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; roll_to(14); { match (&TwoPhase::current_phase(), &Phase::Signed) { @@ -7213,9 +11182,38 @@ pub mod two_phase { ) } }; + { + match (&TwoPhase::round(), &1) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; roll_to(15); { - match (&TwoPhase::current_phase(), &Phase::Unsigned(true)) { + match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { (left_val, right_val) => { if !(*left_val == *right_val) { { @@ -7252,7 +11250,7 @@ pub mod two_phase { }; roll_to(19); { - match (&TwoPhase::current_phase(), &Phase::Unsigned(true)) { + match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { (left_val, right_val) => { if !(*left_val == *right_val) { { @@ -7289,7 +11287,7 @@ pub mod two_phase { }; roll_to(20); { - match (&TwoPhase::current_phase(), &Phase::Unsigned(true)) { + match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { (left_val, right_val) => { if !(*left_val == *right_val) { { @@ -7326,7 +11324,7 @@ pub mod two_phase { }; roll_to(21); { - match (&TwoPhase::current_phase(), &Phase::Unsigned(true)) { + match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { (left_val, right_val) => { if !(*left_val == *right_val) { { @@ -7399,6 +11397,35 @@ pub mod two_phase { ) } }; + { + match (&TwoPhase::round(), &1) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + { + ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( + &[ + "assertion failed: `(left == right)`\n left: `", + "`,\n right: `", + "`", + ], + &match (&&*left_val, &&*right_val) { + (arg0, arg1) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Debug::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Debug::fmt, + ), + ], + }, + )) + } + } + } + } + }; }) } extern crate test; @@ -7448,7 +11475,7 @@ pub mod two_phase { }; roll_to(20); { - match (&TwoPhase::current_phase(), &Phase::Unsigned(true)) { + match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { (left_val, right_val) => { if !(*left_val == *right_val) { { @@ -7536,165 +11563,42 @@ pub mod two_phase { } }) } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const can_only_submit_threshold_better: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::tests::can_only_submit_threshold_better"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(can_only_submit_threshold_better()) - }), - }; - fn can_only_submit_threshold_better() {} } } -use sp_arithmetic::PerThing; +const LOG_TARGET: &'static str = "election-provider"; #[doc(hidden)] pub use sp_npos_elections::VoteWeight; -use sp_npos_elections::{ExtendedBalance, Supports}; -use sp_runtime::RuntimeDebug; +#[doc(hidden)] +pub use sp_runtime::traits::UniqueSaturatedInto; #[doc(hidden)] pub use sp_std::convert::TryInto; -/// A bridge between the entity requesting a long-lasting election from something that implements -/// [`ElectionProvider`], such as the [`two_phase`] module. -pub trait ElectionDataProvider { - fn targets() -> Vec; - fn voters() -> Vec<(AccountId, VoteWeight, Vec)>; - fn desired_targets() -> u32; - fn feasibility_check_assignment( - who: &AccountId, - distribution: &[(AccountId, P)], - ) -> bool; - fn next_election_prediction(now: B) -> B; -} -#[cfg(feature = "std")] -impl ElectionDataProvider for () { - fn targets() -> Vec { - Default::default() - } - fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { - Default::default() - } - fn desired_targets() -> u32 { - Default::default() - } - fn feasibility_check_assignment(_: &AccountId, _: &[(AccountId, P)]) -> bool { - Default::default() - } - fn next_election_prediction(_: B) -> B { - Default::default() - } -} -/// Something that can compute the result of an election and pass it back to a pallet. -pub trait ElectionProvider { - /// Elect a new set of winners. - /// - /// The result is returned in a target major format, namely as a support map. - fn elect( - to_elect: usize, - targets: Vec, - voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Error> - where - ExtendedBalance: From<

::Inner>, - P: sp_std::ops::Mul; - /// Returns true if an election is still ongoing. - fn ongoing() -> bool; -} -pub enum Error { - ElectionFailed, - SnapshotUnAvailable, - Internal(sp_npos_elections::Error), -} -impl core::fmt::Debug for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::ElectionFailed => fmt.debug_tuple("Error::ElectionFailed").finish(), - Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), - Self::Internal(ref a0) => fmt.debug_tuple("Error::Internal").field(a0).finish(), - _ => Ok(()), - } - } -} -impl ::core::marker::StructuralEq for Error {} -#[automatically_derived] -#[allow(unused_qualifications)] -impl ::core::cmp::Eq for Error { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - } - } -} -impl ::core::marker::StructuralPartialEq for Error {} -#[automatically_derived] -#[allow(unused_qualifications)] -impl ::core::cmp::PartialEq for Error { - #[inline] - fn eq(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Internal(ref __self_0), &Error::Internal(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Internal(ref __self_0), &Error::Internal(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - _ => false, - } - } else { - true - } - } - } -} -impl From for Error { - fn from(err: sp_npos_elections::Error) -> Self { - Error::Internal(err) - } -} #[main] pub fn main() -> () { extern crate test; test::test_main_static(&[ + &test_benchmarks, &cannot_submit_too_early, &should_pay_deposit, &good_solution_is_rewarded, &bad_solution_is_slashed, + &suppressed_solution_gets_bond_back, &queue_is_always_sorted, - &can_submit_until_queue_full, - &weakest_is_removed_if_better_provided, &cannot_submit_worse_with_full_queue, - &suppressed_solution_gets_bond_back, - &solutions_are_sorted, - &all_in_one_singed_submission, + &weakest_is_removed_if_better_provided, + &equally_good_is_not_accepted, + &solutions_are_always_sorted, + &all_in_one_singed_submission_scenario, + &validate_unsigned_retracts_wrong_phase, + &validate_unsigned_retracts_low_score, + &priority_is_set, + &invalid_solution_panics, + &miner_works, + &ocw_will_only_submit_if_feasible, + &can_only_submit_threshold_better, + &ocw_check_prevent_duplicate, + &ocw_only_runs_when_signed_open_now, + &ocw_can_submit_to_pool, &phase_rotation_works, &onchain_backup_works, - &can_only_submit_threshold_better, ]) } diff --git a/frame/election-providers/expanded.rs b/frame/election-providers/expanded.rs index 14d412384b5fe..72e6a1e968a54 100644 --- a/frame/election-providers/expanded.rs +++ b/frame/election-providers/expanded.rs @@ -122,7 +122,7 @@ pub mod onchain { } /// The two-phase module. pub mod two_phase { - //! # Two phase election provider pallet. + //! # Two phase election provider pallet. //! //! As the name suggests, this election provider has two distinct phases (see [`Phase`]), signed and //! unsigned. @@ -212,7 +212,7 @@ pub mod two_phase { //! //! TODO //! - use crate::onchain::OnChainSequentialPhragmen; + use crate::onchain::OnChainSequentialPhragmen; use codec::{Decode, Encode, HasCompact}; use frame_support::{ decl_event, decl_module, decl_storage, @@ -232,22 +232,22 @@ pub mod two_phase { RuntimeDebug, }; use sp_std::prelude::*; - #[macro_use] - pub(crate) mod macros { - //! Some helper macros for this crate. - } - pub mod signed { - //! The signed phase implementation. - use crate::two_phase::*; - use codec::Encode; - use sp_arithmetic::traits::SaturatedConversion; - use sp_npos_elections::is_score_better; - use sp_runtime::Perbill; - impl Module - where - ExtendedBalance: From>>, - { - /// Start the signed phase. + #[macro_use] + pub(crate) mod macros { + //! Some helper macros for this crate. + } + pub mod signed { + //! The signed phase implementation. + use crate::two_phase::*; + use codec::Encode; + use sp_arithmetic::traits::SaturatedConversion; + use sp_npos_elections::is_score_better; + use sp_runtime::Perbill; + impl Module + where + ExtendedBalance: From>>, + { + /// Start the signed phase. /// /// Upon calling this, auxillary data for election is stored and signed solutions will be /// accepted. @@ -262,12 +262,12 @@ pub mod two_phase { DesiredTargets::put(desired_targets); } /// Finish the singed phase. Process the signed submissions from best to worse until a valid one - /// is found, rewarding the best oen and slashing the invalid ones along the way. - /// - /// Returns true if we have a good solution in the signed phase. - /// - /// This drains the [`SignedSubmissions`], potentially storing the best valid one in - /// [`QueuedSolution`]. + /// is found, rewarding the best oen and slashing the invalid ones along the way. + /// + /// Returns true if we have a good solution in the signed phase. + /// + /// This drains the [`SignedSubmissions`], potentially storing the best valid one in + /// [`QueuedSolution`]. pub fn finalize_signed_phase() -> bool { let mut all_submission: Vec> = >::take(); @@ -324,18 +324,18 @@ pub mod two_phase { }; }; }); - found_solution - } - /// Find a proper position in the queue for the signed queue, whilst maintaining the order of - /// solution quality. - /// - /// The length of the queue will always be kept less than or equal to `T::MaxSignedSubmissions`. - pub fn insert_submission( - who: &T::AccountId, - queue: &mut Vec, CompactOf>>, - solution: RawSolution>, - ) -> Option { - let outcome = queue + found_solution + } + /// Find a proper position in the queue for the signed queue, whilst maintaining the order of + /// solution quality. + /// + /// The length of the queue will always be kept less than or equal to `T::MaxSignedSubmissions`. + pub fn insert_submission( + who: &T::AccountId, + queue: &mut Vec, CompactOf>>, + solution: RawSolution>, + ) -> Option { + let outcome = queue .iter() .enumerate() .rev() @@ -379,33 +379,33 @@ pub mod two_phase { } }; }; - outcome - } - /// Collect sufficient deposit to store this solution this chain. - /// - /// The deposit is composed of 3 main elements: - /// - /// 1. base deposit, fixed for all submissions. - /// 2. a per-byte deposit, for renting the state usage. - /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize - pub fn deposit_for(solution: &RawSolution>) -> BalanceOf { - let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); - let feasibility_weight = T::WeightInfo::feasibility_check(); - let len_deposit = T::SignedDepositByte::get() * encoded_len; - let weight_deposit = - T::SignedDepositWeight::get() * feasibility_weight.saturated_into(); - T::SignedDepositBase::get() + len_deposit + weight_deposit - } - /// The reward for this solution, if successfully chosen as the best one at the end of the - /// signed phase. - pub fn reward_for(solution: &RawSolution>) -> BalanceOf { - T::SignedRewardBase::get() - + T::SignedRewardFactor::get() - * solution.score[0].saturated_into::>() - } - } - } - pub mod unsigned { + outcome + } + /// Collect sufficient deposit to store this solution this chain. + /// + /// The deposit is composed of 3 main elements: + /// + /// 1. base deposit, fixed for all submissions. + /// 2. a per-byte deposit, for renting the state usage. + /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize + pub fn deposit_for(solution: &RawSolution>) -> BalanceOf { + let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); + let feasibility_weight = T::WeightInfo::feasibility_check(); + let len_deposit = T::SignedDepositByte::get() * encoded_len; + let weight_deposit = + T::SignedDepositWeight::get() * feasibility_weight.saturated_into(); + T::SignedDepositBase::get() + len_deposit + weight_deposit + } + /// The reward for this solution, if successfully chosen as the best one at the end of the + /// signed phase. + pub fn reward_for(solution: &RawSolution>) -> BalanceOf { + T::SignedRewardBase::get() + + T::SignedRewardFactor::get() + * solution.score[0].saturated_into::>() + } + } + } + pub mod unsigned { //! The unsigned phase implementation. use crate::two_phase::*; use frame_support::{dispatch::DispatchResult, unsigned::ValidateUnsigned}; @@ -425,19 +425,19 @@ pub mod two_phase { pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; /// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice /// within a window of 5 blocks. - pub(crate) const OFFCHAIN_REPEAT: u32 = 5; - /// Default number of blocks for which the unsigned transaction should stay in the pool - pub(crate) const DEFAULT_LONGEVITY: u64 = 25; - impl Module + pub(crate) const OFFCHAIN_REPEAT: u32 = 5; + /// Default number of blocks for which the unsigned transaction should stay in the pool + pub(crate) const DEFAULT_LONGEVITY: u64 = 25; + impl Module where ExtendedBalance: From>>, { /// Min a new npos solution. - pub fn mine_solution(iters: usize) -> Result>, Error> { - let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - seq_phragmen::<_, CompactAccuracyOf>( + pub fn mine_solution(iters: usize) -> Result>, Error> { + let desired_targets = Self::desired_targets() as usize; + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + seq_phragmen::<_, CompactAccuracyOf>( desired_targets, targets, voters, @@ -445,18 +445,18 @@ pub mod two_phase { ) .map_err(Into::into) .and_then(Self::prepare_election_result) - } - /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which - /// is ready to be submitted to the chain. - /// - /// Will always reduce the solution as well. - pub fn prepare_election_result( - election_result: ElectionResult>, - ) -> Result>, Error> { - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - let voter_index = - |who: &T::AccountId| -> Option> { + } + /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which + /// is ready to be submitted to the chain. + /// + /// Will always reduce the solution as well. + pub fn prepare_election_result( + election_result: ElectionResult>, + ) -> Result>, Error> { + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + let voter_index = + |who: &T::AccountId| -> Option> { voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < T > > > :: try_into ( i ) . ok ( ) ) }; let target_index = @@ -494,63 +494,63 @@ pub mod two_phase { Self::maximum_compact_len::(0, Default::default(), 0); let compact = Self::trim_compact(compact.len() as u32, compact, &voter_index)?; let winners = sp_npos_elections::to_without_backing(winners); - let score = compact + let score = compact .clone() .score(&winners, stake_of, voter_at, target_at)?; - Ok(RawSolution { compact, score }) - } - /// Get a random number of iterations to run the balancing in the OCW. - /// - /// Uses the offchain seed to generate a random number, maxed with `T::UnsignedMaxIterations`. - pub fn get_balancing_iters() -> usize { - match T::UnsignedMaxIterations::get() { - 0 => 0, - max @ _ => { - let seed = sp_io::offchain::random_seed(); - let random = ::decode(&mut TrailingZeroInput::new(seed.as_ref())) - .expect("input is padded with zeroes; qed") - % max.saturating_add(1); - random as usize - } - } - } - /// Greedily reduce the size of the a solution to fit into the block, w.r.t. weight. - /// - /// The weight of the solution is foremost a function of the number of voters (i.e. - /// `compact.len()`). Aside from this, the other components of the weight are invariant. The - /// number of winners shall not be changed (otherwise the solution is invalid) and the - /// `ElectionSize` is merely a representation of the total number of stakers. - /// - /// Thus, we reside to stripping away some voters. This means only changing the `compact` - /// struct. - /// - /// Note that the solution is already computed, and the winners are elected based on the merit - /// of teh entire stake in the system. Nonetheless, some of the voters will be removed further - /// down the line. - /// - /// Indeed, the score must be computed **after** this step. If this step reduces the score too - /// much, then the solution will be discarded. - pub fn trim_compact( - maximum_allowed_voters: u32, - mut compact: CompactOf, - nominator_index: FN, - ) -> Result, Error> - where - for<'r> FN: Fn(&'r T::AccountId) -> Option>, - { - match compact.len().checked_sub(maximum_allowed_voters as usize) { - Some(to_remove) if to_remove > 0 => { - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let mut voters_sorted = voters - .into_iter() - .map(|(who, stake, _)| (who.clone(), stake)) - .collect::>(); - voters_sorted.sort_by_key(|(_, y)| *y); - let mut removed = 0; - for (maybe_index, _stake) in voters_sorted - .iter() - .map(|(who, stake)| (nominator_index(&who), stake)) - { + Ok(RawSolution { compact, score }) + } + /// Get a random number of iterations to run the balancing in the OCW. + /// + /// Uses the offchain seed to generate a random number, maxed with `T::UnsignedMaxIterations`. + pub fn get_balancing_iters() -> usize { + match T::UnsignedMaxIterations::get() { + 0 => 0, + max @ _ => { + let seed = sp_io::offchain::random_seed(); + let random = ::decode(&mut TrailingZeroInput::new(seed.as_ref())) + .expect("input is padded with zeroes; qed") + % max.saturating_add(1); + random as usize + } + } + } + /// Greedily reduce the size of the a solution to fit into the block, w.r.t. weight. + /// + /// The weight of the solution is foremost a function of the number of voters (i.e. + /// `compact.len()`). Aside from this, the other components of the weight are invariant. The + /// number of winners shall not be changed (otherwise the solution is invalid) and the + /// `ElectionSize` is merely a representation of the total number of stakers. + /// + /// Thus, we reside to stripping away some voters. This means only changing the `compact` + /// struct. + /// + /// Note that the solution is already computed, and the winners are elected based on the merit + /// of teh entire stake in the system. Nonetheless, some of the voters will be removed further + /// down the line. + /// + /// Indeed, the score must be computed **after** this step. If this step reduces the score too + /// much, then the solution will be discarded. + pub fn trim_compact( + maximum_allowed_voters: u32, + mut compact: CompactOf, + nominator_index: FN, + ) -> Result, Error> + where + for<'r> FN: Fn(&'r T::AccountId) -> Option>, + { + match compact.len().checked_sub(maximum_allowed_voters as usize) { + Some(to_remove) if to_remove > 0 => { + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let mut voters_sorted = voters + .into_iter() + .map(|(who, stake, _)| (who.clone(), stake)) + .collect::>(); + voters_sorted.sort_by_key(|(_, y)| *y); + let mut removed = 0; + for (maybe_index, _stake) in voters_sorted + .iter() + .map(|(who, stake)| (nominator_index(&who), stake)) + { let index = maybe_index.ok_or(Error::SnapshotUnAvailable)?; if compact.remove_voter(index) { removed += 1 @@ -558,29 +558,29 @@ pub mod two_phase { if removed >= to_remove { break; } - } - Ok(compact) - } - _ => Ok(compact), - } - } - /// Find the maximum `len` that a compact can have in order to fit into the block weight. - /// - /// This only returns a value between zero and `size.nominators`. - pub fn maximum_compact_len( - _winners_len: u32, - witness: WitnessData, - max_weight: Weight, - ) -> u32 { - if witness.voters < 1 { - return witness.voters; - } - let max_voters = witness.voters.max(1); - let mut voters = max_voters; - let weight_with = |_voters: u32| -> Weight { W::submit_unsigned() }; - let next_voters = - |current_weight: Weight, voters: u32, step: u32| -> Result { - match current_weight.cmp(&max_weight) { + } + Ok(compact) + } + _ => Ok(compact), + } + } + /// Find the maximum `len` that a compact can have in order to fit into the block weight. + /// + /// This only returns a value between zero and `size.nominators`. + pub fn maximum_compact_len( + _winners_len: u32, + witness: WitnessData, + max_weight: Weight, + ) -> u32 { + if witness.voters < 1 { + return witness.voters; + } + let max_voters = witness.voters.max(1); + let mut voters = max_voters; + let weight_with = |_voters: u32| -> Weight { W::submit_unsigned() }; + let next_voters = + |current_weight: Weight, voters: u32, step: u32| -> Result { + match current_weight.cmp(&max_weight) { Ordering::Less => { let next_voters = voters.checked_add(step); match next_voters { @@ -634,9 +634,9 @@ pub mod two_phase { } }; }; - voters.min(witness.voters) - } - /// Checks if an execution of the offchain worker is permitted at the given block number, or not. + voters.min(witness.voters) + } + /// Checks if an execution of the offchain worker is permitted at the given block number, or not. /// /// This essentially makes sure that we don't run on previous blocks in case of a re-org, and we /// don't run twice within a window of length [`OFFCHAIN_REPEAT`]. @@ -656,14 +656,15 @@ pub mod two_phase { } Some(Some(head)) if now > head + threshold => Ok(now), _ => Ok(now), - }, + } + }, ); - match mutate_stat { - Ok(Ok(_)) => Ok(()), - Ok(Err(_)) => Err("failed to write to offchain db."), - Err(why) => Err(why), - } - } + match mutate_stat { + Ok(Ok(_)) => Ok(()), + Ok(Err(_)) => Err("failed to write to offchain db."), + Err(why) => Err(why), + } + } /// Mine a new solution, and submit it back to the chian as an unsigned transaction. pub(crate) fn mine_and_submit() -> Result<(), Error> { let balancing = Self::get_balancing_iters(); @@ -684,32 +685,32 @@ pub mod two_phase { } }; { - if !Self::queued_solution().map_or(true, |q: ReadySolution<_>| { - is_score_better::( - solution.score, - q.score, - T::SolutionImprovementThreshold::get(), - ) - }) { - { - return Err(PalletError::::WeakSubmission.into()); - }; - } + if !Self::queued_solution().map_or(true, |q: ReadySolution<_>| { + is_score_better::( + solution.score, + q.score, + T::SolutionImprovementThreshold::get(), + ) + }) { + { + return Err(PalletError::::WeakSubmission.into()); + }; + } }; Ok(()) - } + } } - #[allow(deprecated)] - impl ValidateUnsigned for Module - where - ExtendedBalance: From>>, - { - type Call = Call; - fn validate_unsigned( - source: TransactionSource, - call: &Self::Call, - ) -> TransactionValidity { - if let Call::submit_unsigned(solution) = call { + #[allow(deprecated)] + impl ValidateUnsigned for Module + where + ExtendedBalance: From>>, + { + type Call = Call; + fn validate_unsigned( + source: TransactionSource, + call: &Self::Call, + ) -> TransactionValidity { + if let Call::submit_unsigned(solution) = call { match source { TransactionSource::Local | TransactionSource::InBlock => {} _ => { @@ -738,38 +739,38 @@ pub mod two_phase { } else { Err(InvalidTransaction::Call.into()) } - } - } + } + } + } + /// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] + /// implementer. + pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< + ::AccountId, + ::BlockNumber, + >>::CompactSolution; + /// The voter index. Derived from [`CompactOf`]. + pub type CompactVoterIndexOf = as CompactSolution>::Voter; + /// The target index. Derived from [`CompactOf`]. + pub type CompactTargetIndexOf = as CompactSolution>::Target; + /// The accuracy of the election. Derived from [`CompactOf`]. + pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; + type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + type PositiveImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::PositiveImbalance; + type NegativeImbalanceOf = <::Currency as Currency< + ::AccountId, + >>::NegativeImbalance; + /// Current phase of the pallet. + pub enum Phase { + /// Nothing, the election is not happening. + Off, + /// Signed phase is open. + Signed, + /// Unsigned phase is open. + Unsigned((bool, Bn)), } - /// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] - /// implementer. - pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< - ::AccountId, - ::BlockNumber, - >>::CompactSolution; - /// The voter index. Derived from [`CompactOf`]. - pub type CompactVoterIndexOf = as CompactSolution>::Voter; - /// The target index. Derived from [`CompactOf`]. - pub type CompactTargetIndexOf = as CompactSolution>::Target; - /// The accuracy of the election. Derived from [`CompactOf`]. - pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; - type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - type PositiveImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::PositiveImbalance; - type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::NegativeImbalance; - /// Current phase of the pallet. - pub enum Phase { - /// Nothing, the election is not happening. - Off, - /// Signed phase is open. - Signed, - /// Unsigned phase is open. - Unsigned((bool, Bn)), - } impl ::core::marker::StructuralPartialEq for Phase {} #[automatically_derived] #[allow(unused_qualifications)] @@ -1534,19 +1535,19 @@ pub mod two_phase { { } }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for ReadySolution - where - Supports: _parity_scale_codec::Decode, - Supports: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(ReadySolution { + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for ReadySolution + where + Supports: _parity_scale_codec::Decode, + Supports: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(ReadySolution { supports: { let res = _parity_scale_codec::Decode::decode(input); match res { @@ -1573,31 +1574,31 @@ pub mod two_phase { } }, }) - } - } - }; - impl core::fmt::Debug for ReadySolution - where - A: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("ReadySolution") - .field("supports", &self.supports) - .field("score", &self.score) - .field("compute", &self.compute) - .finish() - } - } - #[automatically_derived] + } + } + }; + impl core::fmt::Debug for ReadySolution + where + A: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("ReadySolution") + .field("supports", &self.supports) + .field("score", &self.score) + .field("compute", &self.compute) + .finish() + } + } + #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::default::Default for ReadySolution { + impl ::core::default::Default for ReadySolution { #[inline] - fn default() -> ReadySolution { - ReadySolution { - supports: ::core::default::Default::default(), - score: ::core::default::Default::default(), - compute: ::core::default::Default::default(), - } + fn default() -> ReadySolution { + ReadySolution { + supports: ::core::default::Default::default(), + score: ::core::default::Default::default(), + compute: ::core::default::Default::default(), + } } } /// Witness data about the size of the election. @@ -1773,30 +1774,30 @@ pub mod two_phase { } } } - impl ::core::marker::StructuralEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Error { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - impl ::core::marker::StructuralPartialEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Error { - #[inline] - fn eq(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { + impl ::core::marker::StructuralEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + impl ::core::marker::StructuralPartialEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { match (&*self, &*other) { (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { (*__self_0) == (*__arg_1_0) @@ -1839,38 +1840,38 @@ pub mod two_phase { } else { true } - } - } - } - impl From for Error { - fn from(e: crate::onchain::Error) -> Self { - Error::OnChainFallback(e) - } - } - impl From for Error { - fn from(e: sp_npos_elections::Error) -> Self { - Error::NposElections(e) - } - } - /// Errors that can happen in the feasibility check. - pub enum FeasibilityError { - /// Wrong number of winners presented. - WrongWinnerCount, - /// The snapshot is not available. - /// - /// This must be an internal error of the chain. - SnapshotUnavailable, - /// Internal error from the election crate. - NposElectionError(sp_npos_elections::Error), - /// A vote is invalid. - InvalidVote, - /// A voter is invalid. - InvalidVoter, - /// A winner is invalid. - InvalidWinner, - /// The given score was invalid. - InvalidScore, - } + } + } + } + impl From for Error { + fn from(e: crate::onchain::Error) -> Self { + Error::OnChainFallback(e) + } + } + impl From for Error { + fn from(e: sp_npos_elections::Error) -> Self { + Error::NposElections(e) + } + } + /// Errors that can happen in the feasibility check. + pub enum FeasibilityError { + /// Wrong number of winners presented. + WrongWinnerCount, + /// The snapshot is not available. + /// + /// This must be an internal error of the chain. + SnapshotUnavailable, + /// Internal error from the election crate. + NposElectionError(sp_npos_elections::Error), + /// A vote is invalid. + InvalidVote, + /// A voter is invalid. + InvalidVoter, + /// A winner is invalid. + InvalidWinner, + /// The given score was invalid. + InvalidScore, + } impl core::fmt::Debug for FeasibilityError { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { match self { @@ -1904,15 +1905,15 @@ pub mod two_phase { } } } - impl ::core::marker::StructuralPartialEq for FeasibilityError {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for FeasibilityError { - #[inline] - fn eq(&self, other: &FeasibilityError) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + impl ::core::marker::StructuralPartialEq for FeasibilityError {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for FeasibilityError { + #[inline] + fn eq(&self, other: &FeasibilityError) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; if true && __self_vi == __arg_1_vi { match (&*self, &*other) { ( @@ -1942,28 +1943,28 @@ pub mod two_phase { } else { true } - } - } - } - impl From for FeasibilityError { - fn from(e: sp_npos_elections::Error) -> Self { - FeasibilityError::NposElectionError(e) - } - } - /// The weights for this pallet. - pub trait WeightInfo { - fn feasibility_check() -> Weight; - fn submit() -> Weight; - fn submit_unsigned() -> Weight; - } - impl WeightInfo for () { + } + } + } + impl From for FeasibilityError { + fn from(e: sp_npos_elections::Error) -> Self { + FeasibilityError::NposElectionError(e) + } + } + /// The weights for this pallet. + pub trait WeightInfo { + fn feasibility_check() -> Weight; + fn submit() -> Weight; + fn submit_unsigned() -> Weight; + } + impl WeightInfo for () { fn feasibility_check() -> Weight { - Default::default() - } - fn submit() -> Weight { - Default::default() - } - fn submit_unsigned() -> Weight { + Default::default() + } + fn submit() -> Weight { + Default::default() + } + fn submit_unsigned() -> Weight { Default::default() } } @@ -1975,18 +1976,18 @@ pub mod two_phase { type Event: From> + Into<::Event>; /// Currency type. type Currency: ReservableCurrency + Currency; - /// Duration of the signed phase. - type SignedPhase: Get; - /// Duration of the unsigned phase. - type UnsignedPhase: Get; - /// Maximum number of singed submissions that can be queued. - type MaxSignedSubmissions: Get; - type SignedRewardBase: Get>; - type SignedRewardFactor: Get; - type SignedRewardMax: Get>>; - type SignedDepositBase: Get>; - type SignedDepositByte: Get>; - type SignedDepositWeight: Get>; + /// Duration of the signed phase. + type SignedPhase: Get; + /// Duration of the unsigned phase. + type UnsignedPhase: Get; + /// Maximum number of singed submissions that can be queued. + type MaxSignedSubmissions: Get; + type SignedRewardBase: Get>; + type SignedRewardFactor: Get; + type SignedRewardMax: Get>>; + type SignedDepositBase: Get>; + type SignedDepositByte: Get>; + type SignedDepositWeight: Get>; /// The minimum amount of improvement to the solution score that defines a solution as "better". type SolutionImprovementThreshold: Get; type UnsignedMaxIterations: Get; @@ -1994,18 +1995,18 @@ pub mod two_phase { /// Handler for the slashed deposits. type SlashHandler: OnUnbalanced>; /// Handler for the rewards. - type RewardHandler: OnUnbalanced>; - /// Something that will provide the election data. - type ElectionDataProvider: ElectionDataProvider; - /// The weight of the pallet. - type WeightInfo: WeightInfo; - } - use self::sp_api_hidden_includes_decl_storage::hidden_include::{ - IterableStorageDoubleMap as _, IterableStorageMap as _, StorageDoubleMap as _, - StorageMap as _, StoragePrefixedMap as _, StorageValue as _, - }; - #[doc(hidden)] - mod sp_api_hidden_includes_decl_storage { + type RewardHandler: OnUnbalanced>; + /// Something that will provide the election data. + type ElectionDataProvider: ElectionDataProvider; + /// The weight of the pallet. + type WeightInfo: WeightInfo; + } + use self::sp_api_hidden_includes_decl_storage::hidden_include::{ + IterableStorageDoubleMap as _, IterableStorageMap as _, StorageDoubleMap as _, + StorageMap as _, StoragePrefixedMap as _, StorageValue as _, + }; + #[doc(hidden)] + mod sp_api_hidden_includes_decl_storage { pub extern crate frame_support as hidden_include; } trait Store { @@ -2014,10 +2015,10 @@ pub mod two_phase { type SignedSubmissions; type QueuedSolution; type SnapshotTargets; - type SnapshotVoters; - type DesiredTargets; + type SnapshotVoters; + type DesiredTargets; } - impl Store for Module + impl Store for Module where ExtendedBalance: From>>, { @@ -2026,10 +2027,10 @@ pub mod two_phase { type SignedSubmissions = SignedSubmissions; type QueuedSolution = QueuedSolution; type SnapshotTargets = SnapshotTargets; - type SnapshotVoters = SnapshotVoters; - type DesiredTargets = DesiredTargets; + type SnapshotVoters = SnapshotVoters; + type DesiredTargets = DesiredTargets; } - impl Module + impl Module where ExtendedBalance: From>>, { @@ -2046,33 +2047,33 @@ pub mod two_phase { pub fn current_phase() -> Phase { < CurrentPhase < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase < T :: BlockNumber > > > :: get ( ) } - /// Sorted (worse -> best) list of unchecked, signed solutions. - pub fn signed_submissions( - ) -> Vec, CompactOf>> { - < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > > > :: get ( ) - } - /// Current best solution, signed or unsigned. - pub fn queued_solution() -> Option> { - < QueuedSolution < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < ReadySolution < T :: AccountId > > > :: get ( ) - } - /// Snapshot of all Voters. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn snapshot_targets() -> Option> { - < SnapshotTargets < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < T :: AccountId > > > :: get ( ) - } - /// Snapshot of all targets. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn snapshot_voters() -> Option)>> { - < SnapshotVoters < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < ( T :: AccountId , VoteWeight , Vec < T :: AccountId > ) > > > :: get ( ) - } - /// Desired number of targets to elect. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn desired_targets() -> u32 { - < DesiredTargets < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) - } + /// Sorted (worse -> best) list of unchecked, signed solutions. + pub fn signed_submissions( + ) -> Vec, CompactOf>> { + < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > > > :: get ( ) + } + /// Current best solution, signed or unsigned. + pub fn queued_solution() -> Option> { + < QueuedSolution < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < ReadySolution < T :: AccountId > > > :: get ( ) + } + /// Snapshot of all Voters. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub fn snapshot_targets() -> Option> { + < SnapshotTargets < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < T :: AccountId > > > :: get ( ) + } + /// Snapshot of all targets. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub fn snapshot_voters() -> Option)>> { + < SnapshotVoters < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < ( T :: AccountId , VoteWeight , Vec < T :: AccountId > ) > > > :: get ( ) + } + /// Desired number of targets to elect. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub fn desired_targets() -> u32 { + < DesiredTargets < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) + } } #[doc(hidden)] pub struct __GetByteStructRound( @@ -2118,40 +2119,38 @@ pub mod two_phase { (T), >, ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_CurrentPhase: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructCurrentPhase - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec - { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_CurrentPhase - .get_or_init(|| { - let def_val: Phase = Phase::Off; - as Encode>::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructCurrentPhase where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructCurrentPhase where - ExtendedBalance: From>> - { - } + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_CurrentPhase: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructCurrentPhase + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_CurrentPhase + .get_or_init(|| { + let def_val: Phase = Phase::Off; + as Encode>::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructCurrentPhase where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructCurrentPhase where + ExtendedBalance: From>> + { + } #[doc(hidden)] pub struct __GetByteStructSignedSubmissions( pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< @@ -2317,40 +2316,38 @@ pub mod two_phase { >, ); #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] + #[allow(non_upper_case_globals)] static __CACHE_GET_BYTE_STRUCT_DesiredTargets: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructDesiredTargets - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec - { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_DesiredTargets - .get_or_init(|| { - let def_val: u32 = Default::default(); - ::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructDesiredTargets where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructDesiredTargets where - ExtendedBalance: From>> - { - } - impl Module + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructDesiredTargets + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_DesiredTargets + .get_or_init(|| { + let def_val: u32 = Default::default(); + ::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructDesiredTargets where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructDesiredTargets where + ExtendedBalance: From>> + { + } + impl Module where ExtendedBalance: From>>, { @@ -2362,68 +2359,68 @@ pub mod two_phase { } /// Hidden instance generated to be internally used when module is used without /// instance. - #[doc(hidden)] - pub struct __InherentHiddenInstance; - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for __InherentHiddenInstance { - #[inline] - fn clone(&self) -> __InherentHiddenInstance { - match *self { - __InherentHiddenInstance => __InherentHiddenInstance, - } - } - } - impl ::core::marker::StructuralEq for __InherentHiddenInstance {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for __InherentHiddenInstance { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - {} - } - } - impl ::core::marker::StructuralPartialEq for __InherentHiddenInstance {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for __InherentHiddenInstance { - #[inline] - fn eq(&self, other: &__InherentHiddenInstance) -> bool { - match *other { - __InherentHiddenInstance => match *self { - __InherentHiddenInstance => true, - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; + #[doc(hidden)] + pub struct __InherentHiddenInstance; + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for __InherentHiddenInstance { + #[inline] + fn clone(&self) -> __InherentHiddenInstance { + match *self { + __InherentHiddenInstance => __InherentHiddenInstance, + } + } + } + impl ::core::marker::StructuralEq for __InherentHiddenInstance {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for __InherentHiddenInstance { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + {} + } + } + impl ::core::marker::StructuralPartialEq for __InherentHiddenInstance {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for __InherentHiddenInstance { + #[inline] + fn eq(&self, other: &__InherentHiddenInstance) -> bool { + match *other { + __InherentHiddenInstance => match *self { + __InherentHiddenInstance => true, + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; impl _parity_scale_codec::Encode for __InherentHiddenInstance { fn encode_to(&self, dest: &mut EncOut) {} } impl _parity_scale_codec::EncodeLike for __InherentHiddenInstance {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for __InherentHiddenInstance { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(__InherentHiddenInstance) - } - } - }; - impl core::fmt::Debug for __InherentHiddenInstance { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_tuple("__InherentHiddenInstance").finish() - } - } - impl self::sp_api_hidden_includes_decl_storage::hidden_include::traits::Instance + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for __InherentHiddenInstance { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { + Ok(__InherentHiddenInstance) + } + } + }; + impl core::fmt::Debug for __InherentHiddenInstance { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_tuple("__InherentHiddenInstance").finish() + } + } + impl self::sp_api_hidden_includes_decl_storage::hidden_include::traits::Instance for __InherentHiddenInstance { const PREFIX: &'static str = "TwoPhaseElectionProvider"; @@ -2464,76 +2461,76 @@ pub mod two_phase { ) where ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Phase, - > for CurrentPhase - where - ExtendedBalance: From>>, - { - type Query = Phase; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"CurrentPhase" - } - fn from_optional_value_to_query(v: Option>) -> Self::Query { - v.unwrap_or_else(|| Phase::Off) - } - fn from_query_to_optional_value(v: Self::Query) -> Option> { - Some(v) - } - } - /// Sorted (worse -> best) list of unchecked, signed solutions. - pub struct SignedSubmissions( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec, CompactOf>>, - > for SignedSubmissions - where - ExtendedBalance: From>>, - { - type Query = Vec, CompactOf>>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"SignedSubmissions" - } - fn from_optional_value_to_query( - v: Option, CompactOf>>>, - ) -> Self::Query { - v.unwrap_or_else(|| Default::default()) - } - fn from_query_to_optional_value( - v: Self::Query, - ) -> Option, CompactOf>>> { - Some(v) - } - } - /// Current best solution, signed or unsigned. - pub struct QueuedSolution( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - ReadySolution, - > for QueuedSolution - where - ExtendedBalance: From>>, - { - type Query = Option>; + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Phase, + > for CurrentPhase + where + ExtendedBalance: From>>, + { + type Query = Phase; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"CurrentPhase" + } + fn from_optional_value_to_query(v: Option>) -> Self::Query { + v.unwrap_or_else(|| Phase::Off) + } + fn from_query_to_optional_value(v: Self::Query) -> Option> { + Some(v) + } + } + /// Sorted (worse -> best) list of unchecked, signed solutions. + pub struct SignedSubmissions( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ) + where + ExtendedBalance: From>>; + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + Vec, CompactOf>>, + > for SignedSubmissions + where + ExtendedBalance: From>>, + { + type Query = Vec, CompactOf>>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"SignedSubmissions" + } + fn from_optional_value_to_query( + v: Option, CompactOf>>>, + ) -> Self::Query { + v.unwrap_or_else(|| Default::default()) + } + fn from_query_to_optional_value( + v: Self::Query, + ) -> Option, CompactOf>>> { + Some(v) + } + } + /// Current best solution, signed or unsigned. + pub struct QueuedSolution( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ) + where + ExtendedBalance: From>>; + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + ReadySolution, + > for QueuedSolution + where + ExtendedBalance: From>>, + { + type Query = Option>; fn module_prefix() -> &'static [u8] { < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) } @@ -2546,7 +2543,7 @@ pub mod two_phase { fn from_query_to_optional_value(v: Self::Query) -> Option> { v } - } + } /// Snapshot of all Voters. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. @@ -2803,15 +2800,15 @@ pub mod two_phase { #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; impl _parity_scale_codec::Decode for RawEvent - where - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { + where + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + AccountId: _parity_scale_codec::Decode, + { + fn decode( + input: &mut DecIn, + ) -> core::result::Result { match input.read_byte()? { x if x == 0usize as u8 => Ok(RawEvent::SolutionStored({ let res = _parity_scale_codec::Decode::decode(input); @@ -2855,15 +2852,15 @@ pub mod two_phase { })), x => Err("No such variant in enum RawEvent".into()), } - } - } - }; - impl core::fmt::Debug for RawEvent - where - AccountId: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { + } + } + }; + impl core::fmt::Debug for RawEvent + where + AccountId: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { Self::SolutionStored(ref a0) => fmt .debug_tuple("RawEvent::SolutionStored") .field(a0) @@ -2876,18 +2873,18 @@ pub mod two_phase { Self::Slashed(ref a0) => fmt.debug_tuple("RawEvent::Slashed").field(a0).finish(), _ => Ok(()), } - } - } - impl From> for () { - fn from(_: RawEvent) -> () { - () - } - } - impl RawEvent { - #[allow(dead_code)] - #[doc(hidden)] - pub fn metadata() -> &'static [::frame_support::event::EventMetadata] { - &[ + } + } + impl From> for () { + fn from(_: RawEvent) -> () { + () + } + } + impl RawEvent { + #[allow(dead_code)] + #[doc(hidden)] + pub fn metadata() -> &'static [::frame_support::event::EventMetadata] { + &[ ::frame_support::event::EventMetadata { name: ::frame_support::event::DecodeDifferent::Encode("SolutionStored"), arguments: ::frame_support::event::DecodeDifferent::Encode(&[ @@ -2925,9 +2922,9 @@ pub mod two_phase { ]), }, ] - } - } - pub enum PalletError + } + } + pub enum PalletError where ExtendedBalance: From>>, { @@ -2945,23 +2942,23 @@ pub mod two_phase { /// The origin failed to pay the deposit. CannotPayDeposit, } - impl ::frame_support::sp_std::fmt::Debug for PalletError - where - ExtendedBalance: From>>, - { - fn fmt( - &self, - f: &mut ::frame_support::sp_std::fmt::Formatter<'_>, - ) -> ::frame_support::sp_std::fmt::Result { - f.write_str(self.as_str()) - } - } - impl PalletError + impl ::frame_support::sp_std::fmt::Debug for PalletError + where + ExtendedBalance: From>>, + { + fn fmt( + &self, + f: &mut ::frame_support::sp_std::fmt::Formatter<'_>, + ) -> ::frame_support::sp_std::fmt::Result { + f.write_str(self.as_str()) + } + } + impl PalletError where ExtendedBalance: From>>, { fn as_u8(&self) -> u8 { - match self { + match self { PalletError::__Ignore(_, _) => { ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( &["internal error: entered unreachable code: "], @@ -2999,35 +2996,34 @@ pub mod two_phase { } } } - impl From> for &'static str - where - ExtendedBalance: From>>, - { - fn from(err: PalletError) -> &'static str { - err.as_str() - } - } - impl From> for ::frame_support::sp_runtime::DispatchError - where - ExtendedBalance: From>>, - { - fn from(err: PalletError) -> Self { - let index = ::index::>() - .expect("Every active module has an index in the runtime; qed") - as u8; - ::frame_support::sp_runtime::DispatchError::Module { - index, - error: err.as_u8(), - message: Some(err.as_str()), - } - } - } - impl ::frame_support::error::ModuleErrorMetadata for PalletError + impl From> for &'static str + where + ExtendedBalance: From>>, + { + fn from(err: PalletError) -> &'static str { + err.as_str() + } + } + impl From> for ::frame_support::sp_runtime::DispatchError + where + ExtendedBalance: From>>, + { + fn from(err: PalletError) -> Self { + let index = ::index::>() + .expect("Every active module has an index in the runtime; qed") as u8; + ::frame_support::sp_runtime::DispatchError::Module { + index, + error: err.as_u8(), + message: Some(err.as_str()), + } + } + } + impl ::frame_support::error::ModuleErrorMetadata for PalletError where ExtendedBalance: From>>, { fn metadata() -> &'static [::frame_support::error::ErrorMetadata] { - &[ + &[ ::frame_support::error::ErrorMetadata { name: ::frame_support::error::DecodeDifferent::Encode("EarlySubmission"), documentation: ::frame_support::error::DecodeDifferent::Encode(&[ @@ -3053,98 +3049,98 @@ pub mod two_phase { ]), }, ] - } + } } - pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>) - where - ExtendedBalance: From>>; - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Module - where - ExtendedBalance: From>>, - { - #[inline] - fn clone(&self) -> Module { - match *self { - Module(ref __self_0_0) => Module(::core::clone::Clone::clone(&(*__self_0_0))), - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for Module where - ExtendedBalance: From>> - { - } - impl ::core::marker::StructuralPartialEq for Module where - ExtendedBalance: From>> - { - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Module - where - ExtendedBalance: From>>, - { - #[inline] - fn eq(&self, other: &Module) -> bool { - match *other { - Module(ref __self_1_0) => match *self { - Module(ref __self_0_0) => (*__self_0_0) == (*__self_1_0), - }, - } - } - #[inline] - fn ne(&self, other: &Module) -> bool { - match *other { - Module(ref __self_1_0) => match *self { - Module(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), - }, - } - } - } - impl ::core::marker::StructuralEq for Module where - ExtendedBalance: From>> - { - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Module - where - ExtendedBalance: From>>, - { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq< - ::frame_support::sp_std::marker::PhantomData<(T,)>, - >; - } - } - } - impl core::fmt::Debug for Module - where - ExtendedBalance: From>>, - T: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_tuple("Module").field(&self.0).finish() + pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>) + where + ExtendedBalance: From>>; + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Module + where + ExtendedBalance: From>>, + { + #[inline] + fn clone(&self) -> Module { + match *self { + Module(ref __self_0_0) => Module(::core::clone::Clone::clone(&(*__self_0_0))), + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for Module where + ExtendedBalance: From>> + { + } + impl ::core::marker::StructuralPartialEq for Module where + ExtendedBalance: From>> + { + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Module + where + ExtendedBalance: From>>, + { + #[inline] + fn eq(&self, other: &Module) -> bool { + match *other { + Module(ref __self_1_0) => match *self { + Module(ref __self_0_0) => (*__self_0_0) == (*__self_1_0), + }, + } } - } - impl + #[inline] + fn ne(&self, other: &Module) -> bool { + match *other { + Module(ref __self_1_0) => match *self { + Module(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), + }, + } + } + } + impl ::core::marker::StructuralEq for Module where + ExtendedBalance: From>> + { + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Module + where + ExtendedBalance: From>>, + { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq< + ::frame_support::sp_std::marker::PhantomData<(T,)>, + >; + } + } + } + impl core::fmt::Debug for Module + where + ExtendedBalance: From>>, + T: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_tuple("Module").field(&self.0).finish() + } + } + impl ::frame_support::traits::OnInitialize<::BlockNumber> for Module where ExtendedBalance: From>>, { fn on_initialize(now: T::BlockNumber) -> Weight { - let __within_span__ = { - use ::tracing::__macro_support::Callsite as _; - static CALLSITE: ::tracing::__macro_support::MacroCallsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( + let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( "on_initialize", "frame_election_providers::two_phase", ::tracing::Level::TRACE, @@ -3176,14 +3172,14 @@ pub mod two_phase { {}; span } - }; - let __tracing_guard__ = __within_span__.enter(); - { - let next_election = T::ElectionDataProvider::next_election_prediction(now); - let next_election = next_election.max(now); - let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); - let unsigned_deadline = T::UnsignedPhase::get(); - let remaining = next_election - now; + }; + let __tracing_guard__ = __within_span__.enter(); + { + let next_election = T::ElectionDataProvider::next_election_prediction(now); + let next_election = next_election.max(now); + let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); + let unsigned_deadline = T::UnsignedPhase::get(); + let remaining = next_election - now; match Self::current_phase() { Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { >::put(Phase::Signed); @@ -3240,7 +3236,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 494u32, + 497u32, ), ); } @@ -3248,33 +3244,33 @@ pub mod two_phase { } _ => {} } - Default::default() - } - } + Default::default() + } + } } - impl ::frame_support::traits::OnRuntimeUpgrade for Module where - ExtendedBalance: From>> - { - } - impl - ::frame_support::traits::OnFinalize<::BlockNumber> for Module - where - ExtendedBalance: From>>, - { - } - impl + impl ::frame_support::traits::OnRuntimeUpgrade for Module where + ExtendedBalance: From>> + { + } + impl + ::frame_support::traits::OnFinalize<::BlockNumber> for Module + where + ExtendedBalance: From>>, + { + } + impl ::frame_support::traits::OffchainWorker<::BlockNumber> for Module where ExtendedBalance: From>>, { fn offchain_worker(n: T::BlockNumber) { - if Self::set_check_offchain_execution_status(n).is_ok() - && Self::current_phase().is_unsigned_open_at(n) - { - let _ = Self::mine_and_submit().map_err(|e| { - let lvl = ::log::Level::Error; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::__private_api_log( + if Self::set_check_offchain_execution_status(n).is_ok() + && Self::current_phase().is_unsigned_open_at(n) + { + let _ = Self::mine_and_submit().map_err(|e| { + let lvl = ::log::Level::Error; + if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { + ::log::__private_api_log( ::core::fmt::Arguments::new_v1( &["\u{1f3e6} error while submitting transaction in OCW: "], &match (&e,) { @@ -3289,32 +3285,32 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 511u32, + 514u32, ), ); - } - }); - } - } + } + }); + } + } } - impl Module - where - ExtendedBalance: From>>, - { - /// Deposits an event using `frame_system::Module::deposit_event`. - fn deposit_event(event: impl Into<::Event>) { - >::deposit_event(event.into()) - } - } - #[cfg(feature = "std")] - impl ::frame_support::traits::IntegrityTest for Module where - ExtendedBalance: From>> - { - } - /// Can also be called using [`Call`]. + impl Module + where + ExtendedBalance: From>>, + { + /// Deposits an event using `frame_system::Module::deposit_event`. + fn deposit_event(event: impl Into<::Event>) { + >::deposit_event(event.into()) + } + } + #[cfg(feature = "std")] + impl ::frame_support::traits::IntegrityTest for Module where + ExtendedBalance: From>> + { + } + /// Can also be called using [`Call`]. /// /// [`Call`]: enum.Call.html - impl Module + impl Module where ExtendedBalance: From>>, { @@ -3329,16 +3325,16 @@ pub mod two_phase { /// might be rewarded, slashed, or get all or a part of the deposit back. /// /// NOTE: Calling this function will bypass origin filters. - fn submit( + fn submit( origin: T::Origin, solution: RawSolution>, ) -> DispatchResultWithPostInfo { - let __within_span__ = { - use ::tracing::__macro_support::Callsite as _; - static CALLSITE: ::tracing::__macro_support::MacroCallsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( + let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( "submit", "frame_election_providers::two_phase", ::tracing::Level::TRACE, @@ -3399,11 +3395,11 @@ pub mod two_phase { } }; }; - >::put(signed_submissions); - Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Signed)); - Ok(None.into()) - } - #[allow(unreachable_code)] + >::put(signed_submissions); + Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Signed)); + Ok(None.into()) + } + #[allow(unreachable_code)] /// Submit a solution for the unsigned phase. /// /// The dispatch origin fo this call must be __signed__. @@ -3420,16 +3416,16 @@ pub mod two_phase { /// No deposit or reward is associated with this. /// /// NOTE: Calling this function will bypass origin filters. - fn submit_unsigned( + fn submit_unsigned( origin: T::Origin, solution: RawSolution>, ) -> ::frame_support::dispatch::DispatchResult { - let __within_span__ = { - use ::tracing::__macro_support::Callsite as _; - static CALLSITE: ::tracing::__macro_support::MacroCallsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( + let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( "submit_unsigned", "frame_election_providers::two_phase", ::tracing::Level::TRACE, @@ -3470,67 +3466,67 @@ pub mod two_phase { "Invalid unsigned submission must produce invalid block and deprive \ validator from their authoring reward.", ); - >::put(ready); - Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); - } - Ok(()) - } + >::put(ready); + Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); + } + Ok(()) + } } - /// Dispatchable calls. - /// - /// Each variant of this enum maps to a dispatchable function from the associated module. - pub enum Call - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[codec(skip)] - __PhantomItem( - ::frame_support::sp_std::marker::PhantomData<(T,)>, - ::frame_support::Never, - ), - #[allow(non_camel_case_types)] - /// Submit a solution for the signed phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// The solution potentially queued, based on the claimed score and processed at the end of - /// the signed phase. - /// - /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution - /// might be rewarded, slashed, or get all or a part of the deposit back. - submit(RawSolution>), - #[allow(non_camel_case_types)] - /// Submit a solution for the unsigned phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. - /// Moreover, this unsigned solution is only validated when submitted to the pool from the - /// local process. Effectively, this means that only active validators can submit this - /// transaction when authoring a block. - /// - /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will - /// panic if the solution submitted by the validator is invalid, effectively putting their - /// authoring reward at risk. - /// - /// No deposit or reward is associated with this. - submit_unsigned(RawSolution>), - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - match *self { + /// Dispatchable calls. + /// + /// Each variant of this enum maps to a dispatchable function from the associated module. + pub enum Call + where + ExtendedBalance: From>>, + { + #[doc(hidden)] + #[codec(skip)] + __PhantomItem( + ::frame_support::sp_std::marker::PhantomData<(T,)>, + ::frame_support::Never, + ), + #[allow(non_camel_case_types)] + /// Submit a solution for the signed phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// The solution potentially queued, based on the claimed score and processed at the end of + /// the signed phase. + /// + /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution + /// might be rewarded, slashed, or get all or a part of the deposit back. + submit(RawSolution>), + #[allow(non_camel_case_types)] + /// Submit a solution for the unsigned phase. + /// + /// The dispatch origin fo this call must be __signed__. + /// + /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. + /// Moreover, this unsigned solution is only validated when submitted to the pool from the + /// local process. Effectively, this means that only active validators can submit this + /// transaction when authoring a block. + /// + /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will + /// panic if the solution submitted by the validator is invalid, effectively putting their + /// authoring reward at risk. + /// + /// No deposit or reward is associated with this. + submit_unsigned(RawSolution>), + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + { + fn encode_to(&self, dest: &mut EncOut) { + match *self { Call::submit(ref aa) => { dest.push_byte(0usize as u8); dest.push(aa); @@ -3541,19 +3537,19 @@ pub mod two_phase { } _ => (), } - } - } - impl _parity_scale_codec::EncodeLike for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - { - } - }; - const _: () = { + } + } + impl _parity_scale_codec::EncodeLike for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + RawSolution>: _parity_scale_codec::Encode, + { + } + }; + const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; @@ -3794,19 +3790,19 @@ pub mod two_phase { } } impl ::frame_support::dispatch::Callable for Module - where - ExtendedBalance: From>>, - { - type Call = Call; - } - impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[allow(dead_code)] - pub fn call_functions() -> &'static [::frame_support::dispatch::FunctionMetadata] { - &[ + where + ExtendedBalance: From>>, + { + type Call = Call; + } + impl Module + where + ExtendedBalance: From>>, + { + #[doc(hidden)] + #[allow(dead_code)] + pub fn call_functions() -> &'static [::frame_support::dispatch::FunctionMetadata] { + &[ ::frame_support::dispatch::FunctionMetadata { name: ::frame_support::dispatch::DecodeDifferent::Encode("submit"), arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ @@ -3857,59 +3853,59 @@ pub mod two_phase { ]), }, ] - } - } - impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[allow(dead_code)] - pub fn module_constants_metadata( - ) -> &'static [::frame_support::dispatch::ModuleConstantMetadata] { - &[] - } - } - impl ::frame_support::dispatch::ModuleErrorMetadata for Module - where - ExtendedBalance: From>>, - { - fn metadata() -> &'static [::frame_support::dispatch::ErrorMetadata] { - as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() - } - } - impl Module - where - ExtendedBalance: From>>, - { - /// Checks the feasibility of a solution. - /// - /// This checks the solution for the following: - /// - /// 0. **all** of the used indices must be correct. - /// 1. present correct number of winners. - /// 2. any assignment is checked to match with `SnapshotVoters`. - /// 3. for each assignment, the check of `ElectionDataProvider` is also examined. - /// 4. the claimed score is valid. - fn feasibility_check( - solution: RawSolution>, - compute: ElectionCompute, - ) -> Result, FeasibilityError> { - let RawSolution { compact, score } = solution; - let winners = compact.unique_targets(); - { - if !(winners.len() as u32 == Self::desired_targets()) { - { - return Err(FeasibilityError::WrongWinnerCount.into()); - }; - } - }; - let snapshot_voters = - Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; - let snapshot_targets = - Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - let voter_at = |i: crate::two_phase::CompactVoterIndexOf| -> Option { - as crate::TryInto>::try_into(i) + } + } + impl Module + where + ExtendedBalance: From>>, + { + #[doc(hidden)] + #[allow(dead_code)] + pub fn module_constants_metadata( + ) -> &'static [::frame_support::dispatch::ModuleConstantMetadata] { + &[] + } + } + impl ::frame_support::dispatch::ModuleErrorMetadata for Module + where + ExtendedBalance: From>>, + { + fn metadata() -> &'static [::frame_support::dispatch::ErrorMetadata] { + as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() + } + } + impl Module + where + ExtendedBalance: From>>, + { + /// Checks the feasibility of a solution. + /// + /// This checks the solution for the following: + /// + /// 0. **all** of the used indices must be correct. + /// 1. present correct number of winners. + /// 2. any assignment is checked to match with `SnapshotVoters`. + /// 3. for each assignment, the check of `ElectionDataProvider` is also examined. + /// 4. the claimed score is valid. + fn feasibility_check( + solution: RawSolution>, + compute: ElectionCompute, + ) -> Result, FeasibilityError> { + let RawSolution { compact, score } = solution; + let winners = compact.unique_targets(); + { + if !(winners.len() as u32 == Self::desired_targets()) { + { + return Err(FeasibilityError::WrongWinnerCount.into()); + }; + } + }; + let snapshot_voters = + Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; + let snapshot_targets = + Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; + let voter_at = |i: crate::two_phase::CompactVoterIndexOf| -> Option { + as crate::TryInto>::try_into(i) .ok() .and_then(|i| snapshot_voters.get(i).map(|(x, _, _)| x).cloned()) }; @@ -3950,45 +3946,195 @@ pub mod two_phase { .find(|(x, _, _)| x == who) .map(|(_, x, _)| *x) .unwrap_or_default() - }; - let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) - .map_err::(Into::into)?; - let supports = sp_npos_elections::to_supports(&winners, &staked_assignments) - .map_err::(Into::into)?; - let known_score = supports.evaluate(); - { - if !(known_score == score) { - { - return Err(FeasibilityError::InvalidScore.into()); - }; - } - }; - Ok(ReadySolution { - supports, - compute, - score, - }) - } - /// On-chain fallback of election. - fn onchain_fallback() -> Result, Error> { - let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - >::elect::( - desired_targets, - targets, - voters, - ) - .map_err(Into::into) - } - } - impl ElectionProvider for Module + }; + let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) + .map_err::(Into::into)?; + let supports = sp_npos_elections::to_supports(&winners, &staked_assignments) + .map_err::(Into::into)?; + let known_score = supports.evaluate(); + ( + match known_score { + tmp => { + { + ::std::io::_eprint(::core::fmt::Arguments::new_v1_formatted( + &["[", ":", "] ", " = ", "\n"], + &match ( + &"frame/election-providers/src/two_phase/mod.rs", + &674u32, + &"known_score", + &&tmp, + ) { + (arg0, arg1, arg2, arg3) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg2, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new(arg3, ::core::fmt::Debug::fmt), + ], + }, + &[ + ::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 1usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 2usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 3usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ], + )); + }; + tmp + } + }, + match score { + tmp => { + { + ::std::io::_eprint(::core::fmt::Arguments::new_v1_formatted( + &["[", ":", "] ", " = ", "\n"], + &match ( + &"frame/election-providers/src/two_phase/mod.rs", + &674u32, + &"score", + &&tmp, + ) { + (arg0, arg1, arg2, arg3) => [ + ::core::fmt::ArgumentV1::new( + arg0, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg1, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new( + arg2, + ::core::fmt::Display::fmt, + ), + ::core::fmt::ArgumentV1::new(arg3, ::core::fmt::Debug::fmt), + ], + }, + &[ + ::core::fmt::rt::v1::Argument { + position: 0usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 1usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 2usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 0u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ::core::fmt::rt::v1::Argument { + position: 3usize, + format: ::core::fmt::rt::v1::FormatSpec { + fill: ' ', + align: ::core::fmt::rt::v1::Alignment::Unknown, + flags: 4u32, + precision: ::core::fmt::rt::v1::Count::Implied, + width: ::core::fmt::rt::v1::Count::Implied, + }, + }, + ], + )); + }; + tmp + } + }, + ); + { + if !(known_score == score) { + { + return Err(FeasibilityError::InvalidScore.into()); + }; + } + }; + Ok(ReadySolution { + supports, + compute, + score, + }) + } + /// On-chain fallback of election. + fn onchain_fallback() -> Result, Error> { + let desired_targets = Self::desired_targets() as usize; + let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + >::elect::( + desired_targets, + targets, + voters, + ) + .map_err(Into::into) + } + } + impl ElectionProvider for Module where ExtendedBalance: From>>, { const NEEDS_ELECT_DATA: bool = false; - type Error = Error; - fn elect( + type Error = Error; + fn elect( _to_elect: usize, _targets: Vec, _voters: Vec<(T::AccountId, VoteWeight, Vec)>, @@ -3996,7 +4142,7 @@ pub mod two_phase { where ExtendedBalance: From<

::Inner>, { - Self::queued_solution() + Self::queued_solution() .map_or_else( || { Self::onchain_fallback() @@ -4030,7 +4176,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 727u32, + 731u32, ), ); } @@ -4057,7 +4203,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 732u32, + 736u32, ), ); } @@ -4070,7 +4216,7 @@ pub mod two_phase { Phase::Signed | Phase::Unsigned(_) => true, _ => false, } - } + } } } const LOG_TARGET: &'static str = "election-provider"; diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index 685ec982129c1..a6541ad3609e0 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -21,14 +21,15 @@ use super::*; use crate::two_phase::{Module as TwoPhase, *}; pub use frame_benchmarking::{account, benchmarks, whitelist_account, whitelisted_caller}; +use frame_support::assert_ok; use rand::{seq::SliceRandom, thread_rng}; use sp_npos_elections::{ExtendedBalance, VoteWeight}; -use frame_support::assert_ok; -use sp_runtime::InnerOf; +use sp_runtime::{InnerOf, PerU16}; const SEED: u32 = 0; -// TODO: the entire snapshot can probably live in a single place.. +// TODO: the entire snapshot can probably live in a single place.. we most often Read and write it +// at the same time. /// Generate mock on-chain snapshots. /// @@ -52,7 +53,7 @@ where .map(|i| { let mut rng = thread_rng(); let stake = 1000_000u64; - let to_vote = rand::random::() % >::LIMIT; + let to_vote = rand::random::() % >::LIMIT + 1; let votes = targets.as_slice().choose_multiple(&mut rng, to_vote).cloned().collect::>(); let voter = account::("Voter", i, SEED); @@ -78,6 +79,81 @@ where DesiredTargets::put(desired_targets); } +/// Creates a **valid** solution with exactly the given size. +/// +/// The snapshot size must be bigger, otherwise this will panic. +fn solution_with_size(active_voters: u32, winners_count: u32) -> RawSolution> +where + ExtendedBalance: From>>, +{ + let voters = >::snapshot_voters().unwrap(); + let targets = >::snapshot_targets().unwrap(); + + // else we cannot support this, self vote is a must. + assert!(active_voters >= winners_count); + // else we won't have enough voters. + assert!(voters.len() >= active_voters as usize); + // else we won't have enough winners + assert!(targets.len() >= winners_count as usize); + + let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); + let voter_at = crate::voter_at_fn!(voters, T::AccountId, T); + let target_at = crate::target_at_fn!(targets, T::AccountId, T); + let stake_of = crate::stake_of_fn!(voters, T::AccountId); + + // First chose random winners. + let mut rng = rand::thread_rng(); + let winners = targets + .as_slice() + .choose_multiple(&mut rng, winners_count as usize) + .cloned() + .collect::>(); + + let mut assignments = winners + .iter() + .map(|w| Assignment { + who: *w, + distribution: vec![(w, PerU16::one())], + }) + .collect::>(); + + // all external voters who are not self vote. + let mut voters_pool = voters + .iter() + .filter(|(x, _, z)| *x != z[0]) + .cloned() + .collect::>(); + while assignments.len() < active_voters as usize { + // pop one of the voters. + let (who, _, votes) = voters_pool.remove(rand::random::() % voters_pool.len()); + // see if it votes for any of the winners. + let winner_intersection = votes + .iter() + .filter(|v| winners.contains(v)) + .cloned() + .collect::>(); + // if any, add assignment to all of them. + if winner_intersection.len() > 0 { + assignments.push(Assignment { + who, + distribution: winner_intersection + .into_iter() + .map(|w| { + ( + w, + PerU16::from_percent((100 / winner_intersection.len()) as u16), + ) + }) + .collect::>(), + }) + } + } + + let compact = >::from_assignment(assignments, &voter_index, &target_index); + + unimplemented!() +} + benchmarks! { where_clause { where ExtendedBalance: From>>, } _{} @@ -89,14 +165,14 @@ benchmarks! { // This is checking a valid solution. The worse case is indeed a valid solution. feasibility_check { // number of votes in snapshot. - let v in 2000 .. 3000; + let v in 200 .. 300; // number of targets in snapshot. - let t in 500 .. 800; + let t in 50 .. 80; // number of assignments, i.e. compact.len(). This means the active nominators, thus must be // a subset of `v` component. - let a in 200 .. 800; + let a in 20 .. 80; // number of desired targets. Must be a subset of `t` component. - let d in 200 .. 400; + let d in 20 .. 40; println!("running v {}, t {}, a {}, d {}", v, t, a, d); @@ -104,14 +180,25 @@ benchmarks! { put_mock_snapshot::(witness, d); let voters = >::snapshot_voters().unwrap(); + let targets = >::snapshot_targets().unwrap(); + let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); + let voter_at = crate::voter_at_fn!(voters, T::AccountId, T); + let target_at = crate::target_at_fn!(targets, T::AccountId, T); + let stake_of = crate::stake_of_fn!(voters, T::AccountId); - let RawSolution { compact, score } = >::mine_solution(0).unwrap(); + // the score at this point is not usable -- It might change when we resize the compact. + let RawSolution { compact, score: _ } = >::mine_solution(0).unwrap(); let compact = >::trim_compact(a, compact, voter_index).unwrap(); assert_eq!(compact.len() as u32, a); assert_eq!(compact.unique_targets().len() as u32, d); + // re-calc score. + let winners = compact.unique_targets().iter().map(|i| target_at(*i).unwrap()).collect::>(); + let score = compact + .clone() + .score(&winners, stake_of, voter_at, target_at).unwrap(); let raw_solution = RawSolution { compact, score }; let compute = ElectionCompute::Unsigned; }: { diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 614d9903796f8..71644a3b4509b 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -1,6 +1,7 @@ use super::*; use frame_support::{parameter_types, traits::OnInitialize}; use parking_lot::RwLock; +use rand::seq::SliceRandom; use sp_core::{ offchain::{ testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, @@ -11,7 +12,7 @@ use sp_core::{ use sp_election_providers::ElectionDataProvider; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, to_without_backing, - CompactSolution, ElectionResult, EvaluateSupport, + Assignment, CompactSolution, ElectionResult, EvaluateSupport, }; use sp_runtime::{ testing::Header, diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 34b7a52aa8d56..717e963b07ca0 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -137,8 +137,8 @@ impl __OrInvalidIndex for Option { /// See [`compact`] for more info. pub trait CompactSolution: Sized { const LIMIT: usize; - type Voter: UniqueSaturatedInto + TryInto + TryFrom + Debug; - type Target: UniqueSaturatedInto + TryInto + TryFrom + Debug; + type Voter: UniqueSaturatedInto + TryInto + TryFrom + Debug + Copy + Clone; + type Target: UniqueSaturatedInto + TryInto + TryFrom + Debug + Copy + Clone; type VoteWeight: PerThing128; fn from_assignment( @@ -191,6 +191,8 @@ pub trait CompactSolution: Sized { /// Compute the score of this compact solution type. fn score( self, + // TODO: this param is just for error checking.. we can remove it if we make the error API + // better. winners: &[A], stake_of: FS, voter_at: impl Fn(Self::Voter) -> Option, From 9841e3b189a047e8e9df50f979fb3e3095478f2b Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 20 Oct 2020 15:17:20 +0200 Subject: [PATCH 16/62] node-runtime builds. --- Cargo.lock | 2 + bin/node/runtime/Cargo.toml | 3 + bin/node/runtime/src/lib.rs | 44 ++++-- .../runtime/src/weights/pallet_staking.rs | 11 -- .../src/two_phase/benchmarking.rs | 127 ++++++++++------ .../election-providers/src/two_phase/mock.rs | 32 +++- frame/election-providers/src/two_phase/mod.rs | 143 +++++++++++------- .../src/two_phase/signed.rs | 28 +++- .../src/two_phase/unsigned.rs | 105 ++++++++----- frame/staking/Cargo.toml | 3 + frame/staking/src/lib.rs | 6 +- primitives/arithmetic/src/per_things.rs | 7 +- primitives/npos-elections/src/lib.rs | 5 +- 13 files changed, 335 insertions(+), 181 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0d253899f24e..0bd7d07d4a3d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3894,6 +3894,7 @@ name = "node-runtime" version = "2.0.0" dependencies = [ "frame-benchmarking", + "frame-election-providers", "frame-executive", "frame-support", "frame-system", @@ -4916,6 +4917,7 @@ dependencies = [ "serde", "sp-application-crypto", "sp-core", + "sp-election-providers", "sp-io", "sp-npos-elections", "sp-runtime", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 6142998ac063c..a8621de18f221 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -42,6 +42,7 @@ frame-executive = { version = "2.0.0", default-features = false, path = "../../. frame-benchmarking = { version = "2.0.0", default-features = false, path = "../../../frame/benchmarking", optional = true } frame-support = { version = "2.0.0", default-features = false, path = "../../../frame/support" } frame-system = { version = "2.0.0", default-features = false, path = "../../../frame/system" } +frame-election-providers = { version = "2.0.0", default-features = false, path = "../../../frame/election-providers/" } frame-system-benchmarking = { version = "2.0.0", default-features = false, path = "../../../frame/system/benchmarking", optional = true } frame-system-rpc-runtime-api = { version = "2.0.0", default-features = false, path = "../../../frame/system/rpc/runtime-api/" } pallet-authority-discovery = { version = "2.0.0", default-features = false, path = "../../../frame/authority-discovery" } @@ -134,6 +135,7 @@ std = [ "frame-benchmarking/std", "frame-system-rpc-runtime-api/std", "frame-system/std", + "frame-election-providers/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", @@ -149,6 +151,7 @@ runtime-benchmarks = [ "frame-benchmarking", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "frame-election-providers/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "pallet-babe/runtime-benchmarks", "pallet-balances/runtime-benchmarks", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 04381d50a2afa..1d97d355f6a2f 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -70,6 +70,8 @@ use pallet_session::{historical as pallet_session_historical}; use sp_inherents::{InherentData, CheckInherentsResult}; use static_assertions::const_assert; +use frame_election_providers::two_phase as two_phase; + #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; #[cfg(any(feature = "std", test))] @@ -468,18 +470,41 @@ impl pallet_staking::Trait for Runtime { type SessionInterface = Self; type RewardCurve = RewardCurve; type NextNewSession = Session; - type ElectionLookahead = ElectionLookahead; - type Call = Call; - type MaxIterations = MaxIterations; - type MinSolutionScoreBump = MinSolutionScoreBump; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; - type UnsignedPriority = StakingUnsignedPriority; - // The unsigned solution weight targeted by the OCW. We set it to the maximum possible value of - // a single extrinsic. - type OffchainSolutionWeightLimit = OffchainSolutionWeightLimit; + type ElectionProvider = TwoPhaseElectionProvdier; type WeightInfo = weights::pallet_staking::WeightInfo; } +parameter_types! { + pub const SignedPhase: u32 = 50; + pub const UnsignedPhase: u32 = 50; + pub const MaxSignedSubmissions: u32 = 10; + pub const SignedRewardBase: Balance = 1 * DOLLARS; + pub const SignedDepositBase: Balance = 1 * DOLLARS; + pub const MaxUnsignedIterations: u32 = 10; +} + +impl two_phase::Trait for Runtime { + type Event = Event; + type Currency = Balances; + type SignedPhase = SignedPhase; + type UnsignedPhase = UnsignedPhase; + type MaxSignedSubmissions = MaxSignedSubmissions; + type SignedRewardBase = SignedRewardBase; + type SignedRewardFactor = (); + type SignedRewardMax = (); + type SignedDepositBase = SignedDepositBase; + type SignedDepositByte = (); + type SignedDepositWeight = (); + type SolutionImprovementThreshold = (); + type SlashHandler = (); + type RewardHandler = (); + type UnsignedMaxIterations = MaxUnsignedIterations; + type UnsignedPriority = (); + type ElectionDataProvider = Staking; + type WeightInfo = (); +} + parameter_types! { pub const LaunchPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; pub const VotingPeriod: BlockNumber = 28 * 24 * 60 * MINUTES; @@ -920,7 +945,8 @@ construct_runtime!( Indices: pallet_indices::{Module, Call, Storage, Config, Event}, Balances: pallet_balances::{Module, Call, Storage, Config, Event}, TransactionPayment: pallet_transaction_payment::{Module, Storage}, - Staking: pallet_staking::{Module, Call, Config, Storage, Event, ValidateUnsigned}, + TwoPhaseElectionProvdier: two_phase::{Module, Call, Storage, Event, ValidateUnsigned}, + Staking: pallet_staking::{Module, Call, Config, Storage, Event}, Session: pallet_session::{Module, Call, Storage, Event, Config}, Democracy: pallet_democracy::{Module, Call, Storage, Config, Event}, Council: pallet_collective::::{Module, Call, Storage, Origin, Event, Config}, diff --git a/bin/node/runtime/src/weights/pallet_staking.rs b/bin/node/runtime/src/weights/pallet_staking.rs index a4484a2685949..2793a941af79a 100644 --- a/bin/node/runtime/src/weights/pallet_staking.rs +++ b/bin/node/runtime/src/weights/pallet_staking.rs @@ -157,15 +157,4 @@ impl pallet_staking::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().writes(8 as Weight)) .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) } - fn submit_solution_better(v: u32, n: u32, a: u32, w: u32, ) -> Weight { - (0 as Weight) - .saturating_add((964000 as Weight).saturating_mul(v as Weight)) - .saturating_add((432000 as Weight).saturating_mul(n as Weight)) - .saturating_add((204294000 as Weight).saturating_mul(a as Weight)) - .saturating_add((9546000 as Weight).saturating_mul(w as Weight)) - .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(a as Weight))) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(w as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - } } diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index a6541ad3609e0..ad216712d4eed 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -22,15 +22,13 @@ use crate::two_phase::{Module as TwoPhase, *}; pub use frame_benchmarking::{account, benchmarks, whitelist_account, whitelisted_caller}; use frame_support::assert_ok; +use frame_system::RawOrigin; use rand::{seq::SliceRandom, thread_rng}; -use sp_npos_elections::{ExtendedBalance, VoteWeight}; -use sp_runtime::{InnerOf, PerU16}; +use sp_npos_elections::{CompactSolution, ExtendedBalance, VoteWeight}; +use sp_runtime::InnerOf; const SEED: u32 = 0; -// TODO: the entire snapshot can probably live in a single place.. we most often Read and write it -// at the same time. - /// Generate mock on-chain snapshots. /// /// This emulates the start of signed phase, where snapshots are received from an upstream crate. @@ -74,9 +72,12 @@ where ExtendedBalance: From>>, { let (targets, voters) = mock_snapshot::(witness); - >::put(targets); - >::put(voters); - DesiredTargets::put(desired_targets); + let snapshot = SnapshotData { + voters, + targets, + desired_targets, + }; + >::put(snapshot); } /// Creates a **valid** solution with exactly the given size. @@ -86,8 +87,9 @@ fn solution_with_size(active_voters: u32, winners_count: u32) -> RawSo where ExtendedBalance: From>>, { - let voters = >::snapshot_voters().unwrap(); - let targets = >::snapshot_targets().unwrap(); + let SnapshotData { + voters, targets, .. + } = >::snapshot().unwrap(); // else we cannot support this, self vote is a must. assert!(active_voters >= winners_count); @@ -97,6 +99,7 @@ where assert!(targets.len() >= winners_count as usize); let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); + let target_index = crate::target_index_fn!(targets, T::AccountId, T); let voter_at = crate::voter_at_fn!(voters, T::AccountId, T); let target_at = crate::target_at_fn!(targets, T::AccountId, T); let stake_of = crate::stake_of_fn!(voters, T::AccountId); @@ -112,8 +115,8 @@ where let mut assignments = winners .iter() .map(|w| Assignment { - who: *w, - distribution: vec![(w, PerU16::one())], + who: w.clone(), + distribution: vec![(w.clone(), >::one())], }) .collect::>(); @@ -134,6 +137,7 @@ where .collect::>(); // if any, add assignment to all of them. if winner_intersection.len() > 0 { + let dist = (100 / winner_intersection.len()) as u8; assignments.push(Assignment { who, distribution: winner_intersection @@ -141,7 +145,7 @@ where .map(|w| { ( w, - PerU16::from_percent((100 / winner_intersection.len()) as u16), + >::from_percent(dist.into()), ) }) .collect::>(), @@ -149,57 +153,88 @@ where } } - let compact = >::from_assignment(assignments, &voter_index, &target_index); + let compact = + >::from_assignment(assignments, &voter_index, &target_index).unwrap(); + let score = compact + .clone() + .score(winners.as_ref(), stake_of, voter_at, target_at) + .unwrap(); + let round = >::round(); - unimplemented!() + RawSolution { compact, score, round } } benchmarks! { where_clause { where ExtendedBalance: From>>, } _{} - submit_signed {}: {} verify {} - submit_unsigned {}: {} verify {} - open_signed_phase {}: {} verify {} - close_signed_phase {}: {} verify {} - // This is checking a valid solution. The worse case is indeed a valid solution. - feasibility_check { + submit { // number of votes in snapshot. - let v in 200 .. 300; + let v in 2000 .. 3000; // number of targets in snapshot. - let t in 50 .. 80; + let t in 500 .. 800; // number of assignments, i.e. compact.len(). This means the active nominators, thus must be // a subset of `v` component. - let a in 20 .. 80; + let a in 500 .. 1500; // number of desired targets. Must be a subset of `t` component. - let d in 20 .. 40; + let d in 200 .. 400; + + let witness = WitnessData { voters: v, targets: t }; + put_mock_snapshot::(witness, d); - println!("running v {}, t {}, a {}, d {}", v, t, a, d); + let raw_solution = solution_with_size::(a, d); + assert!(>::signed_submissions().len() == 0); + >::put(Phase::Signed); + + let caller = frame_benchmarking::whitelisted_caller(); + T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance() * 10u32.into()); + + }: _(RawOrigin::Signed(caller), raw_solution) + verify { + assert!(>::signed_submissions().len() == 1); + } + + submit_unsigned { + // number of votes in snapshot. + let v in 2000 .. 3000; + // number of targets in snapshot. + let t in 500 .. 800; + // number of assignments, i.e. compact.len(). This means the active nominators, thus must be + // a subset of `v` component. + let a in 500 .. 1500; + // number of desired targets. Must be a subset of `t` component. + let d in 200 .. 400; let witness = WitnessData { voters: v, targets: t }; put_mock_snapshot::(witness, d); - let voters = >::snapshot_voters().unwrap(); - let targets = >::snapshot_targets().unwrap(); + let raw_solution = solution_with_size::(a, d); + assert!(>::queued_solution().is_none()); + >::put(Phase::Unsigned((true, 1u32.into()))); + }: _(RawOrigin::None, raw_solution, witness) + verify { + assert!(>::queued_solution().is_some()); + } - let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); - let voter_at = crate::voter_at_fn!(voters, T::AccountId, T); - let target_at = crate::target_at_fn!(targets, T::AccountId, T); - let stake_of = crate::stake_of_fn!(voters, T::AccountId); + open_signed_phase {}: {} verify {} + close_signed_phase {}: {} verify {} - // the score at this point is not usable -- It might change when we resize the compact. - let RawSolution { compact, score: _ } = >::mine_solution(0).unwrap(); - let compact = >::trim_compact(a, compact, voter_index).unwrap(); + // This is checking a valid solution. The worse case is indeed a valid solution. + feasibility_check { + // number of votes in snapshot. + let v in 2000 .. 3000; + // number of targets in snapshot. + let t in 500 .. 800; + // number of assignments, i.e. compact.len(). This means the active nominators, thus must be + // a subset of `v` component. + let a in 500 .. 1500; + // number of desired targets. Must be a subset of `t` component. + let d in 200 .. 400; - assert_eq!(compact.len() as u32, a); - assert_eq!(compact.unique_targets().len() as u32, d); + let witness = WitnessData { voters: v, targets: t }; + put_mock_snapshot::(witness, d); - // re-calc score. - let winners = compact.unique_targets().iter().map(|i| target_at(*i).unwrap()).collect::>(); - let score = compact - .clone() - .score(&winners, stake_of, voter_at, target_at).unwrap(); - let raw_solution = RawSolution { compact, score }; + let raw_solution = solution_with_size::(a, d); let compute = ElectionCompute::Unsigned; }: { assert_ok!(>::feasibility_check(raw_solution, compute)); @@ -215,6 +250,10 @@ mod test { fn test_benchmarks() { ExtBuilder::default().build_and_execute(|| { assert_ok!(test_benchmark_feasibility_check::()); - }) + }); + + ExtBuilder::default().build_and_execute(|| { + assert_ok!(test_benchmark_submit_unsigned::()); + }); } } diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 71644a3b4509b..c9e198bdd8e7f 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -1,7 +1,6 @@ use super::*; use frame_support::{parameter_types, traits::OnInitialize}; use parking_lot::RwLock; -use rand::seq::SliceRandom; use sp_core::{ offchain::{ testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, @@ -12,7 +11,7 @@ use sp_core::{ use sp_election_providers::ElectionDataProvider; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, to_without_backing, - Assignment, CompactSolution, ElectionResult, EvaluateSupport, + CompactSolution, ElectionResult, EvaluateSupport, }; use sp_runtime::{ testing::Header, @@ -54,9 +53,11 @@ pub fn balances(who: &AccountId) -> (Balance, Balance) { /// /// This is a good example of what an offchain miner would do. pub fn raw_solution() -> RawSolution> { - let voters = TwoPhase::snapshot_voters().unwrap(); - let targets = TwoPhase::snapshot_targets().unwrap(); - let desired = TwoPhase::desired_targets() as usize; + let SnapshotData { + voters, + targets, + desired_targets, + } = TwoPhase::snapshot().unwrap(); // closures let voter_index = crate::voter_index_fn!(voters, AccountId, Runtime); @@ -66,8 +67,13 @@ pub fn raw_solution() -> RawSolution> { let ElectionResult { winners, assignments, - } = seq_phragmen::<_, CompactAccuracyOf>(desired, targets.clone(), voters.clone(), None) - .unwrap(); + } = seq_phragmen::<_, CompactAccuracyOf>( + desired_targets as usize, + targets.clone(), + voters.clone(), + None, + ) + .unwrap(); let winners = to_without_backing(winners); @@ -78,7 +84,17 @@ pub fn raw_solution() -> RawSolution> { let compact = >::from_assignment(assignments, &voter_index, &target_index).unwrap(); - RawSolution { compact, score } + let round = TwoPhase::round(); + RawSolution { compact, score, round } +} + +pub fn witness() -> WitnessData { + TwoPhase::snapshot() + .map(|snap| WitnessData { + voters: snap.voters.len() as u32, + targets: snap.targets.len() as u32, + }) + .unwrap_or_default() } frame_support::impl_outer_dispatch! { diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 742fbf13394da..d5da77cd44205 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -224,12 +224,21 @@ impl Default for ElectionCompute { /// /// Such a solution should never become effective in anyway before being checked by the /// [`Module::feasibility_check`] -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] pub struct RawSolution { /// Compact election edges. compact: C, /// The _claimed_ score of the solution. score: ElectionScore, + /// The round at which this solution should be submitted. + round: u32, +} + +impl Default for RawSolution { + fn default() -> Self { + // Round 0 is always invalid, only set this to 1. + Self { round: 1, compact: Default::default(), score: Default::default() } + } } /// A raw, unchecked signed submission. @@ -278,6 +287,17 @@ pub struct WitnessData { targets: u32, } +/// Snapshot data stored onchain for the duration of the election. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] +pub struct SnapshotData { + /// All voters. + voters: Vec<(AccountId, VoteWeight, Vec)>, + /// All targets + targets: Vec, + /// Desired number of targets, + desired_targets: u32, +} + /// The crate errors. Note that this is different from the [`PalletError`]. #[derive(RuntimeDebug, Eq, PartialEq)] pub enum Error { @@ -336,19 +356,19 @@ impl From for FeasibilityError { /// The weights for this pallet. pub trait WeightInfo { - fn feasibility_check() -> Weight; - fn submit() -> Weight; - fn submit_unsigned() -> Weight; + fn feasibility_check(v: u32, t: u32, a: u32, d: u32) -> Weight; + fn submit(v: u32, t: u32, a: u32, d: u32) -> Weight; + fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight; } impl WeightInfo for () { - fn feasibility_check() -> Weight { + fn feasibility_check(_: u32, _: u32, _: u32, _: u32) -> Weight { Default::default() } - fn submit() -> Weight { + fn submit(_: u32, _: u32, _: u32, _: u32) -> Weight { Default::default() } - fn submit_unsigned() -> Weight { + fn submit_unsigned(_: u32, _: u32, _: u32, _: u32) -> Weight { Default::default() } } @@ -414,20 +434,10 @@ decl_storage! { /// Current best solution, signed or unsigned. pub QueuedSolution get(fn queued_solution): Option>; - /// Snapshot of all Voters. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub SnapshotTargets get(fn snapshot_targets): Option>; - - /// Snapshot of all targets. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub SnapshotVoters get(fn snapshot_voters): Option)>>; - - /// Desired number of targets to elect. + /// Snapshot of all voters, all targets and desired targets to elect. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub DesiredTargets get(fn desired_targets): u32; + pub Snapshot get(fn snapshot): Option>; } } @@ -458,6 +468,10 @@ frame_support::decl_error! { QueueFull, /// The origin failed to pay the deposit. CannotPayDeposit, + /// WitnessData is invalid. + InvalidWitness, + /// Round number is invalid. + InvalidRound, } } @@ -485,7 +499,7 @@ decl_module! { >::put(Phase::Signed); Round::mutate(|r| *r +=1); Self::start_signed_phase(); - log!(info, "Starting signed phase at #{} , round {}", now, Self::round()); + log!(info, "Starting signed phase at #{:?} , round {}.", now, Self::round()); }, Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { // check the unsigned phase. @@ -494,7 +508,7 @@ decl_module! { // good middle ground for now is to always let the unsigned phase be open. let found_solution = Self::finalize_signed_phase(); >::put(Phase::Unsigned((!found_solution, now))); - log!(info, "Starting unsigned phase at #{}", now); + log!(info, "Starting unsigned phase at #{:?}.", now); }, _ => { // Nothing. We wait in the unsigned phase until we receive the call to `elect`. @@ -525,17 +539,30 @@ decl_module! { /// /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution /// might be rewarded, slashed, or get all or a part of the deposit back. - #[weight = T::WeightInfo::submit()] + #[weight = T::WeightInfo::submit(0, 0, 0, 0)] fn submit(origin, solution: RawSolution>) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; // ensure solution is timely. ensure!(Self::current_phase().is_signed(), PalletError::::EarlySubmission); + // ensure round is correct. + ensure!(Self::round() == solution.round, PalletError::::InvalidRound); + + // TODO: this is the only case where having separate snapshot would have been better + // bewe could do just decode_len. + + // build witness. + // defensive-only: if phase is singend, snapshot will exist. + let SnapshotData { voters, targets, .. } = Self::snapshot().unwrap_or_default(); + let witness = WitnessData { voters: voters.len() as u32, targets: targets.len() as u32 }; + + + // ensure solution claims is better. let mut signed_submissions = Self::signed_submissions(); - let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution); - ensure!(maybe_index.is_some(), "QueueFull"); + let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution, witness); + ensure!(maybe_index.is_some(), PalletError::::QueueFull); let index = maybe_index.expect("Option checked to be `Some`; qed."); // collect deposit. Thereafter, the function cannot fail. @@ -564,8 +591,13 @@ decl_module! { /// authoring reward at risk. /// /// No deposit or reward is associated with this. - #[weight = T::WeightInfo::submit_unsigned()] - fn submit_unsigned(origin, solution: RawSolution>) { + #[weight = T::WeightInfo::submit_unsigned( + witness.voters, + witness.targets, + solution.compact.len() as u32, + solution.compact.unique_targets().len() as u32 + )] + fn submit_unsigned(origin, solution: RawSolution>, witness: WitnessData) { ensure_none(origin)?; // check phase and score. @@ -573,6 +605,11 @@ decl_module! { // here. let _ = Self::pre_dispatch_checks(&solution)?; + // ensure witness was correct. + let SnapshotData { voters, targets, .. } = Self::snapshot().unwrap_or_default(); + ensure!(voters.len() as u32 == witness.voters, PalletError::::InvalidWitness); + ensure!(targets.len() as u32 == witness.targets, PalletError::::InvalidWitness); + let ready = Self::feasibility_check(solution, ElectionCompute::Unsigned) .expect( @@ -604,7 +641,7 @@ where solution: RawSolution>, compute: ElectionCompute, ) -> Result, FeasibilityError> { - let RawSolution { compact, score } = solution; + let RawSolution { compact, score, .. } = solution; // winners are not directly encoded in the solution. // TODO: dupe winner @@ -612,19 +649,19 @@ where let winners = compact.unique_targets(); // Ensure that we have received enough winners. + let SnapshotData { + voters, + targets, + desired_targets, + } = Self::snapshot().ok_or(FeasibilityError::SnapshotUnavailable)?; ensure!( - winners.len() as u32 == Self::desired_targets(), - FeasibilityError::WrongWinnerCount + winners.len() as u32 == desired_targets, + FeasibilityError::WrongWinnerCount, ); // ----- Start building. First, we need some closures. - let snapshot_voters = - Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; - let snapshot_targets = - Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - - let voter_at = crate::voter_at_fn!(snapshot_voters, T::AccountId, T); - let target_at = crate::target_at_fn!(snapshot_targets, T::AccountId, T); + let voter_at = crate::voter_at_fn!(voters, T::AccountId, T); + let target_at = crate::target_at_fn!(targets, T::AccountId, T); // first, make sure that all the winners are sane. let winners = winners @@ -642,7 +679,7 @@ where let _ = assignments .iter() .map(|Assignment { who, distribution }| { - snapshot_voters.iter().find(|(v, _, _)| v == who).map_or( + voters.iter().find(|(v, _, _)| v == who).map_or( Err(FeasibilityError::InvalidVoter), |(_, _, t)| { if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) @@ -660,7 +697,7 @@ where .collect::>()?; // ----- Start building support. First, we need some more closures. - let stake_of = stake_of_fn!(snapshot_voters, T::AccountId); + let stake_of = stake_of_fn!(voters, T::AccountId); // This might fail if the normalization fails. Very unlikely. let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) @@ -671,7 +708,6 @@ where // Finally, check that the claimed score was indeed correct. let known_score = supports.evaluate(); - dbg!(known_score, score); ensure!(known_score == score, FeasibilityError::InvalidScore); // let supports = supports.flatten(); @@ -684,11 +720,13 @@ where /// On-chain fallback of election. fn onchain_fallback() -> Result, Error> { - let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - >::elect::( + let SnapshotData { + voters, + targets, desired_targets, + } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; + >::elect::( + desired_targets as usize, targets, voters, ) @@ -724,8 +762,7 @@ where // reset phase. >::put(Phase::Off); // clear snapshots. - >::kill(); - >::kill(); + >::kill(); Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); log!(info, "Finalized election round with compute {:?}.", compute); @@ -762,40 +799,40 @@ mod tests { roll_to(4); assert_eq!(TwoPhase::current_phase(), Phase::Off); - assert!(TwoPhase::snapshot_voters().is_none()); + assert!(TwoPhase::snapshot().is_none()); assert_eq!(TwoPhase::round(), 0); roll_to(5); assert_eq!(TwoPhase::current_phase(), Phase::Signed); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); assert_eq!(TwoPhase::round(), 1); roll_to(14); assert_eq!(TwoPhase::current_phase(), Phase::Signed); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); assert_eq!(TwoPhase::round(), 1); roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); roll_to(19); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); roll_to(20); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); // we close when upstream tells us to elect. roll_to(21); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); TwoPhase::elect::(2, Default::default(), Default::default()) .unwrap(); assert_eq!(TwoPhase::current_phase(), Phase::Off); - assert!(TwoPhase::snapshot_voters().is_none()); + assert!(TwoPhase::snapshot().is_none()); assert_eq!(TwoPhase::round(), 1); }) } diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index 8c0a49987b2c4..2343a9fd6a7a6 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -22,6 +22,7 @@ use codec::Encode; use sp_arithmetic::traits::SaturatedConversion; use sp_npos_elections::is_score_better; use sp_runtime::Perbill; +use sp_npos_elections::CompactSolution; impl Module where @@ -38,9 +39,11 @@ where let voters = T::ElectionDataProvider::voters(); let desired_targets = T::ElectionDataProvider::desired_targets(); - >::put(targets); - >::put(voters); - DesiredTargets::put(desired_targets); + >::put(SnapshotData { + voters, + targets, + desired_targets, + }); } /// Finish the singed phase. Process the signed submissions from best to worse until a valid one @@ -105,6 +108,7 @@ where who: &T::AccountId, queue: &mut Vec, CompactOf>>, solution: RawSolution>, + witness: WitnessData, ) -> Option { // from the last score, compare and see if the current one is better. If none, then the // awarded index is 0. @@ -131,7 +135,7 @@ where } else { // add to the designated spot. If the length is too much, remove one. let reward = Self::reward_for(&solution); - let deposit = Self::deposit_for(&solution); + let deposit = Self::deposit_for(&solution, witness); let submission = SignedSubmission { who: who.clone(), deposit, @@ -162,9 +166,14 @@ where /// 1. base deposit, fixed for all submissions. /// 2. a per-byte deposit, for renting the state usage. /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize - pub fn deposit_for(solution: &RawSolution>) -> BalanceOf { + pub fn deposit_for(solution: &RawSolution>, witness: WitnessData) -> BalanceOf { let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); - let feasibility_weight = T::WeightInfo::feasibility_check(); + let feasibility_weight = T::WeightInfo::feasibility_check( + witness.voters, + witness.targets, + solution.compact.len() as u32, + solution.compact.unique_targets().len() as u32, + ); let len_deposit = T::SignedDepositByte::get() * encoded_len; let weight_deposit = T::SignedDepositWeight::get() * feasibility_weight.saturated_into(); @@ -343,7 +352,7 @@ mod tests { assert_noop!( TwoPhase::submit(Origin::signed(99), solution), - "QueueFull", + PalletError::::QueueFull, ); }) } @@ -417,7 +426,7 @@ mod tests { }; assert_noop!( TwoPhase::submit(Origin::signed(99), solution), - "QueueFull", + PalletError::::QueueFull, ); }) } @@ -529,4 +538,7 @@ mod tests { assert_eq!(balances(&9999), (100, 0)); }) } + + #[test] + fn invalid_round_fails() {} } diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 31090121db1a0..8186a506d8d4e 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -45,14 +45,21 @@ where ExtendedBalance: From>>, { /// Min a new npos solution. - pub fn mine_solution(iters: usize) -> Result>, Error> { - let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - - seq_phragmen::<_, CompactAccuracyOf>(desired_targets, targets, voters, Some((iters, 0))) - .map_err(Into::into) - .and_then(Self::prepare_election_result) + pub fn mine_solution(iters: usize) -> Result<(RawSolution>, WitnessData), Error> { + let SnapshotData { + voters, + targets, + desired_targets, + } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; + + seq_phragmen::<_, CompactAccuracyOf>( + desired_targets as usize, + targets, + voters, + Some((iters, 0)), + ) + .map_err(Into::into) + .and_then(Self::prepare_election_result) } /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which @@ -61,10 +68,12 @@ where /// Will always reduce the solution as well. pub fn prepare_election_result( election_result: ElectionResult>, - ) -> Result>, Error> { - // storage items. - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + ) -> Result<(RawSolution>, WitnessData), Error> { + // storage items. NOTE: we read these in mine_solution and here again, but this is fine + // since only the first read is expensive. + let SnapshotData { + voters, targets, .. + } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; // closures. let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); @@ -99,7 +108,12 @@ where .clone() .score(&winners, stake_of, voter_at, target_at)?; - Ok(RawSolution { compact, score }) + let witness = WitnessData { + voters: voters.len() as u32, + targets: targets.len() as u32, + }; + let round = Self::round(); + Ok((RawSolution { compact, score, round }, witness)) } /// Get a random number of iterations to run the balancing in the OCW. @@ -145,7 +159,7 @@ where match compact.len().checked_sub(maximum_allowed_voters as usize) { Some(to_remove) if to_remove > 0 => { // grab all voters and sort them by least stake. - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let SnapshotData { voters, .. } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; let mut voters_sorted = voters .into_iter() .map(|(who, stake, _)| (who.clone(), stake)) @@ -182,7 +196,7 @@ where /// /// This only returns a value between zero and `size.nominators`. pub fn maximum_compact_len( - _winners_len: u32, + desired_winners: u32, witness: WitnessData, max_weight: Weight, ) -> u32 { @@ -194,7 +208,14 @@ where let mut voters = max_voters; // helper closures. - let weight_with = |_voters: u32| -> Weight { W::submit_unsigned() }; + let weight_with = |active_voters: u32| -> Weight { + W::submit_unsigned( + witness.voters, + witness.targets, + active_voters, + desired_winners, + ) + }; let next_voters = |current_weight: Weight, voters: u32, step: u32| -> Result { match current_weight.cmp(&max_weight) { @@ -291,15 +312,16 @@ where /// Mine a new solution, and submit it back to the chian as an unsigned transaction. pub(crate) fn mine_and_submit() -> Result<(), Error> { let balancing = Self::get_balancing_iters(); - Self::mine_solution(balancing).and_then(|raw_solution| { + Self::mine_solution(balancing).and_then(|(raw_solution, witness)| { // submit the raw solution to the pool. - let call = Call::submit_unsigned(raw_solution).into(); + let call = Call::submit_unsigned(raw_solution, witness).into(); SubmitTransaction::>::submit_unsigned_transaction(call) .map_err(|_| Error::PoolSubmissionFailed) }) } + /// Checks that need to happen in the validte_unsigned and pre_dispatch. pub(crate) fn pre_dispatch_checks(solution: &RawSolution>) -> DispatchResult { // ensure solution is timely. Don't panic yet. This is a cheap check. ensure!( @@ -328,7 +350,7 @@ where { type Call = Call; fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { - if let Call::submit_unsigned(solution) = call { + if let Call::submit_unsigned(solution, _) = call { // discard solution not coming from the local OCW. match source { TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } @@ -346,7 +368,7 @@ where .priority( T::UnsignedPriority::get().saturating_add(solution.score[0].saturated_into()), ) - // TODO: need some provides to de-duplicate. + // TODO: need some provides to de-duplicate: use Round. // TODO: we can do this better. .longevity(DEFAULT_LONGEVITY) // We don't propagate this. This can never the validated at a remote node. @@ -358,7 +380,7 @@ where } fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { - if let Call::submit_unsigned(solution) = call { + if let Call::submit_unsigned(solution, _) = call { Self::pre_dispatch_checks(solution).map_err(|_| InvalidTransaction::Custom(99).into()) } else { Err(InvalidTransaction::Call.into()) @@ -526,7 +548,7 @@ mod tests { score: [5, 0, 0], ..Default::default() }; - let call = Call::submit_unsigned(solution.clone()); + let call = Call::submit_unsigned(solution.clone(), witness()); // initial assert_eq!(TwoPhase::current_phase(), Phase::Off); @@ -576,7 +598,7 @@ mod tests { score: [5, 0, 0], ..Default::default() }; - let call = Call::submit_unsigned(solution.clone()); + let call = Call::submit_unsigned(solution.clone(), witness()); // initial assert!(::validate_unsigned( @@ -618,7 +640,7 @@ mod tests { score: [5, 0, 0], ..Default::default() }; - let call = Call::submit_unsigned(solution.clone()); + let call = Call::submit_unsigned(solution.clone(), witness()); // initial assert_eq!( @@ -649,7 +671,7 @@ mod tests { score: [5, 0, 0], ..Default::default() }; - let call = Call::submit_unsigned(solution.clone()); + let call = Call::submit_unsigned(solution.clone(), witness()); let outer_call: OuterCall = call.into(); let _ = outer_call.dispatch(Origin::none()); }) @@ -662,16 +684,15 @@ mod tests { assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); // ensure we have snapshots in place. - assert!(TwoPhase::snapshot_voters().is_some()); - assert!(TwoPhase::snapshot_targets().is_some()); - assert_eq!(TwoPhase::desired_targets(), 2); + assert!(TwoPhase::snapshot().is_some()); + assert_eq!(TwoPhase::snapshot().unwrap().desired_targets, 2); // mine seq_phragmen solution with 2 iters. - let solution = TwoPhase::mine_solution(2).unwrap(); + let (solution, witness) = TwoPhase::mine_solution(2).unwrap(); // ensure this solution is valid. assert!(TwoPhase::queued_solution().is_none()); - assert_ok!(TwoPhase::submit_unsigned(Origin::none(), solution)); + assert_ok!(TwoPhase::submit_unsigned(Origin::none(), solution, witness)); assert!(TwoPhase::queued_solution().is_some()); }) } @@ -692,7 +713,7 @@ mod tests { roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); - assert_eq!(TwoPhase::desired_targets(), 1); + assert_eq!(TwoPhase::snapshot().unwrap().desired_targets, 1); // an initial solution let result = ElectionResult { @@ -703,10 +724,8 @@ mod tests { distribution: vec![(10, PerU16::one())], }], }; - assert_ok!(TwoPhase::submit_unsigned( - Origin::none(), - TwoPhase::prepare_election_result(result).unwrap(), - )); + let (compact, witness) = TwoPhase::prepare_election_result(result).unwrap(); + assert_ok!(TwoPhase::submit_unsigned(Origin::none(), compact, witness)); assert_eq!(TwoPhase::queued_solution().unwrap().score[0], 10); // trial 1: a solution who's score is only 2, i.e. 20% better in the first element. @@ -724,12 +743,12 @@ mod tests { }, ], }; - let solution = TwoPhase::prepare_election_result(result).unwrap(); + let (solution, witness) = TwoPhase::prepare_election_result(result).unwrap(); // 12 is not 50% more than 10 assert_eq!(solution.score[0], 12); assert_noop!( - TwoPhase::submit_unsigned(Origin::none(), solution), + TwoPhase::submit_unsigned(Origin::none(), solution, witness), PalletError::::WeakSubmission, ); @@ -752,11 +771,11 @@ mod tests { }, ], }; - let solution = TwoPhase::prepare_election_result(result).unwrap(); + let (solution, witness) = TwoPhase::prepare_election_result(result).unwrap(); assert_eq!(solution.score[0], 17); // and it is fine - assert_ok!(TwoPhase::submit_unsigned(Origin::none(), solution)); + assert_ok!(TwoPhase::submit_unsigned(Origin::none(), solution, witness)); }) } @@ -829,7 +848,13 @@ mod tests { let encoded = pool.read().transactions[0].clone(); let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); let call = extrinsic.call; - matches!(call, OuterCall::TwoPhase(Call::submit_unsigned(_))); + matches!(call, OuterCall::TwoPhase(Call::submit_unsigned(_, _))); }) } + + #[test] + fn wrong_witness_fails() {} + + #[test] + fn invalid_round_fails() {} } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 6d451a3ff1910..f1fd02bee08d3 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -17,6 +17,7 @@ static_assertions = "1.1.0" serde = { version = "1.0.101", optional = true } codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] } sp-std = { version = "2.0.0", default-features = false, path = "../../primitives/std" } +# TODO: ideally we should be able to get rid of this by the end of this PR. sp-npos-elections = { version = "2.0.0", default-features = false, path = "../../primitives/npos-elections" } sp-io ={ version = "2.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "2.0.0", default-features = false, path = "../../primitives/runtime" } @@ -26,6 +27,7 @@ frame-system = { version = "2.0.0", default-features = false, path = "../system" pallet-session = { version = "2.0.0", default-features = false, features = ["historical"], path = "../session" } pallet-authorship = { version = "2.0.0", default-features = false, path = "../authorship" } frame-election-providers = { version = "2.0.0", default-features = false, path = "../election-providers" } +sp-election-providers = { version = "2.0.0", default-features = false, path = "../../primitives/election-providers" } sp-application-crypto = { version = "2.0.0", default-features = false, path = "../../primitives/application-crypto" } # Optional imports for benchmarking @@ -61,6 +63,7 @@ std = [ "pallet-authorship/std", "sp-application-crypto/std", "frame-election-providers/std", + "sp-election-providers/std", ] runtime-benchmarks = [ "frame-benchmarking", diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 7f7b8dec46205..85042e7d9d95c 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -282,7 +282,7 @@ pub mod default_weights; pub mod inflation; use codec::{Decode, Encode, HasCompact}; -use frame_election_providers::{ElectionDataProvider, ElectionProvider, Supports}; +use sp_election_providers::{ElectionDataProvider, ElectionProvider}; use frame_support::{ decl_error, decl_event, decl_module, decl_storage, dispatch::{DispatchResult, DispatchResultWithPostInfo}, @@ -299,7 +299,7 @@ use frame_support::{ }; use frame_system::{self as system, ensure_root, ensure_signed, offchain::SendTransactionTypes}; use pallet_session::historical; -use sp_npos_elections::{generate_solution_type, CompactSolution, ExtendedBalance, VoteWeight}; +use sp_npos_elections::{generate_solution_type, CompactSolution, ExtendedBalance, VoteWeight, Supports}; use sp_runtime::{ curve::PiecewiseLinear, traits::{ @@ -765,7 +765,7 @@ pub trait Trait: frame_system::Trait + SendTransactionTypes> { type CurrencyToVote: CurrencyToVote>; /// Something that provides the election functionality. - type ElectionProvider: frame_election_providers::ElectionProvider; + type ElectionProvider: ElectionProvider; /// Tokens have been minted and are unused for validator-reward. /// See [Era payout](./index.html#era-payout). diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index 035a704ba3009..e7b28e641a18e 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -67,7 +67,10 @@ pub trait PerThing: let b = Self::ACCURACY; // if Self::ACCURACY % 100 > 0 then we need the correction for accuracy let c = rational_mul_correction::(b, a, 100.into(), Rounding::Nearest); - Self::from_parts(a / 100.into() * b + c) + + let a: InnerOf = a / 100.into(); + // TODO: fix this, this was panicking with 100% + Self::from_parts(a.saturating_mul(b).saturating_add(c)) } /// Return the product of multiplication of this value by itself. @@ -334,7 +337,7 @@ macro_rules! implement_per_thing { &self.0 } fn decode_from(x: Self::As) -> Self { - // Saturates if `x` is more than `$max` internally. + // Saturates if `x` is more than `$max` internally. Self::from_parts(x) } } diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 717e963b07ca0..397301017212d 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -89,7 +89,6 @@ use sp_std::{ rc::Rc, }; -#[cfg(feature = "std")] use codec::{Decode, Encode}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -559,8 +558,8 @@ impl StakedAssignment { /// /// This, at the current version, resembles the `Exposure` defined in the Staking pallet, yet they /// do not necessarily have to be the same. -#[derive(Default, Debug, Encode, Decode, Clone)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Eq, PartialEq))] +#[derive(Default, Debug, Encode, Decode, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct Support { /// Total support. pub total: ExtendedBalance, From f197b6b25f9864b0afadae09264cacb79b1bd6ce Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 3 Dec 2020 10:37:28 +0000 Subject: [PATCH 17/62] Undo some formatting mistakes --- bin/node/testing/src/bench.rs | 30 +-- client/authority-discovery/src/interval.rs | 12 +- client/consensus/slots/src/lib.rs | 219 ++++++++++----------- frame/babe/src/equivocation.rs | 12 +- frame/balances/src/lib.rs | 117 +++++------ frame/balances/src/weights.rs | 19 +- frame/contracts/proc-macro/src/lib.rs | 20 +- frame/multisig/src/benchmarking.rs | 8 +- frame/support/src/metadata.rs | 2 +- 9 files changed, 203 insertions(+), 236 deletions(-) diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 6e8fc718d294e..35af52a2f36c1 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -373,15 +373,15 @@ impl BenchDb { "Created seed db at {}", dir.path().to_string_lossy(), ); - let (_client, _backend, _task_executor) = - Self::bench_client(database_type, dir.path(), Profile::Native, &keyring); + let (_client, _backend, _task_executor) = Self::bench_client( + database_type, + dir.path(), + Profile::Native, + &keyring, + ); let directory_guard = Guard(dir); - BenchDb { - keyring, - directory_guard, - database_type, - } + BenchDb { keyring, directory_guard, database_type } } /// New immutable benchmarking database. @@ -408,7 +408,7 @@ impl BenchDb { keyring: &BenchKeyring, ) -> (Client, std::sync::Arc, TaskExecutor) { let db_config = sc_client_db::DatabaseSettings { - state_cache_size: 16 * 1024 * 1024, + state_cache_size: 16*1024*1024, state_cache_child_ratio: Some((0, 100)), pruning: PruningMode::ArchiveAll, source: database_type.into_settings(dir.into()), @@ -509,13 +509,13 @@ impl BenchDb { /// Clone this database and create context for testing/benchmarking. pub fn create_context(&self, profile: Profile) -> BenchContext { - let BenchDb { - directory_guard, - keyring, + let BenchDb { directory_guard, keyring, database_type } = self.clone(); + let (client, backend, task_executor) = Self::bench_client( database_type, - } = self.clone(); - let (client, backend, task_executor) = - Self::bench_client(database_type, directory_guard.path(), profile, &keyring); + directory_guard.path(), + profile, + &keyring + ); BenchContext { client: Arc::new(client), @@ -577,7 +577,7 @@ impl BenchKeyring { xt: CheckedExtrinsic, spec_version: u32, tx_version: u32, - genesis_hash: [u8; 32], + genesis_hash: [u8; 32] ) -> UncheckedExtrinsic { match xt.signed { Some((signed, extra)) => { diff --git a/client/authority-discovery/src/interval.rs b/client/authority-discovery/src/interval.rs index 53198db2898c6..b3aa5b1c0f678 100644 --- a/client/authority-discovery/src/interval.rs +++ b/client/authority-discovery/src/interval.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use futures::{future::FutureExt, ready, stream::Stream}; +use futures::stream::Stream; +use futures::future::FutureExt; +use futures::ready; use futures_timer::Delay; -use std::{ - pin::Pin, - task::{Context, Poll}, - time::Duration, -}; +use std::pin::Pin; +use std::task::{Context, Poll}; +use std::time::Duration; /// Exponentially increasing interval /// diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 1c58624829f89..571766bc44b1a 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -23,39 +23,28 @@ #![forbid(unsafe_code)] #![deny(missing_docs)] -mod aux_schema; mod slots; +mod aux_schema; -pub use aux_schema::{check_equivocation, MAX_SLOT_CAPACITY, PRUNING_BOUND}; pub use slots::SlotInfo; use slots::Slots; +pub use aux_schema::{check_equivocation, MAX_SLOT_CAPACITY, PRUNING_BOUND}; +use std::{fmt::Debug, ops::Deref, pin::Pin, sync::Arc, time::{Instant, Duration}}; use codec::{Decode, Encode}; -use futures::{ - future::{self, Either}, - prelude::*, -}; +use futures::{prelude::*, future::{self, Either}}; use futures_timer::Delay; use log::{debug, error, info, warn}; use parking_lot::Mutex; -use sc_telemetry::{telemetry, CONSENSUS_DEBUG, CONSENSUS_INFO, CONSENSUS_WARN}; -use sp_api::{ApiRef, ProvideRuntimeApi}; +use sp_api::{ProvideRuntimeApi, ApiRef}; use sp_arithmetic::traits::BaseArithmetic; -use sp_consensus::{ - BlockImport, CanAuthorWith, Proposer, RecordProof, SelectChain, SlotData, SyncOracle, -}; +use sp_consensus::{BlockImport, Proposer, SyncOracle, SelectChain, CanAuthorWith, SlotData, RecordProof}; use sp_inherents::{InherentData, InherentDataProviders}; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, HashFor, Header, NumberFor}, -}; -use std::{ - fmt::Debug, - ops::Deref, - pin::Pin, - sync::Arc, - time::{Duration, Instant}, + traits::{Block as BlockT, Header, HashFor, NumberFor} }; +use sc_telemetry::{telemetry, CONSENSUS_DEBUG, CONSENSUS_WARN, CONSENSUS_INFO}; /// The changes that need to applied to the storage to create the state for a block. /// @@ -141,7 +130,12 @@ pub trait SimpleSlotWorker { /// Notifies the given slot. Similar to `claim_slot`, but will be called no matter whether we /// need to author blocks or not. - fn notify_slot(&self, _header: &B::Header, _slot_number: u64, _epoch_data: &Self::EpochData) {} + fn notify_slot( + &self, + _header: &B::Header, + _slot_number: u64, + _epoch_data: &Self::EpochData, + ) {} /// Return the pre digest data to include in a block authored with the given claim. fn pre_digest_data( @@ -215,8 +209,7 @@ pub trait SimpleSlotWorker { let (timestamp, slot_number) = (slot_info.timestamp, slot_info.number); let slot_remaining_duration = self.slot_remaining_duration(&slot_info); - let proposing_remaining_duration = - self.proposing_remaining_duration(&chain_head, &slot_info); + let proposing_remaining_duration = self.proposing_remaining_duration(&chain_head, &slot_info); let proposing_remaining = match proposing_remaining_duration { Some(r) if r.as_secs() == 0 && r.as_nanos() == 0 => { @@ -227,7 +220,7 @@ pub trait SimpleSlotWorker { ); return Box::pin(future::ready(None)); - } + }, Some(r) => Box::new(Delay::new(r)) as Box + Unpin + Send>, None => Box::new(future::pending()) as Box<_>, }; @@ -299,51 +292,43 @@ pub trait SimpleSlotWorker { let logs = self.pre_digest_data(slot_number, &claim); // deadline our production to approx. the end of the slot - let proposing = awaiting_proposer.and_then(move |proposer| { - proposer.propose( + let proposing = awaiting_proposer.and_then(move |proposer| proposer.propose( slot_info.inherent_data, sp_runtime::generic::Digest { logs, }, slot_remaining_duration, RecordProof::No, - ).map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e))) - }); + ).map_err(|e| sp_consensus::Error::ClientImport(format!("{:?}", e)))); let proposal_work = futures::future::select(proposing, proposing_remaining).map(move |v| match v { Either::Left((b, _)) => b.map(|b| (b, claim)), Either::Right(_) => { - info!( - "⌛️ Discarding proposal for slot {}; block production took too long", - slot_number - ); + info!("⌛️ Discarding proposal for slot {}; block production took too long", slot_number); // If the node was compiled with debug, tell the user to use release optimizations. - #[cfg(build_type = "debug")] + #[cfg(build_type="debug")] info!("👉 Recompile your node in `--release` mode to mitigate this problem."); telemetry!(CONSENSUS_INFO; "slots.discarding_proposal_took_too_long"; "slot" => slot_number, ); - Err(sp_consensus::Error::ClientImport( - "Timeout in the Slots proposer".into(), - )) - } + Err(sp_consensus::Error::ClientImport("Timeout in the Slots proposer".into())) + }, }); let block_import_params_maker = self.block_import_params(); let block_import = self.block_import(); let logging_target = self.logging_target(); - proposal_work - .and_then(move |(proposal, claim)| async move { - let (block, storage_proof) = (proposal.block, proposal.proof); - let (header, body) = block.clone().deconstruct(); - let header_num = *header.number(); - let header_hash = header.hash(); - let parent_hash = *header.parent_hash(); + proposal_work.and_then(move |(proposal, claim)| async move { + let (block, storage_proof) = (proposal.block, proposal.proof); + let (header, body) = block.clone().deconstruct(); + let header_num = *header.number(); + let header_hash = header.hash(); + let parent_hash = *header.parent_hash(); - let block_import_params = block_import_params_maker( + let block_import_params = block_import_params_maker( header, &header_hash, body, @@ -352,7 +337,7 @@ pub trait SimpleSlotWorker { epoch_data, )?; - info!( + info!( "🔖 Pre-sealed block for proposal at {}. Hash now {:?}, previously {:?}.", header_num, block_import_params.post_hash(), @@ -365,32 +350,25 @@ pub trait SimpleSlotWorker { "hash_previously" => ?header_hash, ); - if let Err(err) = block_import - .lock() - .import_block(block_import_params, Default::default()) - { - warn!( - target: logging_target, - "Error with block built on {:?}: {:?}", parent_hash, err, - ); + if let Err(err) = block_import.lock().import_block(block_import_params, Default::default()) { + warn!( + target: logging_target, + "Error with block built on {:?}: {:?}", + parent_hash, + err, + ); - telemetry!( - CONSENSUS_WARN; "slots.err_with_block_built_on"; - "hash" => ?parent_hash, - "err" => ?err, - ); - } + telemetry!( + CONSENSUS_WARN; "slots.err_with_block_built_on"; + "hash" => ?parent_hash, + "err" => ?err, + ); + } - Ok(SlotResult { - block, - storage_proof, - }) - }) - .then(|r| async move { - r.map_err(|e| warn!(target: "slots", "Encountered consensus error: {:?}", e)) - .ok() - }) - .boxed() + Ok(SlotResult { block, storage_proof }) + }).then(|r| async move { + r.map_err(|e| warn!(target: "slots", "Encountered consensus error: {:?}", e)).ok() + }).boxed() } } @@ -493,12 +471,11 @@ pub enum CheckedHeader { Checked(H, S), } + + #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] -pub enum Error -where - T: Debug, -{ +pub enum Error where T: Debug { #[error("Slot duration is invalid: {0:?}")] SlotDurationInvalid(SlotDuration), } @@ -519,8 +496,7 @@ impl Deref for SlotDuration { impl SlotData for SlotDuration { /// Get the slot duration in milliseconds. fn slot_duration(&self) -> u64 - where - T: SlotData, + where T: SlotData, { self.0.slot_duration() } @@ -534,8 +510,7 @@ impl SlotDuration { /// /// `slot_key` is marked as `'static`, as it should really be a /// compile-time constant. - pub fn get_or_compute(client: &C, cb: CB) -> sp_blockchain::Result - where + pub fn get_or_compute(client: &C, cb: CB) -> sp_blockchain::Result where C: sc_client_api::backend::AuxStore, C: ProvideRuntimeApi, CB: FnOnce(ApiRef, &BlockId) -> sp_blockchain::Result, @@ -568,9 +543,7 @@ impl SlotDuration { }?; if slot_duration.slot_duration() == 0u64 { - return Err(sp_blockchain::Error::Application(Box::new( - Error::SlotDurationInvalid(slot_duration), - ))); + return Err(sp_blockchain::Error::Application(Box::new(Error::SlotDurationInvalid(slot_duration)))) } Ok(slot_duration) @@ -683,7 +656,7 @@ impl Default for BackoffAuthoringOnFinalizedHeadLagging { impl BackoffAuthoringBlocksStrategy for BackoffAuthoringOnFinalizedHeadLagging where - N: BaseArithmetic + Copy, + N: BaseArithmetic + Copy { fn should_backoff( &self, @@ -699,8 +672,8 @@ where } let unfinalized_block_length = chain_head_number - finalized_number; - let interval = - unfinalized_block_length.saturating_sub(self.unfinalized_slack) / self.authoring_bias; + let interval = unfinalized_block_length.saturating_sub(self.unfinalized_slack) + / self.authoring_bias; let interval = interval.min(self.max_interval); // We're doing arithmetic between block and slot numbers. @@ -735,10 +708,10 @@ impl BackoffAuthoringBlocksStrategy for () { #[cfg(test)] mod test { - use crate::{BackoffAuthoringBlocksStrategy, BackoffAuthoringOnFinalizedHeadLagging}; - use sp_api::NumberFor; use std::time::{Duration, Instant}; + use crate::{BackoffAuthoringOnFinalizedHeadLagging, BackoffAuthoringBlocksStrategy}; use substrate_test_runtime_client::runtime::Block; + use sp_api::NumberFor; const SLOT_DURATION: Duration = Duration::from_millis(6000); @@ -856,8 +829,13 @@ mod test { let should_backoff: Vec = (slot_now..300) .map(move |s| { - let b = - strategy.should_backoff(head_number, head_slot, finalized_number, s, "slots"); + let b = strategy.should_backoff( + head_number, + head_slot, + finalized_number, + s, + "slots", + ); // Chain is still advancing (by someone else) head_number += 1; head_slot = s; @@ -897,9 +875,7 @@ mod test { // Should backoff (true) until we are `max_interval` number of slots ahead of the chain // head slot, then we never backoff (false). - let expected: Vec = (slot_now..200) - .map(|s| s <= max_interval + head_slot) - .collect(); + let expected: Vec = (slot_now..200).map(|s| s <= max_interval + head_slot).collect(); assert_eq!(should_backoff, expected); } @@ -944,27 +920,32 @@ mod test { // Gradually start to backoff more and more frequently let expected = [ false, false, false, false, false, // no effect - true, false, true, false, // 1:1 - true, true, false, true, true, false, // 2:1 - true, true, true, false, true, true, true, false, // 3:1 - true, true, true, true, false, true, true, true, true, false, // 4:1 - true, true, true, true, true, false, true, true, true, true, true, false, // 5:1 - true, true, true, true, true, true, false, true, true, true, true, true, true, - false, // 6:1 - true, true, true, true, true, true, true, false, true, true, true, true, true, true, - true, false, // 7:1 - true, true, true, true, true, true, true, true, false, true, true, true, true, true, - true, true, true, false, // 8:1 - true, true, true, true, true, true, true, true, true, false, true, true, true, true, - true, true, true, true, true, false, // 9:1 - true, true, true, true, true, true, true, true, true, true, false, true, true, true, - true, true, true, true, true, true, true, false, // 10:1 - true, true, true, true, true, true, true, true, true, true, true, false, true, true, - true, true, true, true, true, true, true, true, true, false, // 11:1 - true, true, true, true, true, true, true, true, true, true, true, true, false, true, - true, true, true, true, true, true, true, true, true, true, true, false, // 12:1 + true, false, + true, false, // 1:1 + true, true, false, + true, true, false, // 2:1 + true, true, true, false, + true, true, true, false, // 3:1 + true, true, true, true, false, + true, true, true, true, false, // 4:1 + true, true, true, true, true, false, + true, true, true, true, true, false, // 5:1 + true, true, true, true, true, true, false, + true, true, true, true, true, true, false, // 6:1 + true, true, true, true, true, true, true, false, + true, true, true, true, true, true, true, false, // 7:1 + true, true, true, true, true, true, true, true, false, + true, true, true, true, true, true, true, true, false, // 8:1 + true, true, true, true, true, true, true, true, true, false, + true, true, true, true, true, true, true, true, true, false, // 9:1 + true, true, true, true, true, true, true, true, true, true, false, + true, true, true, true, true, true, true, true, true, true, false, // 10:1 + true, true, true, true, true, true, true, true, true, true, true, false, + true, true, true, true, true, true, true, true, true, true, true, false, // 11:1 + true, true, true, true, true, true, true, true, true, true, true, true, false, + true, true, true, true, true, true, true, true, true, true, true, true, false, // 12:1 true, true, true, true, - ]; + ]; assert_eq!(backoff.as_slice(), &expected[..]); } @@ -1022,12 +1003,12 @@ mod test { // number of slots_claimed. let expected_distance = param.max_interval as usize + 1; assert_eq!(last_slot - last_two_claimed.next().unwrap(), 92); - assert_eq!( - last_slot - last_two_claimed.next().unwrap(), - 92 + expected_distance - ); + assert_eq!(last_slot - last_two_claimed.next().unwrap(), 92 + expected_distance); - let intervals: Vec<_> = slots_claimed.windows(2).map(|x| x[1] - x[0]).collect(); + let intervals: Vec<_> = slots_claimed + .windows(2) + .map(|x| x[1] - x[0]) + .collect(); // The key thing is that the distance between claimed slots is capped to `max_interval + 1` // assert_eq!(max_observed_interval, Some(&expected_distance)); @@ -1035,7 +1016,7 @@ mod test { // But lets assert all distances, which we expect to grow linearly until `max_interval + 1` let expected_intervals: Vec<_> = (0..497) - .map(|i| (i / 2).max(1).min(expected_distance)) + .map(|i| (i/2).max(1).min(expected_distance) ) .collect(); assert_eq!(intervals, expected_intervals); @@ -1061,8 +1042,8 @@ mod test { }; // Number of blocks until we reach the max interval - let block_for_max_interval = - param.max_interval * param.authoring_bias + param.unfinalized_slack; + let block_for_max_interval + = param.max_interval * param.authoring_bias + param.unfinalized_slack; while head_state.head_number < block_for_max_interval { if should_backoff(&head_state) { @@ -1086,7 +1067,7 @@ mod test { // or // (start_slot + C) + M * X*(X+1)/2 fn expected_time_to_reach_max_interval( - param: &BackoffAuthoringOnFinalizedHeadLagging, + param: &BackoffAuthoringOnFinalizedHeadLagging ) -> (u64, u64) { let c = param.unfinalized_slack; let m = param.authoring_bias; diff --git a/frame/babe/src/equivocation.rs b/frame/babe/src/equivocation.rs index 6280a5b4ef314..55aaedfe082fe 100644 --- a/frame/babe/src/equivocation.rs +++ b/frame/babe/src/equivocation.rs @@ -37,20 +37,18 @@ use frame_support::{debug, traits::KeyOwnerProofSystem}; use sp_consensus_babe::{EquivocationProof, SlotNumber}; -use sp_runtime::{ - transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, - TransactionValidityError, ValidTransaction, - }, - DispatchResult, Perbill, +use sp_runtime::transaction_validity::{ + InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, + TransactionValidityError, ValidTransaction, }; +use sp_runtime::{DispatchResult, Perbill}; use sp_staking::{ offence::{Kind, Offence, OffenceError, ReportOffence}, SessionIndex, }; use sp_std::prelude::*; -use crate::{Call, Config, Module}; +use crate::{Call, Module, Config}; /// A trait with utility methods for handling equivocation reports in BABE. /// The trait provides methods for reporting an offence triggered by a valid diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index c8f72b317c102..1f119dad76f33 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -151,44 +151,38 @@ #[macro_use] mod tests; -mod benchmarking; -mod tests_composite; mod tests_local; +mod tests_composite; +mod benchmarking; pub mod weights; -pub use self::imbalances::{NegativeImbalance, PositiveImbalance}; -use codec::{Codec, Decode, Encode}; +use sp_std::prelude::*; +use sp_std::{cmp, result, mem, fmt::Debug, ops::BitOr, convert::Infallible}; +use codec::{Codec, Encode, Decode}; use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, ensure, + StorageValue, Parameter, decl_event, decl_storage, decl_module, decl_error, ensure, traits::{ - BalanceStatus as Status, Currency, ExistenceRequirement, - ExistenceRequirement::{AllowDeath, KeepAlive}, - Get, Imbalance, IsDeadAccount, LockIdentifier, LockableCurrency, OnKilledAccount, - OnUnbalanced, ReservableCurrency, SignedImbalance, StoredMap, TryDrop, WithdrawReasons, - }, - Parameter, StorageValue, + Currency, OnKilledAccount, OnUnbalanced, TryDrop, StoredMap, + WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, + Imbalance, SignedImbalance, ReservableCurrency, Get, ExistenceRequirement::KeepAlive, + ExistenceRequirement::AllowDeath, IsDeadAccount, BalanceStatus as Status, + } }; -use frame_system::{self as system, ensure_root, ensure_signed}; use sp_runtime::{ + RuntimeDebug, DispatchResult, DispatchError, traits::{ - AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedSub, MaybeSerializeDeserialize, Member, - Saturating, StaticLookup, Zero, + Zero, AtLeast32BitUnsigned, StaticLookup, Member, CheckedAdd, CheckedSub, + MaybeSerializeDeserialize, Saturating, Bounded, }, - DispatchError, DispatchResult, RuntimeDebug, }; -use sp_std::{cmp, convert::Infallible, fmt::Debug, mem, ops::BitOr, prelude::*, result}; +use frame_system::{self as system, ensure_signed, ensure_root}; +pub use self::imbalances::{PositiveImbalance, NegativeImbalance}; pub use weights::WeightInfo; pub trait Subtrait: frame_system::Config { /// The balance of an account. - type Balance: Parameter - + Member - + AtLeast32BitUnsigned - + Codec - + Default - + Copy - + MaybeSerializeDeserialize - + Debug; + type Balance: Parameter + Member + AtLeast32BitUnsigned + Codec + Default + Copy + + MaybeSerializeDeserialize + Debug; /// The minimum amount required to keep an account open. type ExistentialDeposit: Get; @@ -206,14 +200,8 @@ pub trait Subtrait: frame_system::Config { pub trait Config: frame_system::Config { /// The balance of an account. - type Balance: Parameter - + Member - + AtLeast32BitUnsigned - + Codec - + Default - + Copy - + MaybeSerializeDeserialize - + Debug; + type Balance: Parameter + Member + AtLeast32BitUnsigned + Codec + Default + Copy + + MaybeSerializeDeserialize + Debug; /// Handler for the unbalanced reduction when removing a dust account. type DustRemoval: OnUnbalanced>; @@ -716,15 +704,15 @@ impl, I: Instance> Module { // of the inner member. mod imbalances { use super::{ - result, Config, DefaultInstance, Imbalance, Instance, Saturating, StorageValue, TryDrop, - Zero, + result, DefaultInstance, Imbalance, Config, Zero, Instance, Saturating, + StorageValue, TryDrop, }; use sp_std::mem; /// Opaque, move-only struct with private fields that serves as a token denoting that /// funds have been created without any equal and opposite accounting. #[must_use] - pub struct PositiveImbalance, I: Instance = DefaultInstance>(T::Balance); + pub struct PositiveImbalance, I: Instance=DefaultInstance>(T::Balance); impl, I: Instance> PositiveImbalance { /// Create a new positive imbalance from a balance. @@ -736,7 +724,7 @@ mod imbalances { /// Opaque, move-only struct with private fields that serves as a token denoting that /// funds have been destroyed without any equal and opposite accounting. #[must_use] - pub struct NegativeImbalance, I: Instance = DefaultInstance>(T::Balance); + pub struct NegativeImbalance, I: Instance=DefaultInstance>(T::Balance); impl, I: Instance> NegativeImbalance { /// Create a new negative imbalance from a balance. @@ -850,21 +838,24 @@ mod imbalances { impl, I: Instance> Drop for PositiveImbalance { /// Basic drop handler will just square up the total issuance. fn drop(&mut self) { - >::mutate(|v| *v = v.saturating_add(self.0)); + >::mutate( + |v| *v = v.saturating_add(self.0) + ); } } impl, I: Instance> Drop for NegativeImbalance { /// Basic drop handler will just square up the total issuance. fn drop(&mut self) { - >::mutate(|v| *v = v.saturating_sub(self.0)); + >::mutate( + |v| *v = v.saturating_sub(self.0) + ); } } } -impl, I: Instance> Currency for Module -where - T::Balance: MaybeSerializeDeserialize + Debug, +impl, I: Instance> Currency for Module where + T::Balance: MaybeSerializeDeserialize + Debug { type Balance = T::Balance; type PositiveImbalance = PositiveImbalance; @@ -1112,9 +1103,8 @@ where } } -impl, I: Instance> ReservableCurrency for Module -where - T::Balance: MaybeSerializeDeserialize + Debug, +impl, I: Instance> ReservableCurrency for Module where + T::Balance: MaybeSerializeDeserialize + Debug { /// Check if `who` can reserve `value` from their free balance. /// @@ -1243,7 +1233,7 @@ impl, I: Instance> OnKilledAccount for Module { impl, I: Instance> LockableCurrency for Module where - T::Balance: MaybeSerializeDeserialize + Debug, + T::Balance: MaybeSerializeDeserialize + Debug { type Moment = T::BlockNumber; @@ -1257,16 +1247,9 @@ where amount: T::Balance, reasons: WithdrawReasons, ) { - if amount.is_zero() || reasons.is_empty() { - return; - } - let mut new_lock = Some(BalanceLock { - id, - amount, - reasons: reasons.into(), - }); - let mut locks = Self::locks(who) - .into_iter() + if amount.is_zero() || reasons.is_empty() { return } + let mut new_lock = Some(BalanceLock { id, amount, reasons: reasons.into() }); + let mut locks = Self::locks(who).into_iter() .filter_map(|l| if l.id == id { new_lock.take() } else { Some(l) }) .collect::>(); if let Some(lock) = new_lock { @@ -1283,18 +1266,10 @@ where amount: T::Balance, reasons: WithdrawReasons, ) { - if amount.is_zero() || reasons.is_empty() { - return; - } - let mut new_lock = Some(BalanceLock { - id, - amount, - reasons: reasons.into(), - }); - let mut locks = Self::locks(who) - .into_iter() - .filter_map(|l| { - if l.id == id { + if amount.is_zero() || reasons.is_empty() { return } + let mut new_lock = Some(BalanceLock { id, amount, reasons: reasons.into() }); + let mut locks = Self::locks(who).into_iter().filter_map(|l| + if l.id == id { new_lock.take().map(|nl| { BalanceLock { id: l.id, @@ -1304,8 +1279,7 @@ where }) } else { Some(l) - }) - .collect::>(); + }).collect::>(); if let Some(lock) = new_lock { locks.push(lock) } @@ -1322,9 +1296,8 @@ where } } -impl, I: Instance> IsDeadAccount for Module -where - T::Balance: MaybeSerializeDeserialize + Debug, +impl, I: Instance> IsDeadAccount for Module where + T::Balance: MaybeSerializeDeserialize + Debug { fn is_dead_account(who: &T::AccountId) -> bool { // this should always be exactly equivalent to `Self::account(who).total().is_zero()` if ExistentialDeposit > 0 diff --git a/frame/balances/src/weights.rs b/frame/balances/src/weights.rs index aa9cf12b8e6eb..cdcd3e6b69c66 100644 --- a/frame/balances/src/weights.rs +++ b/frame/balances/src/weights.rs @@ -34,13 +34,11 @@ // --output=./frame/balances/src/weights.rs // --template=./.maintain/frame-weight-template.hbs + #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_balances. @@ -50,6 +48,7 @@ pub trait WeightInfo { fn set_balance_creating() -> Weight; fn set_balance_killing() -> Weight; fn force_transfer() -> Weight; + } /// Weights for pallet_balances using the Substrate node and recommended hardware. @@ -59,27 +58,33 @@ impl WeightInfo for SubstrateWeight { (94_088_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } fn transfer_keep_alive() -> Weight { (64_828_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } fn set_balance_creating() -> Weight { (36_151_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } fn set_balance_killing() -> Weight { (45_505_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } fn force_transfer() -> Weight { (92_986_000 as Weight) .saturating_add(T::DbWeight::get().reads(2 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + } // For backwards compatibility and tests @@ -88,25 +93,31 @@ impl WeightInfo for () { (94_088_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } fn transfer_keep_alive() -> Weight { (64_828_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } fn set_balance_creating() -> Weight { (36_151_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } fn set_balance_killing() -> Weight { (45_505_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } fn force_transfer() -> Weight { (92_986_000 as Weight) .saturating_add(RocksDbWeight::get().reads(2 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + } diff --git a/frame/contracts/proc-macro/src/lib.rs b/frame/contracts/proc-macro/src/lib.rs index 0f64ba07493b9..4e38508297d26 100644 --- a/frame/contracts/proc-macro/src/lib.rs +++ b/frame/contracts/proc-macro/src/lib.rs @@ -21,10 +21,11 @@ extern crate alloc; -use alloc::string::ToString; use proc_macro2::TokenStream; use quote::{quote, quote_spanned}; -use syn::{parse_macro_input, spanned::Spanned, Data, DataStruct, DeriveInput, Fields, Ident}; +use syn::spanned::Spanned; +use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields, Ident}; +use alloc::string::ToString; /// This derives `Debug` for a struct where each field must be of some numeric type. /// It interprets each field as its represents some weight and formats it as times so that @@ -43,7 +44,7 @@ pub fn derive_schedule_debug(input: proc_macro::TokenStream) -> proc_macro::Toke fn derive_debug( input: proc_macro::TokenStream, - fmt: impl Fn(&Ident) -> TokenStream, + fmt: impl Fn(&Ident) -> TokenStream ) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = &input.ident; @@ -54,8 +55,7 @@ fn derive_debug( return quote_spanned! { name.span() => compile_error!("WeightDebug is only supported for structs."); - } - .into(); + }.into(); }; #[cfg(feature = "full")] @@ -87,22 +87,24 @@ fn derive_debug( fn iterate_fields(data: &DataStruct, fmt: impl Fn(&Ident) -> TokenStream) -> TokenStream { match &data.fields { Fields::Named(fields) => { - let recurse = fields.named.iter().filter_map(|f| { + let recurse = fields.named + .iter() + .filter_map(|f| { let name = f.ident.as_ref()?; if name.to_string().starts_with('_') { return None; } let value = fmt(name); - let ret = quote_spanned! { f.span() => + let ret = quote_spanned!{ f.span() => formatter.field(stringify!(#name), #value); }; Some(ret) }); - quote! { + quote!{ #( #recurse )* } } - Fields::Unnamed(fields) => quote_spanned! { + Fields::Unnamed(fields) => quote_spanned!{ fields.span() => compile_error!("Unnamed fields are not supported") }, diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index d63da57575e97..0b549b3d94717 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -29,9 +29,11 @@ use crate::Module as Multisig; const SEED: u32 = 0; -fn setup_multi(s: u32, z: u32) -> Result<(Vec, Vec), &'static str> { +fn setup_multi(s: u32, z: u32) + -> Result<(Vec, Vec), &'static str> +{ let mut signatories: Vec = Vec::new(); - for i in 0..s { + for i in 0 .. s { let signatory = account("signatory", i, SEED); // Give them some balance for a possible deposit let balance = BalanceOf::::max_value(); @@ -42,7 +44,7 @@ fn setup_multi(s: u32, z: u32) -> Result<(Vec, Vec) // Must first convert to outer call type. let call: ::Call = frame_system::Call::::remark(vec![0; z as usize]).into(); let call_data = call.encode(); - return Ok((signatories, call_data)); + return Ok((signatories, call_data)) } benchmarks! { diff --git a/frame/support/src/metadata.rs b/frame/support/src/metadata.rs index a720603288777..f72365985da0a 100644 --- a/frame/support/src/metadata.rs +++ b/frame/support/src/metadata.rs @@ -345,8 +345,8 @@ mod tests { } mod event_module { - use super::system; use crate::dispatch::DispatchResult; + use super::system; pub trait Config: system::Config { type Balance; From 50052817f8e8d16db39615ead9fdfcd178529054 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Mon, 7 Dec 2020 13:06:24 +0000 Subject: [PATCH 18/62] Working on benchmarks' --- frame/election-providers/expanded.rs | 3047 +++++++++-------- .../src/two_phase/benchmarking.rs | 228 +- .../election-providers/src/two_phase/mock.rs | 12 +- frame/election-providers/src/two_phase/mod.rs | 135 +- .../src/two_phase/signed.rs | 8 +- .../src/two_phase/unsigned.rs | 50 +- primitives/arithmetic/src/per_things.rs | 9 +- primitives/npos-elections/compact/src/lib.rs | 2 +- primitives/npos-elections/src/lib.rs | 14 +- 9 files changed, 1777 insertions(+), 1728 deletions(-) diff --git a/frame/election-providers/expanded.rs b/frame/election-providers/expanded.rs index 72e6a1e968a54..d66dc691d10bf 100644 --- a/frame/election-providers/expanded.rs +++ b/frame/election-providers/expanded.rs @@ -124,7 +124,7 @@ pub mod onchain { pub mod two_phase { //! # Two phase election provider pallet. //! - //! As the name suggests, this election provider has two distinct phases (see [`Phase`]), signed and + //! As the name suggests, this election-provider has two distinct phases (see [`Phase`]), signed and //! unsigned. //! //! ## Phases @@ -147,14 +147,14 @@ pub mod two_phase { //! //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution - //! on-chain for a number of blocks. A maximum of [`Trait::MaxSignedSubmissions`] solutions are - //! stored. The queue is always sorted based on score (worse -> best). + //! on-chain for a number of blocks. A maximum of [`Config::MaxSignedSubmissions`] solutions are + //! stored. The queue is always sorted based on score (worse to best). //! //! Upon arrival of a new solution: //! - //! 1. If the queue is not full, it is stored. + //! 1. If the queue is not full, it is stored in the appropriate index. //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the - //! worse solution is discarded (TODO: what to do with the bond?) and the new solution is stored + //! worse solution is discarded (TODO: must return the bond here) and the new solution is stored //! in the correct index. //! 3. If the queue is full and the solution is not an improvement compared to any of the queued //! ones, it is instantly rejected and no additional bond is reserved. @@ -165,7 +165,7 @@ pub mod two_phase { //! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed //! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure //! the score claimed by this score was correct, among other checks. At each step, if the current - //! best solution is passes the feasibility check, it is considered to be the best one. The sender + //! best solution passes the feasibility check, it is considered to be the best one. The sender //! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without //! being checked. //! @@ -243,37 +243,39 @@ pub mod two_phase { use sp_arithmetic::traits::SaturatedConversion; use sp_npos_elections::is_score_better; use sp_runtime::Perbill; - impl Module + impl Module where ExtendedBalance: From>>, { /// Start the signed phase. - /// - /// Upon calling this, auxillary data for election is stored and signed solutions will be - /// accepted. - /// - /// The signed phase must always start before the unsigned phase. - pub fn start_signed_phase() { - let targets = T::ElectionDataProvider::targets(); - let voters = T::ElectionDataProvider::voters(); - let desired_targets = T::ElectionDataProvider::desired_targets(); - >::put(targets); - >::put(voters); - DesiredTargets::put(desired_targets); - } - /// Finish the singed phase. Process the signed submissions from best to worse until a valid one + /// + /// Upon calling this, auxillary data for election is stored and signed solutions will be + /// accepted. + /// + /// The signed phase must always start before the unsigned phase. + pub fn start_signed_phase() { + let targets = T::ElectionDataProvider::targets(); + let voters = T::ElectionDataProvider::voters(); + let desired_targets = T::ElectionDataProvider::desired_targets(); + >::put(RoundSnapshot { + voters, + targets, + desired_targets, + }); + } + /// Finish the singed phase. Process the signed submissions from best to worse until a valid one /// is found, rewarding the best oen and slashing the invalid ones along the way. /// /// Returns true if we have a good solution in the signed phase. /// /// This drains the [`SignedSubmissions`], potentially storing the best valid one in /// [`QueuedSolution`]. - pub fn finalize_signed_phase() -> bool { - let mut all_submission: Vec> = - >::take(); - let mut found_solution = false; - while let Some(best) = all_submission.pop() { - let SignedSubmission { + pub fn finalize_signed_phase() -> bool { + let mut all_submission: Vec> = + >::take(); + let mut found_solution = false; + while let Some(best) = all_submission.pop() { + let SignedSubmission { solution, who, deposit, @@ -428,7 +430,7 @@ pub mod two_phase { pub(crate) const OFFCHAIN_REPEAT: u32 = 5; /// Default number of blocks for which the unsigned transaction should stay in the pool pub(crate) const DEFAULT_LONGEVITY: u64 = 25; - impl Module + impl Module where ExtendedBalance: From>>, { @@ -438,13 +440,13 @@ pub mod two_phase { let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; seq_phragmen::<_, CompactAccuracyOf>( - desired_targets, - targets, - voters, - Some((iters, 0)), - ) - .map_err(Into::into) - .and_then(Self::prepare_election_result) + desired_targets, + targets, + voters, + Some((iters, 0)), + ) + .map_err(Into::into) + .and_then(Self::prepare_election_result) } /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which /// is ready to be submitted to the chain. @@ -457,18 +459,18 @@ pub mod two_phase { let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; let voter_index = |who: &T::AccountId| -> Option> { - voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < T > > > :: try_into ( i ) . ok ( ) ) - }; - let target_index = - |who: &T::AccountId| -> Option> { - targets . iter ( ) . position ( | x | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactTargetIndexOf < T > > > :: try_into ( i ) . ok ( ) ) - }; - let voter_at = - |i: crate::two_phase::CompactVoterIndexOf| -> Option { - < crate :: two_phase :: CompactVoterIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | voters . get ( i ) . map ( | ( x , _ , _ ) | x ) . cloned ( ) ) - }; - let target_at = - |i: crate::two_phase::CompactTargetIndexOf| -> Option { + voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < T > > > :: try_into ( i ) . ok ( ) ) + }; + let target_index = + |who: &T::AccountId| -> Option> { + targets . iter ( ) . position ( | x | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactTargetIndexOf < T > > > :: try_into ( i ) . ok ( ) ) + }; + let voter_at = + |i: crate::two_phase::CompactVoterIndexOf| -> Option { + < crate :: two_phase :: CompactVoterIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | voters . get ( i ) . map ( | ( x , _ , _ ) | x ) . cloned ( ) ) + }; + let target_at = + |i: crate::two_phase::CompactTargetIndexOf| -> Option { < crate :: two_phase :: CompactTargetIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | targets . get ( i ) . cloned ( ) ) }; let stake_of = |who: &T::AccountId| -> crate::VoteWeight { @@ -487,16 +489,16 @@ pub mod two_phase { &stake_of, ) .map_err::(Into::into)?; - sp_npos_elections::reduce(&mut staked); - let ratio = sp_npos_elections::assignment_staked_to_ratio_normalized(staked)?; - let compact = >::from_assignment(ratio, &voter_index, &target_index)?; - let maximum_allowed_voters = - Self::maximum_compact_len::(0, Default::default(), 0); - let compact = Self::trim_compact(compact.len() as u32, compact, &voter_index)?; - let winners = sp_npos_elections::to_without_backing(winners); + sp_npos_elections::reduce(&mut staked); + let ratio = sp_npos_elections::assignment_staked_to_ratio_normalized(staked)?; + let compact = >::from_assignment(ratio, &voter_index, &target_index)?; + let maximum_allowed_voters = + Self::maximum_compact_len::(0, Default::default(), 0); + let compact = Self::trim_compact(compact.len() as u32, compact, &voter_index)?; + let winners = sp_npos_elections::to_without_backing(winners); let score = compact - .clone() - .score(&winners, stake_of, voter_at, target_at)?; + .clone() + .score(&winners, stake_of, voter_at, target_at)?; Ok(RawSolution { compact, score }) } /// Get a random number of iterations to run the balancing in the OCW. @@ -551,11 +553,11 @@ pub mod two_phase { .iter() .map(|(who, stake)| (nominator_index(&who), stake)) { - let index = maybe_index.ok_or(Error::SnapshotUnAvailable)?; - if compact.remove_voter(index) { - removed += 1 - } - if removed >= to_remove { + let index = maybe_index.ok_or(Error::SnapshotUnAvailable)?; + if compact.remove_voter(index) { + removed += 1 + } + if removed >= to_remove { break; } } @@ -648,15 +650,13 @@ pub mod two_phase { let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); let mutate_stat = storage.mutate::<_, &'static str, _>( - |maybe_head: Option>| { - match maybe_head { - Some(Some(head)) if now < head => Err("fork."), - Some(Some(head)) if now >= head && now <= head + threshold => { - Err("recently executed.") - } - Some(Some(head)) if now > head + threshold => Ok(now), - _ => Ok(now), - } + |maybe_head: Option>| match maybe_head { + Some(Some(head)) if now < head => Err("fork."), + Some(Some(head)) if now >= head && now <= head + threshold => { + Err("recently executed.") + } + Some(Some(head)) if now > head + threshold => Ok(now), + _ => Ok(now), }, ); match mutate_stat { @@ -668,13 +668,12 @@ pub mod two_phase { /// Mine a new solution, and submit it back to the chian as an unsigned transaction. pub(crate) fn mine_and_submit() -> Result<(), Error> { let balancing = Self::get_balancing_iters(); - Self::mine_solution(balancing).and_then(|raw_solution| { - let call = Call::submit_unsigned(raw_solution).into(); - SubmitTransaction::>::submit_unsigned_transaction(call) - .map_err(|_| Error::PoolSubmissionFailed) - }) + let raw_solution = Self::mine_solution(balancing)?; + let call = Call::submit_unsigned(raw_solution).into(); + SubmitTransaction::>::submit_unsigned_transaction(call) + .map_err(|_| Error::PoolSubmissionFailed) } - pub(crate) fn pre_dispatch_checks( + pub(crate) fn unsigned_pre_dispatch_checks( solution: &RawSolution>, ) -> DispatchResult { { @@ -701,7 +700,7 @@ pub mod two_phase { } } #[allow(deprecated)] - impl ValidateUnsigned for Module + impl ValidateUnsigned for Module where ExtendedBalance: From>>, { @@ -744,9 +743,9 @@ pub mod two_phase { } /// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] /// implementer. - pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< - ::AccountId, - ::BlockNumber, + pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< + ::AccountId, + ::BlockNumber, >>::CompactSolution; /// The voter index. Derived from [`CompactOf`]. pub type CompactVoterIndexOf = as CompactSolution>::Voter; @@ -755,12 +754,12 @@ pub mod two_phase { /// The accuracy of the election. Derived from [`CompactOf`]. pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - type PositiveImbalanceOf = <::Currency as Currency< - ::AccountId, + <::Currency as Currency<::AccountId>>::Balance; + type PositiveImbalanceOf = <::Currency as Currency< + ::AccountId, >>::PositiveImbalance; - type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, + type NegativeImbalanceOf = <::Currency as Currency< + ::AccountId, >>::NegativeImbalance; /// Current phase of the pallet. pub enum Phase { @@ -768,19 +767,20 @@ pub mod two_phase { Off, /// Signed phase is open. Signed, - /// Unsigned phase is open. + /// Unsigned phase. First element is whether it is open or not, second the starting block + /// number. Unsigned((bool, Bn)), } - impl ::core::marker::StructuralPartialEq for Phase {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Phase { - #[inline] - fn eq(&self, other: &Phase) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { + impl ::core::marker::StructuralPartialEq for Phase {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Phase { + #[inline] + fn eq(&self, other: &Phase) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { match (&*self, &*other) { (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { (*__self_0) == (*__arg_1_0) @@ -807,25 +807,25 @@ pub mod two_phase { } else { true } - } - } - } - impl ::core::marker::StructuralEq for Phase {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Phase { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq<(bool, Bn)>; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Phase { - #[inline] + } + } + } + impl ::core::marker::StructuralEq for Phase {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for Phase { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq<(bool, Bn)>; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for Phase { + #[inline] fn clone(&self) -> Phase { match (&*self,) { (&Phase::Off,) => Phase::Off, @@ -835,87 +835,91 @@ pub mod two_phase { } } } - } + } #[automatically_derived] #[allow(unused_qualifications)] impl ::core::marker::Copy for Phase {} - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Phase - where - Bn: _parity_scale_codec::Encode, - (bool, Bn): _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - Phase::Off => { - dest.push_byte(0usize as u8); - } - Phase::Signed => { - dest.push_byte(1usize as u8); - } - Phase::Unsigned(ref aa) => { - dest.push_byte(2usize as u8); - dest.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for Phase - where - Bn: _parity_scale_codec::Encode, - (bool, Bn): _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Phase - where - Bn: _parity_scale_codec::Decode, - (bool, Bn): _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(Phase::Off), - x if x == 1usize as u8 => Ok(Phase::Signed), - x if x == 2usize as u8 => Ok(Phase::Unsigned({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field Phase :: Unsigned.0".into()), - Ok(a) => a, - } - })), - x => Err("No such variant in enum Phase".into()), - } - } - } - }; - impl core::fmt::Debug for Phase - where - Bn: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for Phase + where + Bn: _parity_scale_codec::Encode, + (bool, Bn): _parity_scale_codec::Encode, + { + fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( + &self, + __codec_dest_edqy: &mut __CodecOutputEdqy, + ) { + match *self { + Phase::Off => { + __codec_dest_edqy.push_byte(0usize as u8); + } + Phase::Signed => { + __codec_dest_edqy.push_byte(1usize as u8); + } + Phase::Unsigned(ref aa) => { + __codec_dest_edqy.push_byte(2usize as u8); + __codec_dest_edqy.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for Phase + where + Bn: _parity_scale_codec::Encode, + (bool, Bn): _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for Phase + where + Bn: _parity_scale_codec::Decode, + (bool, Bn): _parity_scale_codec::Decode, + { + fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( + __codec_input_edqy: &mut __CodecInputEdqy, + ) -> core::result::Result { + match __codec_input_edqy.read_byte()? { + __codec_x_edqy if __codec_x_edqy == 0usize as u8 => Ok(Phase::Off), + __codec_x_edqy if __codec_x_edqy == 1usize as u8 => Ok(Phase::Signed), + __codec_x_edqy if __codec_x_edqy == 2usize as u8 => Ok(Phase::Unsigned({ + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => return Err("Error decoding field Phase :: Unsigned.0".into()), + Ok(__codec_res_edqy) => __codec_res_edqy, + } + })), + _ => Err("No such variant in enum Phase".into()), + } + } + } + }; + impl core::fmt::Debug for Phase + where + Bn: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { Self::Off => fmt.debug_tuple("Phase::Off").finish(), Self::Signed => fmt.debug_tuple("Phase::Signed").finish(), Self::Unsigned(ref a0) => fmt.debug_tuple("Phase::Unsigned").field(a0).finish(), _ => Ok(()), } - } - } - impl Default for Phase { - fn default() -> Self { - Phase::Off - } - } + } + } + impl Default for Phase { + fn default() -> Self { + Phase::Off + } + } impl Phase { /// Weather the phase is signed or not. pub fn is_signed(&self) -> bool { @@ -1001,80 +1005,89 @@ pub mod two_phase { } } } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for ElectionCompute {} - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for ElectionCompute { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - ElectionCompute::OnChain => { - dest.push_byte(0usize as u8); - } - ElectionCompute::Signed => { - dest.push_byte(1usize as u8); - } - ElectionCompute::Unsigned => { - dest.push_byte(2usize as u8); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for ElectionCompute {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for ElectionCompute { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(ElectionCompute::OnChain), - x if x == 1usize as u8 => Ok(ElectionCompute::Signed), - x if x == 2usize as u8 => Ok(ElectionCompute::Unsigned), - x => Err("No such variant in enum ElectionCompute".into()), - } - } - } - }; - impl core::fmt::Debug for ElectionCompute { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::OnChain => fmt.debug_tuple("ElectionCompute::OnChain").finish(), - Self::Signed => fmt.debug_tuple("ElectionCompute::Signed").finish(), - Self::Unsigned => fmt.debug_tuple("ElectionCompute::Unsigned").finish(), - _ => Ok(()), - } - } - } - impl Default for ElectionCompute { - fn default() -> Self { - ElectionCompute::OnChain - } - } - /// A raw, unchecked solution. - /// - /// Such a solution should never become effective in anyway before being checked by the - /// [`Module::feasibility_check`] - pub struct RawSolution { - /// Compact election edges. - compact: C, - /// The _claimed_ score of the solution. - score: ElectionScore, - } - impl ::core::marker::StructuralPartialEq for RawSolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for RawSolution { - #[inline] - fn eq(&self, other: &RawSolution) -> bool { - match *other { + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::marker::Copy for ElectionCompute {} + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for ElectionCompute { + fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( + &self, + __codec_dest_edqy: &mut __CodecOutputEdqy, + ) { + match *self { + ElectionCompute::OnChain => { + __codec_dest_edqy.push_byte(0usize as u8); + } + ElectionCompute::Signed => { + __codec_dest_edqy.push_byte(1usize as u8); + } + ElectionCompute::Unsigned => { + __codec_dest_edqy.push_byte(2usize as u8); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for ElectionCompute {} + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for ElectionCompute { + fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( + __codec_input_edqy: &mut __CodecInputEdqy, + ) -> core::result::Result { + match __codec_input_edqy.read_byte()? { + __codec_x_edqy if __codec_x_edqy == 0usize as u8 => { + Ok(ElectionCompute::OnChain) + } + __codec_x_edqy if __codec_x_edqy == 1usize as u8 => Ok(ElectionCompute::Signed), + __codec_x_edqy if __codec_x_edqy == 2usize as u8 => { + Ok(ElectionCompute::Unsigned) + } + _ => Err("No such variant in enum ElectionCompute".into()), + } + } + } + }; + impl core::fmt::Debug for ElectionCompute { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::OnChain => fmt.debug_tuple("ElectionCompute::OnChain").finish(), + Self::Signed => fmt.debug_tuple("ElectionCompute::Signed").finish(), + Self::Unsigned => fmt.debug_tuple("ElectionCompute::Unsigned").finish(), + _ => Ok(()), + } + } + } + impl Default for ElectionCompute { + fn default() -> Self { + ElectionCompute::OnChain + } + } + /// A raw, unchecked solution. + /// + /// This is what will get submitted to the chain. + /// + /// Such a solution should never become effective in anyway before being checked by the + /// [`Module::feasibility_check`]. + pub struct RawSolution { + /// Compact election edges. + compact: C, + /// The _claimed_ score of the solution. + score: ElectionScore, + } + impl ::core::marker::StructuralPartialEq for RawSolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for RawSolution { + #[inline] + fn eq(&self, other: &RawSolution) -> bool { + match *other { RawSolution { compact: ref __self_1_0, score: ref __self_1_1, @@ -1099,13 +1112,13 @@ pub mod two_phase { } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), }, } - } - } - impl ::core::marker::StructuralEq for RawSolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for RawSolution { - #[inline] + } + } + impl ::core::marker::StructuralEq for RawSolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for RawSolution { + #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { @@ -1113,7 +1126,7 @@ pub mod two_phase { let _: ::core::cmp::AssertParamIsEq; } } - } + } #[automatically_derived] #[allow(unused_qualifications)] impl ::core::clone::Clone for RawSolution { @@ -1130,80 +1143,85 @@ pub mod two_phase { } } } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for RawSolution - where - C: _parity_scale_codec::Encode, - C: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.compact); - dest.push(&self.score); + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for RawSolution + where + C: _parity_scale_codec::Encode, + C: _parity_scale_codec::Encode, + { + fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( + &self, + __codec_dest_edqy: &mut __CodecOutputEdqy, + ) { + __codec_dest_edqy.push(&self.compact); + __codec_dest_edqy.push(&self.score); + } + } + impl _parity_scale_codec::EncodeLike for RawSolution + where + C: _parity_scale_codec::Encode, + C: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for RawSolution + where + C: _parity_scale_codec::Decode, + C: _parity_scale_codec::Decode, + { + fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( + __codec_input_edqy: &mut __CodecInputEdqy, + ) -> core::result::Result { + Ok(RawSolution { + compact: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => return Err("Error decoding field RawSolution.compact".into()), + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + score: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => return Err("Error decoding field RawSolution.score".into()), + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + }) + } + } + }; + impl core::fmt::Debug for RawSolution + where + C: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("RawSolution") + .field("compact", &self.compact) + .field("score", &self.score) + .finish() + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for RawSolution { + #[inline] + fn default() -> RawSolution { + RawSolution { + compact: ::core::default::Default::default(), + score: ::core::default::Default::default(), } } - impl _parity_scale_codec::EncodeLike for RawSolution - where - C: _parity_scale_codec::Encode, - C: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for RawSolution - where - C: _parity_scale_codec::Decode, - C: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(RawSolution { - compact: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field RawSolution.compact".into()), - Ok(a) => a, - } - }, - score: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field RawSolution.score".into()), - Ok(a) => a, - } - }, - }) - } - } - }; - impl core::fmt::Debug for RawSolution - where - C: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("RawSolution") - .field("compact", &self.compact) - .field("score", &self.score) - .finish() - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for RawSolution { - #[inline] - fn default() -> RawSolution { - RawSolution { - compact: ::core::default::Default::default(), - score: ::core::default::Default::default(), - } - } - } + } /// A raw, unchecked signed submission. /// /// This is just a wrapper around [`RawSolution`] and some additional info. @@ -1315,151 +1333,160 @@ pub mod two_phase { } } } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for SignedSubmission - where - A: _parity_scale_codec::Encode, - A: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.who); - dest.push(&self.deposit); - dest.push(&self.reward); - dest.push(&self.solution); - } - } - impl _parity_scale_codec::EncodeLike for SignedSubmission - where - A: _parity_scale_codec::Encode, - A: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for SignedSubmission - where - A: _parity_scale_codec::Decode, - A: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - RawSolution: _parity_scale_codec::Decode, - RawSolution: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(SignedSubmission { - who: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.who".into()) - } - Ok(a) => a, - } - }, - deposit: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.deposit".into()) - } - Ok(a) => a, - } - }, - reward: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.reward".into()) - } - Ok(a) => a, - } - }, - solution: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.solution".into()) - } - Ok(a) => a, - } - }, - }) - } - } - }; - impl core::fmt::Debug for SignedSubmission - where - A: core::fmt::Debug, - B: core::fmt::Debug, - C: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("SignedSubmission") - .field("who", &self.who) - .field("deposit", &self.deposit) - .field("reward", &self.reward) - .field("solution", &self.solution) - .finish() - } - } - /// A checked and parsed solution, ready to be enacted. - pub struct ReadySolution { - /// The final supports of the solution. This is target-major vector, storing each winners, total - /// backing, and each individual backer. - supports: Supports, - /// The score of the solution. - /// - /// This is needed to potentially challenge the solution. - score: ElectionScore, - /// How this election was computed. - compute: ElectionCompute, - } - impl ::core::marker::StructuralPartialEq for ReadySolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for ReadySolution { - #[inline] - fn eq(&self, other: &ReadySolution) -> bool { - match *other { - ReadySolution { - supports: ref __self_1_0, - score: ref __self_1_1, - compute: ref __self_1_2, - } => match *self { - ReadySolution { - supports: ref __self_0_0, - score: ref __self_0_1, - compute: ref __self_0_2, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - } - }, - } - } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for SignedSubmission + where + A: _parity_scale_codec::Encode, + A: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + { + fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( + &self, + __codec_dest_edqy: &mut __CodecOutputEdqy, + ) { + __codec_dest_edqy.push(&self.who); + __codec_dest_edqy.push(&self.deposit); + __codec_dest_edqy.push(&self.reward); + __codec_dest_edqy.push(&self.solution); + } + } + impl _parity_scale_codec::EncodeLike for SignedSubmission + where + A: _parity_scale_codec::Encode, + A: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + B: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + RawSolution: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for SignedSubmission + where + A: _parity_scale_codec::Decode, + A: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + B: _parity_scale_codec::Decode, + RawSolution: _parity_scale_codec::Decode, + RawSolution: _parity_scale_codec::Decode, + { + fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( + __codec_input_edqy: &mut __CodecInputEdqy, + ) -> core::result::Result { + Ok(SignedSubmission { + who: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err("Error decoding field SignedSubmission.who".into()) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + deposit: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err("Error decoding field SignedSubmission.deposit".into()) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + reward: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err("Error decoding field SignedSubmission.reward".into()) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + solution: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err("Error decoding field SignedSubmission.solution".into()) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + }) + } + } + }; + impl core::fmt::Debug for SignedSubmission + where + A: core::fmt::Debug, + B: core::fmt::Debug, + C: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("SignedSubmission") + .field("who", &self.who) + .field("deposit", &self.deposit) + .field("reward", &self.reward) + .field("solution", &self.solution) + .finish() + } + } + /// A checked solution, ready to be enacted. + pub struct ReadySolution { + /// The final supports of the solution. + /// + /// This is target-major vector, storing each winners, total backing, and each individual + /// backer. + supports: Supports, + /// The score of the solution. + /// + /// This is needed to potentially challenge the solution. + score: ElectionScore, + /// How this election was computed. + compute: ElectionCompute, + } + impl ::core::marker::StructuralPartialEq for ReadySolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for ReadySolution { + #[inline] + fn eq(&self, other: &ReadySolution) -> bool { + match *other { + ReadySolution { + supports: ref __self_1_0, + score: ref __self_1_1, + compute: ref __self_1_2, + } => match *self { + ReadySolution { + supports: ref __self_0_0, + score: ref __self_0_1, + compute: ref __self_0_2, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + } + }, + } + } #[inline] fn ne(&self, other: &ReadySolution) -> bool { match *other { @@ -1479,13 +1506,13 @@ pub mod two_phase { } }, } - } - } - impl ::core::marker::StructuralEq for ReadySolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for ReadySolution { - #[inline] + } + } + impl ::core::marker::StructuralEq for ReadySolution {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for ReadySolution { + #[inline] #[doc(hidden)] fn assert_receiver_is_total_eq(&self) -> () { { @@ -1494,7 +1521,7 @@ pub mod two_phase { let _: ::core::cmp::AssertParamIsEq; } } - } + } #[automatically_derived] #[allow(unused_qualifications)] impl ::core::clone::Clone for ReadySolution { @@ -1513,28 +1540,31 @@ pub mod two_phase { } } } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for ReadySolution - where - Supports: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.supports); - dest.push(&self.score); - dest.push(&self.compute); - } - } - impl _parity_scale_codec::EncodeLike for ReadySolution - where - Supports: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - { - } - }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for ReadySolution + where + Supports: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, + { + fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( + &self, + __codec_dest_edqy: &mut __CodecOutputEdqy, + ) { + __codec_dest_edqy.push(&self.supports); + __codec_dest_edqy.push(&self.score); + __codec_dest_edqy.push(&self.compute); + } + } + impl _parity_scale_codec::EncodeLike for ReadySolution + where + Supports: _parity_scale_codec::Encode, + Supports: _parity_scale_codec::Encode, + { + } + }; const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] @@ -1544,36 +1574,39 @@ pub mod two_phase { Supports: _parity_scale_codec::Decode, Supports: _parity_scale_codec::Decode, { - fn decode( - input: &mut DecIn, + fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( + __codec_input_edqy: &mut __CodecInputEdqy, ) -> core::result::Result { Ok(ReadySolution { - supports: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field ReadySolution.supports".into()) - } - Ok(a) => a, - } - }, - score: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field ReadySolution.score".into()), - Ok(a) => a, - } - }, - compute: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field ReadySolution.compute".into()) - } - Ok(a) => a, - } - }, - }) + supports: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err("Error decoding field ReadySolution.supports".into()) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + score: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => return Err("Error decoding field ReadySolution.score".into()), + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + compute: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err("Error decoding field ReadySolution.compute".into()) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + }) } } }; @@ -1682,12 +1715,15 @@ pub mod two_phase { #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; impl _parity_scale_codec::Encode for WitnessData { - fn encode_to(&self, dest: &mut EncOut) { + fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( + &self, + __codec_dest_edqy: &mut __CodecOutputEdqy, + ) { { - dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . voters ) ) ; + __codec_dest_edqy . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . voters ) ) ; } { - dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . targets ) ) ; + __codec_dest_edqy . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . targets ) ) ; } } } @@ -1698,22 +1734,22 @@ pub mod two_phase { #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; impl _parity_scale_codec::Decode for WitnessData { - fn decode( - input: &mut DecIn, + fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( + __codec_input_edqy: &mut __CodecInputEdqy, ) -> core::result::Result { Ok(WitnessData { voters: { - let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; - match res { + let __codec_res_edqy = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( __codec_input_edqy ) ; + match __codec_res_edqy { Err(_) => return Err("Error decoding field WitnessData.voters".into()), - Ok(a) => a.into(), + Ok(__codec_res_edqy) => __codec_res_edqy.into(), } }, targets: { - let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; - match res { + let __codec_res_edqy = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( __codec_input_edqy ) ; + match __codec_res_edqy { Err(_) => return Err("Error decoding field WitnessData.targets".into()), - Ok(a) => a.into(), + Ok(__codec_res_edqy) => __codec_res_edqy.into(), } }, }) @@ -1739,7 +1775,203 @@ pub mod two_phase { } } } - /// The crate errors. Note that this is different from the [`PalletError`]. + /// A snapshot of all the data that is needed for en entire round. They are provided by + /// [`ElectionDataProvider`] at the beginning of the signed phase and are kept around until the + /// round is finished. + /// + /// These are stored together because they are often times accessed together. + pub struct RoundSnapshot { + /// All of the voters. + pub voters: Vec<(A, VoteWeight, Vec)>, + /// All of the targets. + pub targets: Vec, + /// Desired number of winners to be elected for this round. + pub desired_targets: u32, + } + impl ::core::marker::StructuralPartialEq for RoundSnapshot {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for RoundSnapshot { + #[inline] + fn eq(&self, other: &RoundSnapshot) -> bool { + match *other { + RoundSnapshot { + voters: ref __self_1_0, + targets: ref __self_1_1, + desired_targets: ref __self_1_2, + } => match *self { + RoundSnapshot { + voters: ref __self_0_0, + targets: ref __self_0_1, + desired_targets: ref __self_0_2, + } => { + (*__self_0_0) == (*__self_1_0) + && (*__self_0_1) == (*__self_1_1) + && (*__self_0_2) == (*__self_1_2) + } + }, + } + } + #[inline] + fn ne(&self, other: &RoundSnapshot) -> bool { + match *other { + RoundSnapshot { + voters: ref __self_1_0, + targets: ref __self_1_1, + desired_targets: ref __self_1_2, + } => match *self { + RoundSnapshot { + voters: ref __self_0_0, + targets: ref __self_0_1, + desired_targets: ref __self_0_2, + } => { + (*__self_0_0) != (*__self_1_0) + || (*__self_0_1) != (*__self_1_1) + || (*__self_0_2) != (*__self_1_2) + } + }, + } + } + } + impl ::core::marker::StructuralEq for RoundSnapshot {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for RoundSnapshot { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq)>>; + let _: ::core::cmp::AssertParamIsEq>; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for RoundSnapshot { + #[inline] + fn clone(&self) -> RoundSnapshot { + match *self { + RoundSnapshot { + voters: ref __self_0_0, + targets: ref __self_0_1, + desired_targets: ref __self_0_2, + } => RoundSnapshot { + voters: ::core::clone::Clone::clone(&(*__self_0_0)), + targets: ::core::clone::Clone::clone(&(*__self_0_1)), + desired_targets: ::core::clone::Clone::clone(&(*__self_0_2)), + }, + } + } + } + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for RoundSnapshot + where + Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Encode, + Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Encode, + Vec: _parity_scale_codec::Encode, + Vec: _parity_scale_codec::Encode, + { + fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( + &self, + __codec_dest_edqy: &mut __CodecOutputEdqy, + ) { + __codec_dest_edqy.push(&self.voters); + __codec_dest_edqy.push(&self.targets); + __codec_dest_edqy.push(&self.desired_targets); + } + } + impl _parity_scale_codec::EncodeLike for RoundSnapshot + where + Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Encode, + Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Encode, + Vec: _parity_scale_codec::Encode, + Vec: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for RoundSnapshot + where + Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Decode, + Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Decode, + Vec: _parity_scale_codec::Decode, + Vec: _parity_scale_codec::Decode, + { + fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( + __codec_input_edqy: &mut __CodecInputEdqy, + ) -> core::result::Result { + Ok(RoundSnapshot { + voters: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err("Error decoding field RoundSnapshot.voters".into()) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + targets: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err("Error decoding field RoundSnapshot.targets".into()) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + desired_targets: { + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err( + "Error decoding field RoundSnapshot.desired_targets".into() + ) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + }, + }) + } + } + }; + impl core::fmt::Debug for RoundSnapshot + where + A: core::fmt::Debug, + { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + fmt.debug_struct("RoundSnapshot") + .field("voters", &self.voters) + .field("targets", &self.targets) + .field("desired_targets", &self.desired_targets) + .finish() + } + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::default::Default for RoundSnapshot { + #[inline] + fn default() -> RoundSnapshot { + RoundSnapshot { + voters: ::core::default::Default::default(), + targets: ::core::default::Default::default(), + desired_targets: ::core::default::Default::default(), + } + } + } + /// The crate errors. + /// + /// Note that this is different from the [`PalletError`]. pub enum Error { /// A feasibility error. Feasibility(FeasibilityError), @@ -1757,89 +1989,89 @@ pub mod two_phase { impl core::fmt::Debug for Error { fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { match self { - Self::Feasibility(ref a0) => { - fmt.debug_tuple("Error::Feasibility").field(a0).finish() - } - Self::OnChainFallback(ref a0) => { - fmt.debug_tuple("Error::OnChainFallback").field(a0).finish() - } - Self::NposElections(ref a0) => { - fmt.debug_tuple("Error::NposElections").field(a0).finish() - } - Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), - Self::PoolSubmissionFailed => { - fmt.debug_tuple("Error::PoolSubmissionFailed").finish() - } - _ => Ok(()), - } - } - } - impl ::core::marker::StructuralEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Error { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; + Self::Feasibility(ref a0) => { + fmt.debug_tuple("Error::Feasibility").field(a0).finish() + } + Self::OnChainFallback(ref a0) => { + fmt.debug_tuple("Error::OnChainFallback").field(a0).finish() + } + Self::NposElections(ref a0) => { + fmt.debug_tuple("Error::NposElections").field(a0).finish() + } + Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), + Self::PoolSubmissionFailed => { + fmt.debug_tuple("Error::PoolSubmissionFailed").finish() + } + _ => Ok(()), } } } - impl ::core::marker::StructuralPartialEq for Error {} + impl ::core::marker::StructuralEq for Error {} #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Error { - #[inline] - fn eq(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - ( - &Error::OnChainFallback(ref __self_0), - &Error::OnChainFallback(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - ( - &Error::NposElections(ref __self_0), - &Error::NposElections(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - ( - &Error::OnChainFallback(ref __self_0), - &Error::OnChainFallback(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - ( - &Error::NposElections(ref __self_0), - &Error::NposElections(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - _ => false, - } - } else { - true - } + impl ::core::cmp::Eq for Error { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + let _: ::core::cmp::AssertParamIsEq; + } + } + } + impl ::core::marker::StructuralPartialEq for Error {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for Error { + #[inline] + fn eq(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { + (*__self_0) == (*__arg_1_0) + } + ( + &Error::OnChainFallback(ref __self_0), + &Error::OnChainFallback(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + ( + &Error::NposElections(ref __self_0), + &Error::NposElections(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &Error) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { + (*__self_0) != (*__arg_1_0) + } + ( + &Error::OnChainFallback(ref __self_0), + &Error::OnChainFallback(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + ( + &Error::NposElections(ref __self_0), + &Error::NposElections(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => false, + } + } else { + true + } } } } @@ -1853,6 +2085,11 @@ pub mod two_phase { Error::NposElections(e) } } + impl From for Error { + fn from(e: FeasibilityError) -> Self { + Error::Feasibility(e) + } + } /// Errors that can happen in the feasibility check. pub enum FeasibilityError { /// Wrong number of winners presented. @@ -1862,7 +2099,7 @@ pub mod two_phase { /// This must be an internal error of the chain. SnapshotUnavailable, /// Internal error from the election crate. - NposElectionError(sp_npos_elections::Error), + NposElection(sp_npos_elections::Error), /// A vote is invalid. InvalidVote, /// A voter is invalid. @@ -1872,39 +2109,39 @@ pub mod two_phase { /// The given score was invalid. InvalidScore, } - impl core::fmt::Debug for FeasibilityError { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::WrongWinnerCount => fmt - .debug_tuple("FeasibilityError::WrongWinnerCount") - .finish(), - Self::SnapshotUnavailable => fmt - .debug_tuple("FeasibilityError::SnapshotUnavailable") - .finish(), - Self::NposElectionError(ref a0) => fmt - .debug_tuple("FeasibilityError::NposElectionError") - .field(a0) - .finish(), - Self::InvalidVote => fmt.debug_tuple("FeasibilityError::InvalidVote").finish(), - Self::InvalidVoter => fmt.debug_tuple("FeasibilityError::InvalidVoter").finish(), - Self::InvalidWinner => fmt.debug_tuple("FeasibilityError::InvalidWinner").finish(), - Self::InvalidScore => fmt.debug_tuple("FeasibilityError::InvalidScore").finish(), - _ => Ok(()), - } - } - } - impl ::core::marker::StructuralEq for FeasibilityError {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for FeasibilityError { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - } - } - } + impl core::fmt::Debug for FeasibilityError { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Self::WrongWinnerCount => fmt + .debug_tuple("FeasibilityError::WrongWinnerCount") + .finish(), + Self::SnapshotUnavailable => fmt + .debug_tuple("FeasibilityError::SnapshotUnavailable") + .finish(), + Self::NposElection(ref a0) => fmt + .debug_tuple("FeasibilityError::NposElection") + .field(a0) + .finish(), + Self::InvalidVote => fmt.debug_tuple("FeasibilityError::InvalidVote").finish(), + Self::InvalidVoter => fmt.debug_tuple("FeasibilityError::InvalidVoter").finish(), + Self::InvalidWinner => fmt.debug_tuple("FeasibilityError::InvalidWinner").finish(), + Self::InvalidScore => fmt.debug_tuple("FeasibilityError::InvalidScore").finish(), + _ => Ok(()), + } + } + } + impl ::core::marker::StructuralEq for FeasibilityError {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::Eq for FeasibilityError { + #[inline] + #[doc(hidden)] + fn assert_receiver_is_total_eq(&self) -> () { + { + let _: ::core::cmp::AssertParamIsEq; + } + } + } impl ::core::marker::StructuralPartialEq for FeasibilityError {} #[automatically_derived] #[allow(unused_qualifications)] @@ -1914,66 +2151,50 @@ pub mod two_phase { { let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &FeasibilityError::NposElectionError(ref __self_0), - &FeasibilityError::NposElectionError(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &FeasibilityError) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &FeasibilityError::NposElectionError(ref __self_0), - &FeasibilityError::NposElectionError(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - _ => false, - } - } else { - true - } + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &FeasibilityError::NposElection(ref __self_0), + &FeasibilityError::NposElection(ref __arg_1_0), + ) => (*__self_0) == (*__arg_1_0), + _ => true, + } + } else { + false + } + } + } + #[inline] + fn ne(&self, other: &FeasibilityError) -> bool { + { + let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; + let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; + if true && __self_vi == __arg_1_vi { + match (&*self, &*other) { + ( + &FeasibilityError::NposElection(ref __self_0), + &FeasibilityError::NposElection(ref __arg_1_0), + ) => (*__self_0) != (*__arg_1_0), + _ => false, + } + } else { + true + } } } } impl From for FeasibilityError { fn from(e: sp_npos_elections::Error) -> Self { - FeasibilityError::NposElectionError(e) - } - } - /// The weights for this pallet. - pub trait WeightInfo { - fn feasibility_check() -> Weight; - fn submit() -> Weight; - fn submit_unsigned() -> Weight; - } - impl WeightInfo for () { - fn feasibility_check() -> Weight { - Default::default() - } - fn submit() -> Weight { - Default::default() - } - fn submit_unsigned() -> Weight { - Default::default() + FeasibilityError::NposElection(e) } } - pub trait Trait: frame_system::Trait + SendTransactionTypes> + pub trait WeightInfo {} + pub trait Config: frame_system::Config + SendTransactionTypes> where ExtendedBalance: From>>, { /// Event type. - type Event: From> + Into<::Event>; + type Event: From> + Into<::Event>; /// Currency type. type Currency: ReservableCurrency + Currency; /// Duration of the signed phase. @@ -1990,7 +2211,10 @@ pub mod two_phase { type SignedDepositWeight: Get>; /// The minimum amount of improvement to the solution score that defines a solution as "better". type SolutionImprovementThreshold: Get; + /// Maximum number of iteration of balancing that will be executed in the embedded miner of the + /// pallet. type UnsignedMaxIterations: Get; + /// The priority of the unsigned transaction submitted in the unsigned-phase type UnsignedPriority: Get; /// Handler for the slashed deposits. type SlashHandler: OnUnbalanced>; @@ -1999,7 +2223,7 @@ pub mod two_phase { /// Something that will provide the election data. type ElectionDataProvider: ElectionDataProvider; /// The weight of the pallet. - type WeightInfo: WeightInfo; + type WeightInfo; } use self::sp_api_hidden_includes_decl_storage::hidden_include::{ IterableStorageDoubleMap as _, IterableStorageMap as _, StorageDoubleMap as _, @@ -2014,11 +2238,9 @@ pub mod two_phase { type CurrentPhase; type SignedSubmissions; type QueuedSolution; - type SnapshotTargets; - type SnapshotVoters; - type DesiredTargets; + type Snapshot; } - impl Store for Module + impl Store for Module where ExtendedBalance: From>>, { @@ -2026,15 +2248,13 @@ pub mod two_phase { type CurrentPhase = CurrentPhase; type SignedSubmissions = SignedSubmissions; type QueuedSolution = QueuedSolution; - type SnapshotTargets = SnapshotTargets; - type SnapshotVoters = SnapshotVoters; - type DesiredTargets = DesiredTargets; + type Snapshot = Snapshot; } - impl Module + impl Module where ExtendedBalance: From>>, { - /// Internal counter ofr the number of rounds. + /// Internal counter for the number of rounds. /// /// This is useful for de-duplication of transactions submitted to the pool, and general /// diagnostics of the module. @@ -2056,23 +2276,11 @@ pub mod two_phase { pub fn queued_solution() -> Option> { < QueuedSolution < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < ReadySolution < T :: AccountId > > > :: get ( ) } - /// Snapshot of all Voters. + /// Snapshot data of the round. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn snapshot_targets() -> Option> { - < SnapshotTargets < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < T :: AccountId > > > :: get ( ) - } - /// Snapshot of all targets. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn snapshot_voters() -> Option)>> { - < SnapshotVoters < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < ( T :: AccountId , VoteWeight , Vec < T :: AccountId > ) > > > :: get ( ) - } - /// Desired number of targets to elect. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn desired_targets() -> u32 { - < DesiredTargets < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) + pub fn snapshot() -> Option> { + < Snapshot < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < RoundSnapshot < T :: AccountId > > > :: get ( ) } } #[doc(hidden)] @@ -2088,7 +2296,7 @@ pub mod two_phase { self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructRound where ExtendedBalance: From>>, @@ -2105,11 +2313,11 @@ pub mod two_phase { .clone() } } - unsafe impl Send for __GetByteStructRound where + unsafe impl Send for __GetByteStructRound where ExtendedBalance: From>> { } - unsafe impl Sync for __GetByteStructRound where + unsafe impl Sync for __GetByteStructRound where ExtendedBalance: From>> { } @@ -2126,7 +2334,7 @@ pub mod two_phase { self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte for __GetByteStructCurrentPhase where ExtendedBalance: From>>, @@ -2143,187 +2351,29 @@ pub mod two_phase { .clone() } } - unsafe impl Send for __GetByteStructCurrentPhase where + unsafe impl Send for __GetByteStructCurrentPhase where ExtendedBalance: From>> { } - unsafe impl Sync for __GetByteStructCurrentPhase where + unsafe impl Sync for __GetByteStructCurrentPhase where ExtendedBalance: From>> { } - #[doc(hidden)] - pub struct __GetByteStructSignedSubmissions( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_SignedSubmissions: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructSignedSubmissions - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec - { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SignedSubmissions . get_or_init ( | | { let def_val : Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > = Default :: default ( ) ; < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > as Encode > :: encode ( & def_val ) } ) . clone ( ) - } - } - unsafe impl Send for __GetByteStructSignedSubmissions where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructSignedSubmissions where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructQueuedSolution( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_QueuedSolution: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructQueuedSolution - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec - { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_QueuedSolution - .get_or_init(|| { - let def_val: Option> = Default::default(); - > as Encode>::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructQueuedSolution where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructQueuedSolution where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructSnapshotTargets( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_SnapshotTargets: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructSnapshotTargets - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec - { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SnapshotTargets - .get_or_init(|| { - let def_val: Option> = Default::default(); - > as Encode>::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructSnapshotTargets where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructSnapshotTargets where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructSnapshotVoters( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_SnapshotVoters: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructSnapshotVoters - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec - { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SnapshotVoters - .get_or_init(|| { - let def_val: Option)>> = - Default::default(); - )>> as Encode>::encode( - &def_val, - ) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructSnapshotVoters where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructSnapshotVoters where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructDesiredTargets( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] + #[doc(hidden)] + pub struct __GetByteStructSignedSubmissions( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_DesiredTargets: + static __CACHE_GET_BYTE_STRUCT_SignedSubmissions: self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructDesiredTargets + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructSignedSubmissions where ExtendedBalance: From>>, { @@ -2331,30 +2381,101 @@ pub mod two_phase { &self, ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_DesiredTargets + __CACHE_GET_BYTE_STRUCT_SignedSubmissions . get_or_init ( | | { let def_val : Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > = Default :: default ( ) ; < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > as Encode > :: encode ( & def_val ) } ) . clone ( ) + } + } + unsafe impl Send for __GetByteStructSignedSubmissions where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructSignedSubmissions where + ExtendedBalance: From>> + { + } + #[doc(hidden)] + pub struct __GetByteStructQueuedSolution( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_QueuedSolution: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructQueuedSolution + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_QueuedSolution .get_or_init(|| { - let def_val: u32 = Default::default(); - ::encode(&def_val) + let def_val: Option> = Default::default(); + > as Encode>::encode(&def_val) + }) + .clone() + } + } + unsafe impl Send for __GetByteStructQueuedSolution where + ExtendedBalance: From>> + { + } + unsafe impl Sync for __GetByteStructQueuedSolution where + ExtendedBalance: From>> + { + } + #[doc(hidden)] + pub struct __GetByteStructSnapshot( + pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T), + >, + ); + #[cfg(feature = "std")] + #[allow(non_upper_case_globals)] + static __CACHE_GET_BYTE_STRUCT_Snapshot: + self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, + > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); + #[cfg(feature = "std")] + impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte + for __GetByteStructSnapshot + where + ExtendedBalance: From>>, + { + fn default_byte( + &self, + ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { + use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; + __CACHE_GET_BYTE_STRUCT_Snapshot + .get_or_init(|| { + let def_val: Option> = Default::default(); + > as Encode>::encode(&def_val) }) .clone() } } - unsafe impl Send for __GetByteStructDesiredTargets where + unsafe impl Send for __GetByteStructSnapshot where ExtendedBalance: From>> { } - unsafe impl Sync for __GetByteStructDesiredTargets where + unsafe impl Sync for __GetByteStructSnapshot where ExtendedBalance: From>> { } - impl Module + impl Module where ExtendedBalance: From>>, { #[doc(hidden)] pub fn storage_metadata( ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::StorageMetadata { - self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Round" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructRound :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Internal counter ofr the number of rounds." , "" , " This is useful for de-duplication of transactions submitted to the pool, and general" , " diagnostics of the module." , "" , " This is merely incremented once per every time that signed phase starts." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec, CompactOf>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted (worse -> best) list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current best solution, signed or unsigned." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } ] [ .. ] ) , } + self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Round" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructRound :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Internal counter for the number of rounds." , "" , " This is useful for de-duplication of transactions submitted to the pool, and general" , " diagnostics of the module." , "" , " This is merely incremented once per every time that signed phase starts." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec, CompactOf>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted (worse -> best) list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current best solution, signed or unsigned." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Snapshot" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "RoundSnapshot" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshot :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot data of the round." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } ] [ .. ] ) , } } } /// Hidden instance generated to be internally used when module is used without @@ -2398,18 +2519,22 @@ pub mod two_phase { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for __InherentHiddenInstance { - fn encode_to(&self, dest: &mut EncOut) {} - } - impl _parity_scale_codec::EncodeLike for __InherentHiddenInstance {} + impl _parity_scale_codec::Encode for __InherentHiddenInstance { + fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( + &self, + __codec_dest_edqy: &mut __CodecOutputEdqy, + ) { + } + } + impl _parity_scale_codec::EncodeLike for __InherentHiddenInstance {} }; const _: () = { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; impl _parity_scale_codec::Decode for __InherentHiddenInstance { - fn decode( - input: &mut DecIn, + fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( + __codec_input_edqy: &mut __CodecInputEdqy, ) -> core::result::Result { Ok(__InherentHiddenInstance) } @@ -2425,7 +2550,7 @@ pub mod two_phase { { const PREFIX: &'static str = "TwoPhaseElectionProvider"; } - /// Internal counter ofr the number of rounds. + /// Internal counter for the number of rounds. /// /// This is useful for de-duplication of transactions submitted to the pool, and general /// diagnostics of the module. @@ -2454,14 +2579,14 @@ pub mod two_phase { } } /// Current phase. - pub struct CurrentPhase( + pub struct CurrentPhase( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T,), >, ) where ExtendedBalance: From>>; - impl + impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< Phase, > for CurrentPhase @@ -2483,14 +2608,14 @@ pub mod two_phase { } } /// Sorted (worse -> best) list of unchecked, signed solutions. - pub struct SignedSubmissions( + pub struct SignedSubmissions( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T,), >, ) where ExtendedBalance: From>>; - impl + impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< Vec, CompactOf>>, > for SignedSubmissions @@ -2516,14 +2641,14 @@ pub mod two_phase { } } /// Current best solution, signed or unsigned. - pub struct QueuedSolution( + pub struct QueuedSolution( self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< (T,), >, ) where ExtendedBalance: From>>; - impl + impl self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< ReadySolution, > for QueuedSolution @@ -2531,137 +2656,77 @@ pub mod two_phase { ExtendedBalance: From>>, { type Query = Option>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"QueuedSolution" - } - fn from_optional_value_to_query(v: Option>) -> Self::Query { - v.or_else(|| Default::default()) - } - fn from_query_to_optional_value(v: Self::Query) -> Option> { - v - } - } - /// Snapshot of all Voters. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub struct SnapshotTargets( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec, - > for SnapshotTargets - where - ExtendedBalance: From>>, - { - type Query = Option>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"SnapshotTargets" - } - fn from_optional_value_to_query(v: Option>) -> Self::Query { - v.or_else(|| Default::default()) - } - fn from_query_to_optional_value(v: Self::Query) -> Option> { - v - } - } - /// Snapshot of all targets. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub struct SnapshotVoters( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec<(T::AccountId, VoteWeight, Vec)>, - > for SnapshotVoters - where - ExtendedBalance: From>>, - { - type Query = Option)>>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"SnapshotVoters" - } - fn from_optional_value_to_query( - v: Option)>>, - ) -> Self::Query { - v.or_else(|| Default::default()) - } - fn from_query_to_optional_value( - v: Self::Query, - ) -> Option)>> { - v - } - } - /// Desired number of targets to elect. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub struct DesiredTargets( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, - ); - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - u32, - > for DesiredTargets - { - type Query = u32; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"DesiredTargets" - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - v.unwrap_or_else(|| Default::default()) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - Some(v) - } - } - /// [`RawEvent`] specialized for the configuration [`Trait`] - /// - /// [`RawEvent`]: enum.RawEvent.html - /// [`Trait`]: trait.Trait.html - pub type Event = RawEvent<::AccountId>; - /// Events for this module. - /// - pub enum RawEvent { - /// A solution was stored with the given compute. - /// - /// If the solution is signed, this means that it hasn't yet been processed. If the solution - /// is unsigned, this means that it has also been processed. - SolutionStored(ElectionCompute), - /// The election has been finalized, with `Some` of the given computation, or else if the - /// election failed, `None`. - ElectionFinalized(Option), - /// An account has been rewarded for their signed submission being finalized. - Rewarded(AccountId), - /// An account has been slashed for submitting an invalid signed submission. - Slashed(AccountId), - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for RawEvent { - #[inline] - fn clone(&self) -> RawEvent { - match (&*self,) { + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"QueuedSolution" + } + fn from_optional_value_to_query(v: Option>) -> Self::Query { + v.or_else(|| Default::default()) + } + fn from_query_to_optional_value(v: Self::Query) -> Option> { + v + } + } + /// Snapshot data of the round. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + pub struct Snapshot( + self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< + (T,), + >, + ) + where + ExtendedBalance: From>>; + impl + self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< + RoundSnapshot, + > for Snapshot + where + ExtendedBalance: From>>, + { + type Query = Option>; + fn module_prefix() -> &'static [u8] { + < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) + } + fn storage_prefix() -> &'static [u8] { + b"Snapshot" + } + fn from_optional_value_to_query(v: Option>) -> Self::Query { + v.or_else(|| Default::default()) + } + fn from_query_to_optional_value(v: Self::Query) -> Option> { + v + } + } + /// [`RawEvent`] specialized for the configuration [`Config`] + /// + /// [`RawEvent`]: enum.RawEvent.html + /// [`Config`]: trait.Config.html + pub type Event = RawEvent<::AccountId>; + /// Events for this module. + /// + pub enum RawEvent { + /// A solution was stored with the given compute. + /// + /// If the solution is signed, this means that it hasn't yet been processed. If the solution + /// is unsigned, this means that it has also been processed. + SolutionStored(ElectionCompute), + /// The election has been finalized, with `Some` of the given computation, or else if the + /// election failed, `None`. + ElectionFinalized(Option), + /// An account has been rewarded for their signed submission being finalized. + Rewarded(AccountId), + /// An account has been slashed for submitting an invalid signed submission. + Slashed(AccountId), + } + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::clone::Clone for RawEvent { + #[inline] + fn clone(&self) -> RawEvent { + match (&*self,) { (&RawEvent::SolutionStored(ref __self_0),) => { RawEvent::SolutionStored(::core::clone::Clone::clone(&(*__self_0))) } @@ -2675,13 +2740,13 @@ pub mod two_phase { RawEvent::Slashed(::core::clone::Clone::clone(&(*__self_0))) } } - } - } - impl ::core::marker::StructuralPartialEq for RawEvent {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for RawEvent { - #[inline] + } + } + impl ::core::marker::StructuralPartialEq for RawEvent {} + #[automatically_derived] + #[allow(unused_qualifications)] + impl ::core::cmp::PartialEq for RawEvent { + #[inline] fn eq(&self, other: &RawEvent) -> bool { { let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; @@ -2737,7 +2802,7 @@ pub mod two_phase { } } } - } + } impl ::core::marker::StructuralEq for RawEvent {} #[automatically_derived] #[allow(unused_qualifications)] @@ -2753,105 +2818,117 @@ pub mod two_phase { } } } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for RawEvent - where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - RawEvent::SolutionStored(ref aa) => { - dest.push_byte(0usize as u8); - dest.push(aa); - } - RawEvent::ElectionFinalized(ref aa) => { - dest.push_byte(1usize as u8); - dest.push(aa); - } - RawEvent::Rewarded(ref aa) => { - dest.push_byte(2usize as u8); - dest.push(aa); - } - RawEvent::Slashed(ref aa) => { - dest.push_byte(3usize as u8); - dest.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for RawEvent - where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for RawEvent + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Encode for RawEvent + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + { + fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( + &self, + __codec_dest_edqy: &mut __CodecOutputEdqy, + ) { + match *self { + RawEvent::SolutionStored(ref aa) => { + __codec_dest_edqy.push_byte(0usize as u8); + __codec_dest_edqy.push(aa); + } + RawEvent::ElectionFinalized(ref aa) => { + __codec_dest_edqy.push_byte(1usize as u8); + __codec_dest_edqy.push(aa); + } + RawEvent::Rewarded(ref aa) => { + __codec_dest_edqy.push_byte(2usize as u8); + __codec_dest_edqy.push(aa); + } + RawEvent::Slashed(ref aa) => { + __codec_dest_edqy.push_byte(3usize as u8); + __codec_dest_edqy.push(aa); + } + _ => (), + } + } + } + impl _parity_scale_codec::EncodeLike for RawEvent + where + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + AccountId: _parity_scale_codec::Encode, + { + } + }; + const _: () = { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for RawEvent where AccountId: _parity_scale_codec::Decode, AccountId: _parity_scale_codec::Decode, AccountId: _parity_scale_codec::Decode, AccountId: _parity_scale_codec::Decode, { - fn decode( - input: &mut DecIn, + fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( + __codec_input_edqy: &mut __CodecInputEdqy, ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(RawEvent::SolutionStored({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err( - "Error decoding field RawEvent :: SolutionStored.0".into() - ) - } - Ok(a) => a, - } - })), - x if x == 1usize as u8 => Ok(RawEvent::ElectionFinalized({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err( - "Error decoding field RawEvent :: ElectionFinalized.0".into() - ) - } - Ok(a) => a, - } - })), - x if x == 2usize as u8 => Ok(RawEvent::Rewarded({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field RawEvent :: Rewarded.0".into()) - } - Ok(a) => a, - } - })), - x if x == 3usize as u8 => Ok(RawEvent::Slashed({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field RawEvent :: Slashed.0".into()) - } - Ok(a) => a, - } - })), - x => Err("No such variant in enum RawEvent".into()), - } + match __codec_input_edqy.read_byte()? { + __codec_x_edqy if __codec_x_edqy == 0usize as u8 => { + Ok(RawEvent::SolutionStored({ + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err( + "Error decoding field RawEvent :: SolutionStored.0".into() + ) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + })) + } + __codec_x_edqy if __codec_x_edqy == 1usize as u8 => { + Ok(RawEvent::ElectionFinalized({ + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err( + "Error decoding field RawEvent :: ElectionFinalized.0" + .into(), + ) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + })) + } + __codec_x_edqy if __codec_x_edqy == 2usize as u8 => Ok(RawEvent::Rewarded({ + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err("Error decoding field RawEvent :: Rewarded.0".into()) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + })), + __codec_x_edqy if __codec_x_edqy == 3usize as u8 => Ok(RawEvent::Slashed({ + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err("Error decoding field RawEvent :: Slashed.0".into()) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + })), + _ => Err("No such variant in enum RawEvent".into()), + } } } }; @@ -2924,7 +3001,7 @@ pub mod two_phase { ] } } - pub enum PalletError + pub enum PalletError where ExtendedBalance: From>>, { @@ -2942,7 +3019,7 @@ pub mod two_phase { /// The origin failed to pay the deposit. CannotPayDeposit, } - impl ::frame_support::sp_std::fmt::Debug for PalletError + impl ::frame_support::sp_std::fmt::Debug for PalletError where ExtendedBalance: From>>, { @@ -2953,7 +3030,7 @@ pub mod two_phase { f.write_str(self.as_str()) } } - impl PalletError + impl PalletError where ExtendedBalance: From>>, { @@ -2996,7 +3073,7 @@ pub mod two_phase { } } } - impl From> for &'static str + impl From> for &'static str where ExtendedBalance: From>>, { @@ -3004,7 +3081,7 @@ pub mod two_phase { err.as_str() } } - impl From> for ::frame_support::sp_runtime::DispatchError + impl From> for ::frame_support::sp_runtime::DispatchError where ExtendedBalance: From>>, { @@ -3018,7 +3095,7 @@ pub mod two_phase { } } } - impl ::frame_support::error::ModuleErrorMetadata for PalletError + impl ::frame_support::error::ModuleErrorMetadata for PalletError where ExtendedBalance: From>>, { @@ -3051,12 +3128,12 @@ pub mod two_phase { ] } } - pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>) + pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>) where ExtendedBalance: From>>; #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::clone::Clone for Module + impl ::core::clone::Clone for Module where ExtendedBalance: From>>, { @@ -3069,17 +3146,17 @@ pub mod two_phase { } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::marker::Copy for Module where + impl ::core::marker::Copy for Module where ExtendedBalance: From>> { } - impl ::core::marker::StructuralPartialEq for Module where + impl ::core::marker::StructuralPartialEq for Module where ExtendedBalance: From>> { } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Module + impl ::core::cmp::PartialEq for Module where ExtendedBalance: From>>, { @@ -3090,23 +3167,23 @@ pub mod two_phase { Module(ref __self_0_0) => (*__self_0_0) == (*__self_1_0), }, } - } - #[inline] - fn ne(&self, other: &Module) -> bool { - match *other { - Module(ref __self_1_0) => match *self { - Module(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), - }, - } + } + #[inline] + fn ne(&self, other: &Module) -> bool { + match *other { + Module(ref __self_1_0) => match *self { + Module(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), + }, + } } } - impl ::core::marker::StructuralEq for Module where + impl ::core::marker::StructuralEq for Module where ExtendedBalance: From>> { } #[automatically_derived] #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Module + impl ::core::cmp::Eq for Module where ExtendedBalance: From>>, { @@ -3120,7 +3197,7 @@ pub mod two_phase { } } } - impl core::fmt::Debug for Module + impl core::fmt::Debug for Module where ExtendedBalance: From>>, T: core::fmt::Debug, @@ -3129,8 +3206,8 @@ pub mod two_phase { fmt.debug_tuple("Module").field(&self.0).finish() } } - impl - ::frame_support::traits::OnInitialize<::BlockNumber> for Module + impl + ::frame_support::traits::OnInitialize<::BlockNumber> for Module where ExtendedBalance: From>>, { @@ -3145,7 +3222,7 @@ pub mod two_phase { "frame_election_providers::two_phase", ::tracing::Level::TRACE, Some("frame/election-providers/src/two_phase/mod.rs"), - Some(464u32), + Some(469u32), Some("frame_election_providers::two_phase"), ::tracing_core::field::FieldSet::new( &[], @@ -3209,7 +3286,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 488u32, + 493u32, ), ); } @@ -3236,7 +3313,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 497u32, + 502u32, ), ); } @@ -3248,18 +3325,67 @@ pub mod two_phase { } } } - impl ::frame_support::traits::OnRuntimeUpgrade for Module where - ExtendedBalance: From>> + impl ::frame_support::traits::OnRuntimeUpgrade for Module + where + ExtendedBalance: From>>, { + fn on_runtime_upgrade() -> ::frame_support::dispatch::Weight { + let __within_span__ = { + use ::tracing::__macro_support::Callsite as _; + static CALLSITE: ::tracing::__macro_support::MacroCallsite = { + use ::tracing::__macro_support::MacroCallsite; + static META: ::tracing::Metadata<'static> = { + ::tracing_core::metadata::Metadata::new( + "on_runtime_upgrade", + "frame_election_providers::two_phase", + ::tracing::Level::TRACE, + Some("frame/election-providers/src/two_phase/mod.rs"), + Some(469u32), + Some("frame_election_providers::two_phase"), + ::tracing_core::field::FieldSet::new( + &[], + ::tracing_core::callsite::Identifier(&CALLSITE), + ), + ::tracing::metadata::Kind::SPAN, + ) + }; + MacroCallsite::new(&META) + }; + let mut interest = ::tracing::subscriber::Interest::never(); + if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL + && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() + && { + interest = CALLSITE.interest(); + !interest.is_never() + } && CALLSITE.is_enabled(interest) + { + let meta = CALLSITE.metadata(); + ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) + } else { + let span = CALLSITE.disabled_span(); + {}; + span + } + }; + let __tracing_guard__ = __within_span__.enter(); + frame_support::traits::PalletVersion { + major: 2u16, + minor: 0u8, + patch: 0u8, + } + .put_into_storage::<::PalletInfo, Self>(); + <::DbWeight as ::frame_support::traits::Get<_>>::get() + .writes(1) + } } - impl - ::frame_support::traits::OnFinalize<::BlockNumber> for Module + impl + ::frame_support::traits::OnFinalize<::BlockNumber> for Module where ExtendedBalance: From>>, { } - impl - ::frame_support::traits::OffchainWorker<::BlockNumber> for Module + impl + ::frame_support::traits::OffchainWorker<::BlockNumber> for Module where ExtendedBalance: From>>, { @@ -3285,7 +3411,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 514u32, + 519u32, ), ); } @@ -3293,24 +3419,24 @@ pub mod two_phase { } } } - impl Module + impl Module where ExtendedBalance: From>>, { /// Deposits an event using `frame_system::Module::deposit_event`. - fn deposit_event(event: impl Into<::Event>) { + fn deposit_event(event: impl Into<::Event>) { >::deposit_event(event.into()) } } #[cfg(feature = "std")] - impl ::frame_support::traits::IntegrityTest for Module where + impl ::frame_support::traits::IntegrityTest for Module where ExtendedBalance: From>> { } /// Can also be called using [`Call`]. /// /// [`Call`]: enum.Call.html - impl Module + impl Module where ExtendedBalance: From>>, { @@ -3318,8 +3444,8 @@ pub mod two_phase { /// /// The dispatch origin fo this call must be __signed__. /// - /// The solution potentially queued, based on the claimed score and processed at the end of - /// the signed phase. + /// The solution is potentially queued, based on the claimed score and processed at the end + /// of the signed phase. /// /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution /// might be rewarded, slashed, or get all or a part of the deposit back. @@ -3339,7 +3465,7 @@ pub mod two_phase { "frame_election_providers::two_phase", ::tracing::Level::TRACE, Some("frame/election-providers/src/two_phase/mod.rs"), - Some(464u32), + Some(469u32), Some("frame_election_providers::two_phase"), ::tracing_core::field::FieldSet::new( &[], @@ -3430,7 +3556,7 @@ pub mod two_phase { "frame_election_providers::two_phase", ::tracing::Level::TRACE, Some("frame/election-providers/src/two_phase/mod.rs"), - Some(464u32), + Some(469u32), Some("frame_election_providers::two_phase"), ::tracing_core::field::FieldSet::new( &[], @@ -3457,15 +3583,15 @@ pub mod two_phase { {}; span } - }; - let __tracing_guard__ = __within_span__.enter(); - { - ensure_none(origin)?; - let _ = Self::pre_dispatch_checks(&solution)?; - let ready = Self::feasibility_check(solution, ElectionCompute::Unsigned).expect( - "Invalid unsigned submission must produce invalid block and deprive \ + }; + let __tracing_guard__ = __within_span__.enter(); + { + ensure_none(origin)?; + let _ = Self::unsigned_pre_dispatch_checks(&solution)?; + let ready = Self::feasibility_check(solution, ElectionCompute::Unsigned).expect( + "Invalid unsigned submission must produce invalid block and deprive \ validator from their authoring reward.", - ); + ); >::put(ready); Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); } @@ -3475,7 +3601,7 @@ pub mod two_phase { /// Dispatchable calls. /// /// Each variant of this enum maps to a dispatchable function from the associated module. - pub enum Call + pub enum Call where ExtendedBalance: From>>, { @@ -3490,8 +3616,8 @@ pub mod two_phase { /// /// The dispatch origin fo this call must be __signed__. /// - /// The solution potentially queued, based on the claimed score and processed at the end of - /// the signed phase. + /// The solution is potentially queued, based on the claimed score and processed at the end + /// of the signed phase. /// /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution /// might be rewarded, slashed, or get all or a part of the deposit back. @@ -3517,7 +3643,7 @@ pub mod two_phase { #[allow(unknown_lints)] #[allow(rust_2018_idioms)] extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Call + impl _parity_scale_codec::Encode for Call where ExtendedBalance: From>>, RawSolution>: _parity_scale_codec::Encode, @@ -3525,21 +3651,24 @@ pub mod two_phase { RawSolution>: _parity_scale_codec::Encode, RawSolution>: _parity_scale_codec::Encode, { - fn encode_to(&self, dest: &mut EncOut) { + fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( + &self, + __codec_dest_edqy: &mut __CodecOutputEdqy, + ) { match *self { - Call::submit(ref aa) => { - dest.push_byte(0usize as u8); - dest.push(aa); - } - Call::submit_unsigned(ref aa) => { - dest.push_byte(1usize as u8); - dest.push(aa); - } - _ => (), - } + Call::submit(ref aa) => { + __codec_dest_edqy.push_byte(0usize as u8); + __codec_dest_edqy.push(aa); + } + Call::submit_unsigned(ref aa) => { + __codec_dest_edqy.push_byte(1usize as u8); + __codec_dest_edqy.push(aa); + } + _ => (), + } } } - impl _parity_scale_codec::EncodeLike for Call + impl _parity_scale_codec::EncodeLike for Call where ExtendedBalance: From>>, RawSolution>: _parity_scale_codec::Encode, @@ -3550,48 +3679,54 @@ pub mod two_phase { } }; const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(Call::submit({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field Call :: submit.0".into()), - Ok(a) => a, - } - })), - x if x == 1usize as u8 => Ok(Call::submit_unsigned({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field Call :: submit_unsigned.0".into()) - } - Ok(a) => a, - } - })), - x => Err("No such variant in enum Call".into()), - } - } - } - }; - impl ::frame_support::dispatch::GetDispatchInfo for Call - where - ExtendedBalance: From>>, - { - fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { - match *self { + #[allow(unknown_lints)] + #[allow(rust_2018_idioms)] + extern crate codec as _parity_scale_codec; + impl _parity_scale_codec::Decode for Call + where + ExtendedBalance: From>>, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + RawSolution>: _parity_scale_codec::Decode, + { + fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( + __codec_input_edqy: &mut __CodecInputEdqy, + ) -> core::result::Result { + match __codec_input_edqy.read_byte()? { + __codec_x_edqy if __codec_x_edqy == 0usize as u8 => Ok(Call::submit({ + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => return Err("Error decoding field Call :: submit.0".into()), + Ok(__codec_res_edqy) => __codec_res_edqy, + } + })), + __codec_x_edqy if __codec_x_edqy == 1usize as u8 => { + Ok(Call::submit_unsigned({ + let __codec_res_edqy = + _parity_scale_codec::Decode::decode(__codec_input_edqy); + match __codec_res_edqy { + Err(_) => { + return Err( + "Error decoding field Call :: submit_unsigned.0".into() + ) + } + Ok(__codec_res_edqy) => __codec_res_edqy, + } + })) + } + _ => Err("No such variant in enum Call".into()), + } + } + } + }; + impl ::frame_support::dispatch::GetDispatchInfo for Call + where + ExtendedBalance: From>>, + { + fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { + match *self { Call::submit(ref solution) => { let base_weight = T::WeightInfo::submit(); let weight = ::frame_support::dispatch::GetCallName for Call - where - ExtendedBalance: From>>, - { - fn get_call_name(&self) -> &'static str { - match *self { + } + } + impl ::frame_support::dispatch::GetCallName for Call + where + ExtendedBalance: From>>, + { + fn get_call_name(&self) -> &'static str { + match *self { Call::submit(ref solution) => { let _ = (solution); "submit" @@ -3668,29 +3803,63 @@ pub mod two_phase { )) } } - } - fn get_call_names() -> &'static [&'static str] { - &["submit", "submit_unsigned"] - } - } - impl ::frame_support::dispatch::Clone for Call - where - ExtendedBalance: From>>, - { - fn clone(&self) -> Self { - match *self { - Call::submit(ref solution) => Call::submit((*solution).clone()), - Call::submit_unsigned(ref solution) => Call::submit_unsigned((*solution).clone()), - _ => ::std::rt::begin_panic("internal error: entered unreachable code"), - } - } - } - impl ::frame_support::dispatch::PartialEq for Call - where - ExtendedBalance: From>>, - { - fn eq(&self, _other: &Self) -> bool { - match *self { + } + fn get_call_names() -> &'static [&'static str] { + &["submit", "submit_unsigned"] + } + } + pub use ::frame_support::traits::GetPalletVersion as _; + impl ::frame_support::traits::GetPalletVersion for Module + where + ExtendedBalance: From>>, + { + fn current_version() -> ::frame_support::traits::PalletVersion { + frame_support::traits::PalletVersion { + major: 2u16, + minor: 0u8, + patch: 0u8, + } + } + fn storage_version() -> Option<::frame_support::traits::PalletVersion> { + let key = ::frame_support::traits::PalletVersion::storage_key::< + ::PalletInfo, + Self, + >() + .expect("Every active pallet has a name in the runtime; qed"); + ::frame_support::storage::unhashed::get(&key) + } + } + impl ::frame_support::traits::OnGenesis for Module + where + ExtendedBalance: From>>, + { + fn on_genesis() { + frame_support::traits::PalletVersion { + major: 2u16, + minor: 0u8, + patch: 0u8, + } + .put_into_storage::<::PalletInfo, Self>(); + } + } + impl ::frame_support::dispatch::Clone for Call + where + ExtendedBalance: From>>, + { + fn clone(&self) -> Self { + match *self { + Call::submit(ref solution) => Call::submit((*solution).clone()), + Call::submit_unsigned(ref solution) => Call::submit_unsigned((*solution).clone()), + _ => ::std::rt::begin_panic("internal error: entered unreachable code"), + } + } + } + impl ::frame_support::dispatch::PartialEq for Call + where + ExtendedBalance: From>>, + { + fn eq(&self, _other: &Self) -> bool { + match *self { Call::submit(ref solution) => { let self_params = (solution,); if let Call::submit(ref solution) = *_other { @@ -3719,22 +3888,21 @@ pub mod two_phase { } _ => ::std::rt::begin_panic("internal error: entered unreachable code"), } - } - } - impl ::frame_support::dispatch::Eq for Call where - ExtendedBalance: From>> - { - } - impl ::frame_support::dispatch::fmt::Debug for Call - where - ExtendedBalance: From>>, - { - fn fmt( - &self, - _f: &mut ::frame_support::dispatch::fmt::Formatter, - ) -> ::frame_support::dispatch::result::Result<(), ::frame_support::dispatch::fmt::Error> - { - match *self { + } + } + impl ::frame_support::dispatch::Eq for Call where + ExtendedBalance: From>> + { + } + impl ::frame_support::dispatch::fmt::Debug for Call + where + ExtendedBalance: From>>, + { + fn fmt( + &self, + _f: &mut ::frame_support::dispatch::fmt::Formatter, + ) -> ::frame_support::dispatch::result::Result<(), ::frame_support::dispatch::fmt::Error> { + match *self { Call::submit(ref solution) => _f.write_fmt(::core::fmt::Arguments::new_v1( &["", ""], &match (&"submit", &(solution.clone(),)) { @@ -3757,18 +3925,18 @@ pub mod two_phase { } _ => ::std::rt::begin_panic("internal error: entered unreachable code"), } - } - } - impl ::frame_support::traits::UnfilteredDispatchable for Call - where - ExtendedBalance: From>>, - { - type Origin = T::Origin; - fn dispatch_bypass_filter( - self, - _origin: Self::Origin, - ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { - match self { + } + } + impl ::frame_support::traits::UnfilteredDispatchable for Call + where + ExtendedBalance: From>>, + { + type Origin = T::Origin; + fn dispatch_bypass_filter( + self, + _origin: Self::Origin, + ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { + match self { Call::submit(solution) => >::submit(_origin, solution) .map(Into::into) .map_err(Into::into), @@ -3787,15 +3955,15 @@ pub mod two_phase { )) } } - } - } - impl ::frame_support::dispatch::Callable for Module + } + } + impl ::frame_support::dispatch::Callable for Module where ExtendedBalance: From>>, { type Call = Call; } - impl Module + impl Module where ExtendedBalance: From>>, { @@ -3818,8 +3986,8 @@ pub mod two_phase { r"", r" The dispatch origin fo this call must be __signed__.", r"", - r" The solution potentially queued, based on the claimed score and processed at the end of", - r" the signed phase.", + r" The solution is potentially queued, based on the claimed score and processed at the end", + r" of the signed phase.", r"", r" A deposit is reserved and recorded for the solution. Based on the outcome, the solution", r" might be rewarded, slashed, or get all or a part of the deposit back.", @@ -3855,7 +4023,7 @@ pub mod two_phase { ] } } - impl Module + impl Module where ExtendedBalance: From>>, { @@ -3866,7 +4034,7 @@ pub mod two_phase { &[] } } - impl ::frame_support::dispatch::ModuleErrorMetadata for Module + impl ::frame_support::dispatch::ModuleErrorMetadata for Module where ExtendedBalance: From>>, { @@ -3874,7 +4042,7 @@ pub mod two_phase { as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() } } - impl Module + impl Module where ExtendedBalance: From>>, { @@ -3906,18 +4074,18 @@ pub mod two_phase { Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; let voter_at = |i: crate::two_phase::CompactVoterIndexOf| -> Option { as crate::TryInto>::try_into(i) - .ok() - .and_then(|i| snapshot_voters.get(i).map(|(x, _, _)| x).cloned()) - }; - let target_at = |i: crate::two_phase::CompactTargetIndexOf| -> Option { - as crate::TryInto>::try_into(i) - .ok() - .and_then(|i| snapshot_targets.get(i).cloned()) - }; - let winners = winners - .into_iter() - .map(|i| target_at(i).ok_or(FeasibilityError::InvalidWinner)) - .collect::, FeasibilityError>>()?; + .ok() + .and_then(|i| snapshot_voters.get(i).map(|(x, _, _)| x).cloned()) + }; + let target_at = |i: crate::two_phase::CompactTargetIndexOf| -> Option { + as crate::TryInto>::try_into(i) + .ok() + .and_then(|i| snapshot_targets.get(i).cloned()) + }; + let winners = winners + .into_iter() + .map(|i| target_at(i).ok_or(FeasibilityError::InvalidWinner)) + .collect::, FeasibilityError>>()?; let assignments = compact .into_assignment(voter_at, target_at) .map_err::(Into::into)?; @@ -3952,156 +4120,6 @@ pub mod two_phase { let supports = sp_npos_elections::to_supports(&winners, &staked_assignments) .map_err::(Into::into)?; let known_score = supports.evaluate(); - ( - match known_score { - tmp => { - { - ::std::io::_eprint(::core::fmt::Arguments::new_v1_formatted( - &["[", ":", "] ", " = ", "\n"], - &match ( - &"frame/election-providers/src/two_phase/mod.rs", - &674u32, - &"known_score", - &&tmp, - ) { - (arg0, arg1, arg2, arg3) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg2, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new(arg3, ::core::fmt::Debug::fmt), - ], - }, - &[ - ::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 1usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 2usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 3usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ], - )); - }; - tmp - } - }, - match score { - tmp => { - { - ::std::io::_eprint(::core::fmt::Arguments::new_v1_formatted( - &["[", ":", "] ", " = ", "\n"], - &match ( - &"frame/election-providers/src/two_phase/mod.rs", - &674u32, - &"score", - &&tmp, - ) { - (arg0, arg1, arg2, arg3) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg2, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new(arg3, ::core::fmt::Debug::fmt), - ], - }, - &[ - ::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 1usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 2usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 3usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ], - )); - }; - tmp - } - }, - ); { if !(known_score == score) { { @@ -4117,9 +4135,11 @@ pub mod two_phase { } /// On-chain fallback of election. fn onchain_fallback() -> Result, Error> { - let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + let RoundSnapshot { + desired_targets, + voters, + targets, + } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; >::elect::( desired_targets, targets, @@ -4128,7 +4148,7 @@ pub mod two_phase { .map_err(Into::into) } } - impl ElectionProvider for Module + impl ElectionProvider for Module where ExtendedBalance: From>>, { @@ -4155,8 +4175,7 @@ pub mod two_phase { ) .map(|(supports, compute)| { >::put(Phase::Off); - >::kill(); - >::kill(); + >::kill(); Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); { let lvl = ::log::Level::Info; @@ -4176,7 +4195,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 731u32, + 733u32, ), ); } @@ -4203,7 +4222,7 @@ pub mod two_phase { crate::LOG_TARGET, "frame_election_providers::two_phase", "frame/election-providers/src/two_phase/mod.rs", - 736u32, + 738u32, ), ); } diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index d69bea6766e12..86fd627cd4db7 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -24,78 +24,103 @@ pub use frame_benchmarking::{account, benchmarks, whitelist_account, whitelisted use frame_support::assert_ok; use rand::{seq::SliceRandom, thread_rng}; use sp_npos_elections::{ExtendedBalance, VoteWeight}; -use sp_runtime::{InnerOf, PerU16}; +use sp_runtime::InnerOf; use std::convert::TryInto; const SEED: u32 = 0; -// TODO: the entire snapshot can probably live in a single place.. we most often Read and write it -// at the same time. - -/// Generate mock on-chain snapshots. +/// Creates a **valid** solution with exactly the given size. /// -/// This emulates the start of signed phase, where snapshots are received from an upstream crate. -fn mock_snapshot( +/// The snapshot is also created internally. +/// +/// The snapshot size must be bigger, otherwise this will panic. +fn solution_with_size( witness: WitnessData, -) -> ( - Vec, - Vec<(T::AccountId, VoteWeight, Vec)>, -) + active_voters_count: u32, + winners_count: u32, +) -> RawSolution> where ExtendedBalance: From>>, + > as std::convert::TryFrom>::Error: std::fmt::Debug, { + assert!(witness.targets >= winners_count, "must have enough targets"); + assert!( + witness.voters >= active_voters_count, + "must have enough voters" + ); + let stake: u64 = 1000_000; // first generates random targets. let targets: Vec = (0..witness.targets) .map(|i| account("Targets", i, SEED)) .collect(); - // generate voters, each voting for a random subset of the targets. - let mut voters = (0..(witness.voters - witness.targets)) + let mut rng = thread_rng(); + // decide who are the winners. + let winners = targets + .as_slice() + .choose_multiple(&mut rng, winners_count as usize) + .cloned() + .collect::>(); + + // generate first active voters who must vote for a subset of winners. + // TODO: this could lead to an underestimate, the active voters should only vote for winners to + // maximize all the iterations. + let active_voters = (0..active_voters_count) .map(|i| { - let mut rng = thread_rng(); - let to_vote = rand::random::() % >::LIMIT + 1; - let votes = targets.as_slice().choose_multiple(&mut rng, to_vote).cloned().collect::>(); + // chose a random number of votes to give to the winners, and whatever is left is given + // to everyone. + let votes_to_winners = rand::random::() % >::LIMIT + 1; + let votes_to_everyone = >::LIMIT - votes_to_winners; + + let winner_votes = winners + .as_slice() + .choose_multiple(&mut rng, votes_to_winners) + .cloned(); + let rest_votes = targets + .as_slice() + .choose_multiple(&mut rng, votes_to_everyone as usize) + .cloned(); + + let votes = winner_votes.chain(rest_votes).collect::>(); let voter = account::("Voter", i, SEED); (voter, stake, votes) }) .collect::>(); - // targets should have self vote. This is very helpful, because it ensure that by doing the trim, - // we almost never reduce the number of unique targets. For this cause, we also make the self - // vote heavier, to ensure that trimming only removes a voter here and there, not a target. - voters.extend(targets.iter().map(|t| (t.clone(), stake, vec![t.clone()]))); + // rest of the voters. They can only vote for non-winners. + let non_winners = targets + .iter() + .filter(|t| !winners.contains(t)) + .cloned() + .collect::>(); + let rest_voters = (active_voters_count..witness.voters) + .map(|i| { + let votes = (&non_winners) + .choose_multiple(&mut rng, >::LIMIT) + .cloned() + .collect::>(); + let voter = account::("Voter", i, SEED); + (voter, stake, votes) + }) + .collect::>(); - (targets, voters) -} + dbg!(active_voters.len(), rest_voters.len(), winners.len()); + // active_voters.extend(rest_voters); + let mut all_voters = active_voters.clone(); + all_voters.extend(rest_voters); -fn put_mock_snapshot(witness: WitnessData, desired_targets: u32) -where - ExtendedBalance: From>>, -{ - let (targets, voters) = mock_snapshot::(witness); - >::put(targets); - >::put(voters); - DesiredTargets::put(desired_targets); -} + assert_eq!(active_voters.len() as u32, active_voters_count); + assert_eq!(all_voters.len() as u32, witness.voters); + assert_eq!(winners.len() as u32, winners_count); -/// Creates a **valid** solution with exactly the given size. -/// -/// The snapshot size must be bigger, otherwise this will panic. -fn solution_with_size(active_voters: u32, winners_count: u32) -> RawSolution> -where - ExtendedBalance: From>>, - > as std::convert::TryFrom>::Error: std::fmt::Debug, -{ - let voters = >::snapshot_voters().unwrap(); - let targets = >::snapshot_targets().unwrap(); + let voters = active_voters; - // else we cannot support this, self vote is a must. - assert!(active_voters >= winners_count); - // else we won't have enough voters. - assert!(voters.len() >= active_voters as usize); - // else we won't have enough winners - assert!(targets.len() >= winners_count as usize); + >::put(RoundSnapshot { + desired_targets: winners_count, + voters: all_voters, + targets: targets.clone(), + }); let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); let voter_at = crate::voter_at_fn!(voters, T::AccountId, T); @@ -103,66 +128,37 @@ where let target_index = crate::target_index_fn!(targets, T::AccountId, T); let stake_of = crate::stake_of_fn!(voters, T::AccountId); - // First chose random winners. - let mut rng = rand::thread_rng(); - let winners = targets - .as_slice() - .choose_multiple(&mut rng, winners_count as usize) - .cloned() - .collect::>(); - - let mut assignments = winners + let assignments = voters .iter() - .map(|w| Assignment { - who: w.clone(), - distribution: vec![(w.clone(), >::one())], - }) - .collect::>(); - - // all external voters who are not self vote. - let mut voters_pool = voters - .iter() - .filter(|(x, _, z)| *x != z[0]) - .cloned() - .collect::>(); - - // add from `voters_pool` to `assignments` until we have enough. - while assignments.len() < active_voters as usize { - // pop one of the voters. - let (who, _, votes) = voters_pool.remove(rand::random::() % voters_pool.len()); - // see if it votes for any of the winners. - let winner_intersection = votes - .iter() - .filter(|v| winners.contains(v)) - .cloned() - .collect::>(); - - // if any, add assignment to all of them. - if winner_intersection.len() > 0 { - assignments.push(Assignment { - who, - distribution: winner_intersection + .map(|(voter, _stake, votes)| { + let percent_per_edge: InnerOf> = + (100 / votes.len()).try_into().unwrap(); + Assignment { + who: voter.clone(), + distribution: votes .iter() - .map(|w| { - let percent: InnerOf> = (100 / winner_intersection.len()).try_into().unwrap(); - ( - w.clone(), - >::from_percent(percent), - ) - }) + .map(|t| (t.clone(), >::from_percent(percent_per_edge))) .collect::>(), - }) - } - } + } + }) + .collect::>(); - let compact = >::from_assignment(assignments, &voter_index, &target_index).unwrap(); - let score = compact.clone().score(winners, stake_of, voter_at, target_at).unwrap(); + let compact = + >::from_assignment(assignments, &voter_index, &target_index).unwrap(); + let score = compact + .clone() + .score(&winners, stake_of, voter_at, target_at) + .unwrap(); RawSolution { compact, score } } benchmarks! { - where_clause { where ExtendedBalance: From>>, } + where_clause { + where ExtendedBalance: From>>, + // TODO: do I really need this? + > as std::convert::TryFrom>::Error: std::fmt::Debug, + } _{} submit_signed {}: {} verify {} @@ -172,42 +168,24 @@ benchmarks! { // This is checking a valid solution. The worse case is indeed a valid solution. feasibility_check { - // number of votes in snapshot. + // number of voters in snapshot. let v in 200 .. 300; // number of targets in snapshot. - let t in 50 .. 80; - // number of assignments, i.e. compact.len(). This means the active nominators, thus must be - // a subset of `v` component. - let a in 20 .. 80; + let t in 80 .. 140; + // number of assignments, i.e. compact.voters_count(). This means the active nominators, + // thus must be a subset of `v` component. + let a in 80 .. 140; // number of desired targets. Must be a subset of `t` component. - let d in 20 .. 40; + let d in 30 .. 60; println!("running v {}, t {}, a {}, d {}", v, t, a, d); let witness = WitnessData { voters: v, targets: t }; - put_mock_snapshot::(witness, d); - - let voters = >::snapshot_voters().unwrap(); - let targets = >::snapshot_targets().unwrap(); - - let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); - let voter_at = crate::voter_at_fn!(voters, T::AccountId, T); - let target_at = crate::target_at_fn!(targets, T::AccountId, T); - let stake_of = crate::stake_of_fn!(voters, T::AccountId); - - // the score at this point is not usable -- It might change when we resize the compact. - let RawSolution { compact, score: _ } = >::mine_solution(0).unwrap(); - let compact = >::trim_compact(a, compact, voter_index).unwrap(); + let raw_solution = solution_with_size::(witness, a, d); - assert_eq!(compact.len() as u32, a); - assert_eq!(compact.unique_targets().len() as u32, d); + assert_eq!(raw_solution.compact.voters_count() as u32, a); + assert_eq!(raw_solution.compact.unique_targets().len() as u32, d); - // re-calc score. - let winners = compact.unique_targets().iter().map(|i| target_at(*i).unwrap()).collect::>(); - let score = compact - .clone() - .score(&winners, stake_of, voter_at, target_at).unwrap(); - let raw_solution = RawSolution { compact, score }; let compute = ElectionCompute::Unsigned; }: { assert_ok!(>::feasibility_check(raw_solution, compute)); diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 50e229e4e527c..3436f8b21d5b3 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -1,7 +1,6 @@ use super::*; use frame_support::{parameter_types, traits::OnInitialize}; use parking_lot::RwLock; -use rand::seq::SliceRandom; use sp_core::{ offchain::{ testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, @@ -12,7 +11,7 @@ use sp_core::{ use sp_election_providers::ElectionDataProvider; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, to_without_backing, - Assignment, CompactSolution, ElectionResult, EvaluateSupport, + CompactSolution, ElectionResult, EvaluateSupport, }; use sp_runtime::{ testing::Header, @@ -54,9 +53,12 @@ pub fn balances(who: &AccountId) -> (Balance, Balance) { /// /// This is a good example of what an offchain miner would do. pub fn raw_solution() -> RawSolution> { - let voters = TwoPhase::snapshot_voters().unwrap(); - let targets = TwoPhase::snapshot_targets().unwrap(); - let desired = TwoPhase::desired_targets() as usize; + let RoundSnapshot { + voters, + targets, + desired_targets, + } = TwoPhase::snapshot().unwrap(); + let desired = desired_targets as usize; // closures let voter_index = crate::voter_index_fn!(voters, AccountId, Runtime); diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 73793ba03c280..b32ed977e29ab 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -17,7 +17,7 @@ //! # Two phase election provider pallet. //! -//! As the name suggests, this election provider has two distinct phases (see [`Phase`]), signed and +//! As the name suggests, this election-provider has two distinct phases (see [`Phase`]), signed and //! unsigned. //! //! ## Phases @@ -41,13 +41,13 @@ //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution //! on-chain for a number of blocks. A maximum of [`Config::MaxSignedSubmissions`] solutions are -//! stored. The queue is always sorted based on score (worse -> best). +//! stored. The queue is always sorted based on score (worse to best). //! //! Upon arrival of a new solution: //! -//! 1. If the queue is not full, it is stored. +//! 1. If the queue is not full, it is stored in the appropriate index. //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the -//! worse solution is discarded (TODO: what to do with the bond?) and the new solution is stored +//! worse solution is discarded (TODO: must return the bond here) and the new solution is stored //! in the correct index. //! 3. If the queue is full and the solution is not an improvement compared to any of the queued //! ones, it is instantly rejected and no additional bond is reserved. @@ -58,7 +58,7 @@ //! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed //! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure //! the score claimed by this score was correct, among other checks. At each step, if the current -//! best solution is passes the feasibility check, it is considered to be the best one. The sender +//! best solution passes the feasibility check, it is considered to be the best one. The sender //! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without //! being checked. //! @@ -127,8 +127,9 @@ use sp_runtime::{ }; use sp_std::prelude::*; +// TODO: make this only test. #[cfg(any(feature = "runtime-benchmarks", test))] -pub mod benchmarking; +mod benchmarking; #[cfg(test)] mod mock; #[macro_use] @@ -166,7 +167,8 @@ pub enum Phase { Off, /// Signed phase is open. Signed, - /// Unsigned phase is open. + /// Unsigned phase. First element is whether it is open or not, second the starting block + /// number. Unsigned((bool, Bn)), } @@ -222,8 +224,10 @@ impl Default for ElectionCompute { /// A raw, unchecked solution. /// +/// This is what will get submitted to the chain. +/// /// Such a solution should never become effective in anyway before being checked by the -/// [`Module::feasibility_check`] +/// [`Module::feasibility_check`]. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] pub struct RawSolution { /// Compact election edges. @@ -247,11 +251,13 @@ pub struct SignedSubmission { solution: RawSolution, } -/// A checked and parsed solution, ready to be enacted. +/// A checked solution, ready to be enacted. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] pub struct ReadySolution { - /// The final supports of the solution. This is target-major vector, storing each winners, total - /// backing, and each individual backer. + /// The final supports of the solution. + /// + /// This is target-major vector, storing each winners, total backing, and each individual + /// backer. supports: Supports, /// The score of the solution. /// @@ -278,7 +284,24 @@ pub struct WitnessData { targets: u32, } -/// The crate errors. Note that this is different from the [`PalletError`]. +/// A snapshot of all the data that is needed for en entire round. They are provided by +/// [`ElectionDataProvider`] at the beginning of the signed phase and are kept around until the +/// round is finished. +/// +/// These are stored together because they are often times accessed together. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] +pub struct RoundSnapshot { + /// All of the voters. + pub voters: Vec<(A, VoteWeight, Vec)>, + /// All of the targets. + pub targets: Vec, + /// Desired number of winners to be elected for this round. + pub desired_targets: u32, +} + +/// The crate errors. +/// +/// Note that this is different from the [`PalletError`]. #[derive(RuntimeDebug, Eq, PartialEq)] pub enum Error { /// A feasibility error. @@ -307,6 +330,12 @@ impl From for Error { } } +impl From for Error { + fn from(e: FeasibilityError) -> Self { + Error::Feasibility(e) + } +} + /// Errors that can happen in the feasibility check. #[derive(RuntimeDebug, Eq, PartialEq)] pub enum FeasibilityError { @@ -317,7 +346,7 @@ pub enum FeasibilityError { /// This must be an internal error of the chain. SnapshotUnavailable, /// Internal error from the election crate. - NposElectionError(sp_npos_elections::Error), + NposElection(sp_npos_elections::Error), /// A vote is invalid. InvalidVote, /// A voter is invalid. @@ -330,11 +359,10 @@ pub enum FeasibilityError { impl From for FeasibilityError { fn from(e: sp_npos_elections::Error) -> Self { - FeasibilityError::NposElectionError(e) + FeasibilityError::NposElection(e) } } -/// The weights for this pallet. pub trait WeightInfo { fn feasibility_check() -> Weight; fn submit() -> Weight; @@ -374,6 +402,7 @@ where type SignedRewardBase: Get>; type SignedRewardFactor: Get; type SignedRewardMax: Get>>; + type SignedDepositBase: Get>; type SignedDepositByte: Get>; type SignedDepositWeight: Get>; @@ -381,7 +410,10 @@ where /// The minimum amount of improvement to the solution score that defines a solution as "better". type SolutionImprovementThreshold: Get; + /// Maximum number of iteration of balancing that will be executed in the embedded miner of the + /// pallet. type UnsignedMaxIterations: Get; + /// The priority of the unsigned transaction submitted in the unsigned-phase type UnsignedPriority: Get; /// Handler for the slashed deposits. @@ -398,7 +430,7 @@ where decl_storage! { trait Store for Module as TwoPhaseElectionProvider where ExtendedBalance: From>> { - /// Internal counter ofr the number of rounds. + /// Internal counter for the number of rounds. /// /// This is useful for de-duplication of transactions submitted to the pool, and general /// diagnostics of the module. @@ -414,20 +446,10 @@ decl_storage! { /// Current best solution, signed or unsigned. pub QueuedSolution get(fn queued_solution): Option>; - /// Snapshot of all Voters. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub SnapshotTargets get(fn snapshot_targets): Option>; - - /// Snapshot of all targets. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub SnapshotVoters get(fn snapshot_voters): Option)>>; - - /// Desired number of targets to elect. + /// Snapshot data of the round. /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub DesiredTargets get(fn desired_targets): u32; + pub Snapshot get(fn snapshot): Option>; } } @@ -520,8 +542,8 @@ decl_module! { /// /// The dispatch origin fo this call must be __signed__. /// - /// The solution potentially queued, based on the claimed score and processed at the end of - /// the signed phase. + /// The solution is potentially queued, based on the claimed score and processed at the end + /// of the signed phase. /// /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution /// might be rewarded, slashed, or get all or a part of the deposit back. @@ -539,6 +561,7 @@ decl_module! { let index = maybe_index.expect("Option checked to be `Some`; qed."); // collect deposit. Thereafter, the function cannot fail. + // TODO: ensure this index is correct. let deposit = signed_submissions[index].deposit; T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; @@ -571,7 +594,7 @@ decl_module! { // check phase and score. // TODO: since we do this in pre-dispatch, we can just ignore it // here. - let _ = Self::pre_dispatch_checks(&solution)?; + let _ = Self::unsigned_pre_dispatch_checks(&solution)?; let ready = Self::feasibility_check(solution, ElectionCompute::Unsigned) @@ -611,18 +634,23 @@ where // TODO: dupe in compact. let winners = compact.unique_targets(); + // read the entire snapshot. + // TODO: maybe we can store desired_targets separately if it + // happens to make a difference to the weight. For now I think it will not and we always + // want to charge the full weight of this call anyhow. + let RoundSnapshot { + voters: snapshot_voters, + targets: snapshot_targets, + desired_targets, + } = Self::snapshot().ok_or(FeasibilityError::SnapshotUnavailable)?; + // Ensure that we have received enough winners. ensure!( - winners.len() as u32 == Self::desired_targets(), + winners.len() as u32 == desired_targets, FeasibilityError::WrongWinnerCount ); // ----- Start building. First, we need some closures. - let snapshot_voters = - Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; - let snapshot_targets = - Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - let voter_at = crate::voter_at_fn!(snapshot_voters, T::AccountId, T); let target_at = crate::target_at_fn!(snapshot_targets, T::AccountId, T); @@ -644,8 +672,8 @@ where .map(|Assignment { who, distribution }| { snapshot_voters.iter().find(|(v, _, _)| v == who).map_or( Err(FeasibilityError::InvalidVoter), - |(_, _, t)| { - if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) + |(_voter, _stake, targets)| { + if distribution.iter().map(|(d, _)| d).all(|d| targets.contains(d)) && T::ElectionDataProvider::feasibility_check_assignment::< CompactAccuracyOf, >(who, distribution) @@ -683,11 +711,13 @@ where /// On-chain fallback of election. fn onchain_fallback() -> Result, Error> { - let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - >::elect::( + let RoundSnapshot { desired_targets, + voters, + targets, + } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; + >::elect::( + desired_targets as usize, targets, voters, ) @@ -723,8 +753,7 @@ where // reset phase. >::put(Phase::Off); // clear snapshots. - >::kill(); - >::kill(); + >::kill(); Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); log!(info, "Finalized election round with compute {:?}.", compute); @@ -761,40 +790,40 @@ mod tests { roll_to(4); assert_eq!(TwoPhase::current_phase(), Phase::Off); - assert!(TwoPhase::snapshot_voters().is_none()); + assert!(TwoPhase::snapshot().is_none()); assert_eq!(TwoPhase::round(), 0); roll_to(5); assert_eq!(TwoPhase::current_phase(), Phase::Signed); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); assert_eq!(TwoPhase::round(), 1); roll_to(14); assert_eq!(TwoPhase::current_phase(), Phase::Signed); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); assert_eq!(TwoPhase::round(), 1); roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); roll_to(19); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); roll_to(20); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); // we close when upstream tells us to elect. roll_to(21); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); - assert!(TwoPhase::snapshot_voters().is_some()); + assert!(TwoPhase::snapshot().is_some()); TwoPhase::elect::(2, Default::default(), Default::default()) .unwrap(); assert_eq!(TwoPhase::current_phase(), Phase::Off); - assert!(TwoPhase::snapshot_voters().is_none()); + assert!(TwoPhase::snapshot().is_none()); assert_eq!(TwoPhase::round(), 1); }) } diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index cbe8ea12d4c41..4f5bedcb1fd19 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -38,9 +38,11 @@ where let voters = T::ElectionDataProvider::voters(); let desired_targets = T::ElectionDataProvider::desired_targets(); - >::put(targets); - >::put(voters); - DesiredTargets::put(desired_targets); + >::put(RoundSnapshot { + voters, + targets, + desired_targets, + }); } /// Finish the singed phase. Process the signed submissions from best to worse until a valid one diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 29cd797bd6c38..f72c1694096e4 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -46,13 +46,20 @@ where { /// Min a new npos solution. pub fn mine_solution(iters: usize) -> Result>, Error> { - let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - - seq_phragmen::<_, CompactAccuracyOf>(desired_targets, targets, voters, Some((iters, 0))) - .map_err(Into::into) - .and_then(Self::prepare_election_result) + let RoundSnapshot { + desired_targets, + voters, + targets, + } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; + + seq_phragmen::<_, CompactAccuracyOf>( + desired_targets as usize, + targets, + voters, + Some((iters, 0)), + ) + .map_err(Into::into) + .and_then(Self::prepare_election_result) } /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which @@ -62,9 +69,10 @@ where pub fn prepare_election_result( election_result: ElectionResult>, ) -> Result>, Error> { - // storage items. - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; + // storage items. Note: we have already read this from storage, they must be in cache. + let RoundSnapshot { + voters, targets, .. + } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; // closures. let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); @@ -91,7 +99,7 @@ where // TODO let maximum_allowed_voters = Self::maximum_compact_len::(0, Default::default(), 0); - let compact = Self::trim_compact(compact.len() as u32, compact, &voter_index)?; + let compact = Self::trim_compact(compact.voters_count() as u32, compact, &voter_index)?; // re-calc score. let winners = sp_npos_elections::to_without_backing(winners); @@ -142,10 +150,10 @@ where where for<'r> FN: Fn(&'r T::AccountId) -> Option>, { - match compact.len().checked_sub(maximum_allowed_voters as usize) { + match compact.voters_count().checked_sub(maximum_allowed_voters as usize) { Some(to_remove) if to_remove > 0 => { // grab all voters and sort them by least stake. - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; + let RoundSnapshot { voters, .. } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; let mut voters_sorted = voters .into_iter() .map(|(who, stake, _)| (who.clone(), stake)) @@ -300,7 +308,9 @@ where .map_err(|_| Error::PoolSubmissionFailed) } - pub(crate) fn pre_dispatch_checks(solution: &RawSolution>) -> DispatchResult { + pub(crate) fn unsigned_pre_dispatch_checks( + solution: &RawSolution>, + ) -> DispatchResult { // ensure solution is timely. Don't panic yet. This is a cheap check. ensure!( Self::current_phase().is_unsigned_open(), @@ -337,7 +347,7 @@ where } } - if let Err(_why) = Self::pre_dispatch_checks(solution) { + if let Err(_why) = Self::unsigned_pre_dispatch_checks(solution) { return InvalidTransaction::Custom(99).into(); // TODO } @@ -359,7 +369,8 @@ where fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { if let Call::submit_unsigned(solution) = call { - Self::pre_dispatch_checks(solution).map_err(|_| InvalidTransaction::Custom(99).into()) + Self::unsigned_pre_dispatch_checks(solution) + .map_err(|_| InvalidTransaction::Custom(99).into()) } else { Err(InvalidTransaction::Call.into()) } @@ -662,9 +673,8 @@ mod tests { assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); // ensure we have snapshots in place. - assert!(TwoPhase::snapshot_voters().is_some()); - assert!(TwoPhase::snapshot_targets().is_some()); - assert_eq!(TwoPhase::desired_targets(), 2); + assert!(TwoPhase::snapshot().is_some()); + assert_eq!(TwoPhase::snapshot().unwrap().desired_targets, 2); // mine seq_phragmen solution with 2 iters. let solution = TwoPhase::mine_solution(2).unwrap(); @@ -692,7 +702,7 @@ mod tests { roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); - assert_eq!(TwoPhase::desired_targets(), 1); + assert_eq!(TwoPhase::snapshot().unwrap().desired_targets, 1); // an initial solution let result = ElectionResult { diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index 035a704ba3009..1fe3e749a0423 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -67,7 +67,12 @@ pub trait PerThing: let b = Self::ACCURACY; // if Self::ACCURACY % 100 > 0 then we need the correction for accuracy let c = rational_mul_correction::(b, a, 100.into(), Rounding::Nearest); - Self::from_parts(a / 100.into() * b + c) + // TODO: this will fail with + // [primitives/arithmetic/src/per_things.rs:70] a = 100 + // [primitives/arithmetic/src/per_things.rs:70] b = 65535 + // [primitives/arithmetic/src/per_things.rs:70] c = 35 + let base: Self::Inner = 100.into(); + Self::from_parts(a / base.saturating_mul(b).saturating_add(c)) } /// Return the product of multiplication of this value by itself. @@ -334,7 +339,7 @@ macro_rules! implement_per_thing { &self.0 } fn decode_from(x: Self::As) -> Self { - // Saturates if `x` is more than `$max` internally. + // Saturates if `x` is more than `$max` internally. Self::from_parts(x) } } diff --git a/primitives/npos-elections/compact/src/lib.rs b/primitives/npos-elections/compact/src/lib.rs index 86ddaf4af70bc..52b03a11934d2 100644 --- a/primitives/npos-elections/compact/src/lib.rs +++ b/primitives/npos-elections/compact/src/lib.rs @@ -179,7 +179,7 @@ fn struct_def( type Target = #target_type; type VoteWeight = #weight_type; - fn len(&self) -> usize { + fn voters_count(&self) -> usize { let mut all_len = 0usize; #len_impl all_len diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 717e963b07ca0..5e0e6c7b6f898 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -157,13 +157,15 @@ pub trait CompactSolution: Sized { target_at: impl Fn(Self::Target) -> Option, ) -> Result>, Error>; - /// Get the length of all the assignments that this type is encoding. This is basically - /// the same as the number of assignments, or the number of voters in total. - fn len(&self) -> usize; + /// Get the length of all the assignments that this type is encoding. + /// + /// This is basically the same as the number of assignments, or the number of voters in total. + fn voters_count(&self) -> usize; /// Get the total count of edges. /// - /// This is effectively in the range of {[`Self::len`], [`Self::len`] * [`Self::LIMIT`]}. + /// This is effectively in the range of {[`Self::voters_count`], [`Self::voters_count`] * + /// [`Self::LIMIT`]}. fn edge_count(&self) -> usize; /// Get the number of unique targets in the whole struct. @@ -176,7 +178,9 @@ pub trait CompactSolution: Sized { /// Get the average edge count. fn average_edge_count(&self) -> usize { - self.edge_count().checked_div(self.len()).unwrap_or(0) + self.edge_count() + .checked_div(self.voters_count()) + .unwrap_or(0) } /// Remove a certain voter. From bd0d3315796aac9e735006983a08cc82c2c735ed Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 8 Dec 2020 09:46:55 +0000 Subject: [PATCH 19/62] Fix bench --- .../src/two_phase/benchmarking.rs | 39 +++++++------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index 86fd627cd4db7..9f3a7a1e647c2 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -48,14 +48,17 @@ where witness.voters >= active_voters_count, "must have enough voters" ); + assert!((>::LIMIT as u32) < winners_count, "must have enough winners to give them votes."); let stake: u64 = 1000_000; + // first generates random targets. let targets: Vec = (0..witness.targets) .map(|i| account("Targets", i, SEED)) .collect(); let mut rng = thread_rng(); + // decide who are the winners. let winners = targets .as_slice() @@ -64,27 +67,16 @@ where .collect::>(); // generate first active voters who must vote for a subset of winners. - // TODO: this could lead to an underestimate, the active voters should only vote for winners to - // maximize all the iterations. let active_voters = (0..active_voters_count) .map(|i| { - // chose a random number of votes to give to the winners, and whatever is left is given - // to everyone. - let votes_to_winners = rand::random::() % >::LIMIT + 1; - let votes_to_everyone = >::LIMIT - votes_to_winners; - + // chose a random subset of winners. let winner_votes = winners .as_slice() - .choose_multiple(&mut rng, votes_to_winners) - .cloned(); - let rest_votes = targets - .as_slice() - .choose_multiple(&mut rng, votes_to_everyone as usize) - .cloned(); - - let votes = winner_votes.chain(rest_votes).collect::>(); + .choose_multiple(&mut rng, >::LIMIT) + .cloned() + .collect::>(); let voter = account::("Voter", i, SEED); - (voter, stake, votes) + (voter, stake, winner_votes) }) .collect::>(); @@ -105,30 +97,27 @@ where }) .collect::>(); - dbg!(active_voters.len(), rest_voters.len(), winners.len()); - // active_voters.extend(rest_voters); let mut all_voters = active_voters.clone(); all_voters.extend(rest_voters); + all_voters.shuffle(&mut rng); assert_eq!(active_voters.len() as u32, active_voters_count); assert_eq!(all_voters.len() as u32, witness.voters); assert_eq!(winners.len() as u32, winners_count); - let voters = active_voters; - >::put(RoundSnapshot { desired_targets: winners_count, - voters: all_voters, + voters: all_voters.clone(), targets: targets.clone(), }); - let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); - let voter_at = crate::voter_at_fn!(voters, T::AccountId, T); + let stake_of = crate::stake_of_fn!(all_voters, T::AccountId); + let voter_index = crate::voter_index_fn!(all_voters, T::AccountId, T); + let voter_at = crate::voter_at_fn!(all_voters, T::AccountId, T); let target_at = crate::target_at_fn!(targets, T::AccountId, T); let target_index = crate::target_index_fn!(targets, T::AccountId, T); - let stake_of = crate::stake_of_fn!(voters, T::AccountId); - let assignments = voters + let assignments = active_voters .iter() .map(|(voter, _stake, votes)| { let percent_per_edge: InnerOf> = From eac45718daa239bd5892c62720094471f9a4c6d7 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 8 Dec 2020 16:27:59 +0000 Subject: [PATCH 20/62] Everything compiles and good -- need to fix benches. --- Cargo.lock | 1 - frame/election-providers/Cargo.toml | 30 +- frame/election-providers/exapnded.test.rs | 11604 ---------------- frame/election-providers/expanded.rs | 4247 ------ frame/election-providers/src/lib.rs | 4 +- .../src/two_phase/benchmarking.rs | 11 +- .../election-providers/src/two_phase/mock.rs | 116 +- frame/election-providers/src/two_phase/mod.rs | 246 +- .../src/two_phase/signed.rs | 228 +- .../src/two_phase/unsigned.rs | 100 +- frame/offences/benchmarking/src/lib.rs | 21 +- 11 files changed, 500 insertions(+), 16108 deletions(-) delete mode 100644 frame/election-providers/exapnded.test.rs delete mode 100644 frame/election-providers/expanded.rs diff --git a/Cargo.lock b/Cargo.lock index 564a146f18abd..872b326ba294d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1584,7 +1584,6 @@ dependencies = [ "sp-io", "sp-npos-elections", "sp-runtime", - "sp-staking", "sp-std", "sp-tracing", "static_assertions", diff --git a/frame/election-providers/Cargo.toml b/frame/election-providers/Cargo.toml index 001bc7989abe3..ebe0be8eb3094 100644 --- a/frame/election-providers/Cargo.toml +++ b/frame/election-providers/Cargo.toml @@ -16,16 +16,16 @@ targets = ["x86_64-unknown-linux-gnu"] static_assertions = "1.1.0" serde = { version = "1.0.101", optional = true } codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] } -sp-io ={ version = "2.0.0-rc6", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/runtime" } -sp-staking = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/staking" } -frame-support = { version = "2.0.0-rc6", default-features = false, path = "../support" } -frame-system = { version = "2.0.0-rc6", default-features = false, path = "../system" } -sp-npos-elections = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/npos-elections" } -sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } -sp-arithmetic = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/arithmetic" } -sp-election-providers = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/election-providers" } +frame-support = { version = "2.0.0", default-features = false, path = "../support" } +frame-system = { version = "2.0.0", default-features = false, path = "../system" } + +sp-io ={ version = "2.0.0", default-features = false, path = "../../primitives/io" } +sp-std = { version = "2.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "2.0.0", default-features = false, path = "../../primitives/runtime" } +sp-npos-elections = { version = "2.0.0", default-features = false, path = "../../primitives/npos-elections" } +sp-arithmetic = { version = "2.0.0", default-features = false, path = "../../primitives/arithmetic" } +sp-election-providers = { version = "2.0.0", default-features = false, path = "../../primitives/election-providers" } # Optional imports for benchmarking frame-benchmarking = { version = "2.0.0", default-features = false, path = "../benchmarking", optional = true } @@ -37,7 +37,7 @@ sp-io = { version = "2.0.0", path = "../../primitives/io" } hex-literal = "0.3.1" pallet-balances = { version = "2.0.0", path = "../balances" } sp-core = { version = "2.0.0", path = "../../primitives/core" } -paste = "1.0.1" +paste = "1.0.3" substrate-test-utils = { version = "2.0.0", path = "../../test-utils" } parking_lot = "0.10.2" sp-tracing = { version = "2.0.0", path = "../../primitives/tracing" } @@ -51,12 +51,16 @@ default = ["std"] std = [ "serde", "codec/std", + "frame-support/std", - "sp-runtime/std", - "sp-npos-elections/std", "frame-system/std", + + "sp-io/std", "sp-std/std", - "sp-election-providers/std" + "sp-runtime/std", + "sp-npos-elections/std", + "sp-arithmetic/std", + "sp-election-providers/std", ] runtime-benchmarks = [ "frame-benchmarking", diff --git a/frame/election-providers/exapnded.test.rs b/frame/election-providers/exapnded.test.rs deleted file mode 100644 index 0640a9bc62ff9..0000000000000 --- a/frame/election-providers/exapnded.test.rs +++ /dev/null @@ -1,11604 +0,0 @@ -#![feature(prelude_import)] -//! Various implementation for `ElectionProvider`. -//! -//! Two main election providers are implemented in this crate. -//! -//! 1. [`onchain`]: A `struct` that perform the election onchain (i.e. in the fly). This type is -//! likely to be expensive for most chains and damage the block time. Only use when you are sure -//! that the inputs are bounded and small enough. -//! 2. [`two_phase`]: An individual `pallet` that performs the election in two phases, signed and -//! unsigned. Needless to say, the pallet needs to be included in the final runtime. -#[prelude_import] -use std::prelude::v1::*; -#[macro_use] -extern crate std; -/// The onchain module. -pub mod onchain { - use sp_arithmetic::PerThing; - use sp_election_providers::ElectionProvider; - use sp_npos_elections::{ - ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Supports, VoteWeight, - }; - use sp_runtime::RuntimeDebug; - use sp_std::{collections::btree_map::BTreeMap, prelude::*}; - /// Errors of the on-chain election. - pub enum Error { - /// An internal error in the NPoS elections crate. - NposElections(sp_npos_elections::Error), - } - impl core::fmt::Debug for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::NposElections(ref a0) => { - fmt.debug_tuple("Error::NposElections").field(a0).finish() - } - _ => Ok(()), - } - } - } - impl ::core::marker::StructuralEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Error { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - } - } - } - impl ::core::marker::StructuralPartialEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Error { - #[inline] - fn eq(&self, other: &Error) -> bool { - match (&*self, &*other) { - (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - } - } - #[inline] - fn ne(&self, other: &Error) -> bool { - match (&*self, &*other) { - (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - } - } - } - impl From for Error { - fn from(e: sp_npos_elections::Error) -> Self { - Error::NposElections(e) - } - } - /// A simple on-chian implementation of the election provider trait. - /// - /// This will accept voting data on the fly and produce the results immediately. - /// - /// ### Warning - /// - /// This can be very expensive to run frequently on-chain. Use with care. - pub struct OnChainSequentialPhragmen; - impl ElectionProvider for OnChainSequentialPhragmen { - type Error = Error; - const NEEDS_ELECT_DATA: bool = true; - fn elect( - to_elect: usize, - targets: Vec, - voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>, - { - let mut stake_map: BTreeMap = BTreeMap::new(); - voters.iter().for_each(|(v, s, _)| { - stake_map.insert(v.clone(), *s); - }); - let stake_of = Box::new(|w: &AccountId| -> VoteWeight { - stake_map.get(w).cloned().unwrap_or_default() - }); - sp_npos_elections::seq_phragmen::<_, P>(to_elect, targets, voters, None) - .and_then(|e| { - let ElectionResult { - winners, - assignments, - } = e; - let staked = sp_npos_elections::assignment_ratio_to_staked_normalized( - assignments, - &stake_of, - )?; - let winners = sp_npos_elections::to_without_backing(winners); - sp_npos_elections::to_supports(&winners, &staked) - }) - .map_err(From::from) - } - fn ongoing() -> bool { - false - } - } -} -/// The two-phase module. -pub mod two_phase { - //! # Two phase election provider pallet. - //! - //! As the name suggests, this election provider has two distinct phases (see [`Phase`]), signed and - //! unsigned. - //! - //! ## Phases - //! - //! The timeline of pallet is as follows. At each block, - //! [`ElectionDataProvider::next_election_prediction`] is used to estimate the time remaining to the - //! next call to `elect`. Based on this, a phase is chosen. The timeline is as follows. - //! - //! ```ignore - //! elect() - //! + <--T::SignedPhase--> + <--T::UnsignedPhase--> + - //! +-------------------------------------------------------------------+ - //! Phase::Off + Phase::Signed + Phase::Unsigned + - //! - //! Note that the unsigned phase starts `T::UnsignedPhase` blocks before the - //! `next_election_prediction`, but only ends when a call to `ElectionProvider::elect` happens. - //! - //! ``` - //! ### Signed Phase - //! - //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A - //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution - //! on-chain for a number of blocks. A maximum of [`Trait::MaxSignedSubmissions`] solutions are - //! stored. The queue is always sorted based on score (worse -> best). - //! - //! Upon arrival of a new solution: - //! - //! 1. If the queue is not full, it is stored. - //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the - //! worse solution is discarded (TODO: what to do with the bond?) and the new solution is stored - //! in the correct index. - //! 3. If the queue is full and the solution is not an improvement compared to any of the queued - //! ones, it is instantly rejected and no additional bond is reserved. - //! - //! A signed solution cannot be reversed, taken back, updated, or retracted. In other words, the - //! origin can not bail out in any way. - //! - //! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed - //! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure - //! the score claimed by this score was correct, among other checks. At each step, if the current - //! best solution is passes the feasibility check, it is considered to be the best one. The sender - //! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without - //! being checked. - //! - //! The following example covers all of the cases at the end of the signed phase: - //! - //! ```ignore - //! Queue - //! +-------------------------------+ - //! |Solution(score=20, valid=false)| +--> Slashed - //! +-------------------------------+ - //! |Solution(score=15, valid=true )| +--> Rewarded - //! +-------------------------------+ - //! |Solution(score=10, valid=true )| +--> Discarded - //! +-------------------------------+ - //! |Solution(score=05, valid=false)| +--> Discarded - //! +-------------------------------+ - //! | None | - //! +-------------------------------+ - //! ``` - //! - //! TODO: what if length of some phase is zero? - //! - //! Note that both of the bottom solutions end up being discarded and get their deposit back, - //! despite one of them being invalid. - //! - //! ## Unsigned Phase - //! - //! If signed phase ends with a good solution, then the unsigned phase will be `active` - //! ([`Phase::Unsigned(true)`]), else the unsigned phase will be `passive`. - //! - //! TODO - //! - //! ### Fallback - //! - //! If we reach the end of both phases (i.e. call to `ElectionProvider::elect` happens) and no good - //! solution is queued, then we fallback to an on-chain election. The on-chain election is slow, and - //! contains to balancing or reduction post-processing. - //! - //! ## Correct Submission - //! - //! TODO - //! - //! ## Accuracy - //! - //! TODO - //! - use crate::onchain::OnChainSequentialPhragmen; - use codec::{Decode, Encode, HasCompact}; - use frame_support::{ - decl_event, decl_module, decl_storage, - dispatch::DispatchResultWithPostInfo, - ensure, - traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, - weights::Weight, - }; - use frame_system::{ensure_none, ensure_signed, offchain::SendTransactionTypes}; - use sp_election_providers::{ElectionDataProvider, ElectionProvider}; - use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, is_score_better, Assignment, CompactSolution, - ElectionScore, EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, - }; - use sp_runtime::{ - traits::Zero, transaction_validity::TransactionPriority, InnerOf, PerThing, Perbill, - RuntimeDebug, - }; - use sp_std::prelude::*; - #[cfg(any(feature = "runtime-benchmarks", test))] - pub mod benchmarking { - //! Two phase election pallet benchmarking. - use super::*; - use crate::two_phase::{Module as TwoPhase, *}; - pub use frame_benchmarking::{account, benchmarks, whitelist_account, whitelisted_caller}; - use frame_support::assert_ok; - use rand::{seq::SliceRandom, thread_rng}; - use sp_npos_elections::{ExtendedBalance, VoteWeight}; - use sp_runtime::InnerOf; - const SEED: u32 = 0; - /// Generate mock on-chain snapshots. - /// - /// This emulates the start of signed phase, where snapshots are received from an upstream crate. - fn mock_snapshot( - witness: WitnessData, - ) -> ( - Vec, - Vec<(T::AccountId, VoteWeight, Vec)>, - ) - where - ExtendedBalance: From>>, - { - let targets: Vec = (0..witness.targets) - .map(|i| account("Targets", i, SEED)) - .collect(); - let mut voters = (0..(witness.voters - witness.targets)) - .map(|i| { - let mut rng = thread_rng(); - let stake = 1000_000u64; - let to_vote = rand::random::() % >::LIMIT + 1; - let votes = targets - .as_slice() - .choose_multiple(&mut rng, to_vote) - .cloned() - .collect::>(); - let voter = account::("Voter", i, SEED); - (voter, stake, votes) - }) - .collect::>(); - voters.extend( - targets - .iter() - .map(|t| (t.clone(), 1000_000_0u64, <[_]>::into_vec(box [t.clone()]))), - ); - (targets, voters) - } - fn put_mock_snapshot(witness: WitnessData, desired_targets: u32) - where - ExtendedBalance: From>>, - { - let (targets, voters) = mock_snapshot::(witness); - >::put(targets); - >::put(voters); - DesiredTargets::put(desired_targets); - } - #[allow(non_camel_case_types)] - struct submit_signed; - #[allow(unused_variables)] - impl ::frame_benchmarking::BenchmarkingSetup for submit_signed - where - ExtendedBalance: From>>, - { - fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { - ::alloc::vec::Vec::new() - } - fn instance( - &self, - components: &[(::frame_benchmarking::BenchmarkParameter, u32)], - verify: bool, - ) -> Result Result<(), &'static str>>, &'static str> { - Ok(Box::new(move || -> Result<(), &'static str> { - {}; - if verify { - {}; - } - Ok(()) - })) - } - } - fn test_benchmark_submit_signed() -> Result<(), &'static str> - where - T: frame_system::Trait, - ExtendedBalance: From>>, - { - let selected_benchmark = SelectedBenchmark::submit_signed; - let components = - >::components( - &selected_benchmark, - ); - let execute_benchmark = | c : Vec < ( :: frame_benchmarking :: BenchmarkParameter , u32 ) > | -> Result < ( ) , & 'static str > { let closure_to_verify = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T , _ > > :: instance ( & selected_benchmark , & c , true ) ? ; if :: frame_benchmarking :: Zero :: is_zero ( & frame_system :: Module :: < T > :: block_number ( ) ) { frame_system :: Module :: < T > :: set_block_number ( 1 . into ( ) ) ; } closure_to_verify ( ) ? ; :: frame_benchmarking :: benchmarking :: wipe_db ( ) ; Ok ( ( ) ) } ; - if components.is_empty() { - execute_benchmark(Default::default())?; - } else { - for (_, (name, low, high)) in components.iter().enumerate() { - for component_value in <[_]>::into_vec(box [low, high]) { - let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = components - .iter() - .enumerate() - .map(|(_, (n, _, h))| { - if n == name { - (*n, *component_value) - } else { - (*n, *h) - } - }) - .collect(); - execute_benchmark(c)?; - } - } - } - Ok(()) - } - #[allow(non_camel_case_types)] - struct submit_unsigned; - #[allow(unused_variables)] - impl ::frame_benchmarking::BenchmarkingSetup for submit_unsigned - where - ExtendedBalance: From>>, - { - fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { - ::alloc::vec::Vec::new() - } - fn instance( - &self, - components: &[(::frame_benchmarking::BenchmarkParameter, u32)], - verify: bool, - ) -> Result Result<(), &'static str>>, &'static str> { - Ok(Box::new(move || -> Result<(), &'static str> { - {}; - if verify { - {}; - } - Ok(()) - })) - } - } - fn test_benchmark_submit_unsigned() -> Result<(), &'static str> - where - T: frame_system::Trait, - ExtendedBalance: From>>, - { - let selected_benchmark = SelectedBenchmark::submit_unsigned; - let components = - >::components( - &selected_benchmark, - ); - let execute_benchmark = | c : Vec < ( :: frame_benchmarking :: BenchmarkParameter , u32 ) > | -> Result < ( ) , & 'static str > { let closure_to_verify = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T , _ > > :: instance ( & selected_benchmark , & c , true ) ? ; if :: frame_benchmarking :: Zero :: is_zero ( & frame_system :: Module :: < T > :: block_number ( ) ) { frame_system :: Module :: < T > :: set_block_number ( 1 . into ( ) ) ; } closure_to_verify ( ) ? ; :: frame_benchmarking :: benchmarking :: wipe_db ( ) ; Ok ( ( ) ) } ; - if components.is_empty() { - execute_benchmark(Default::default())?; - } else { - for (_, (name, low, high)) in components.iter().enumerate() { - for component_value in <[_]>::into_vec(box [low, high]) { - let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = components - .iter() - .enumerate() - .map(|(_, (n, _, h))| { - if n == name { - (*n, *component_value) - } else { - (*n, *h) - } - }) - .collect(); - execute_benchmark(c)?; - } - } - } - Ok(()) - } - #[allow(non_camel_case_types)] - struct open_signed_phase; - #[allow(unused_variables)] - impl ::frame_benchmarking::BenchmarkingSetup for open_signed_phase - where - ExtendedBalance: From>>, - { - fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { - ::alloc::vec::Vec::new() - } - fn instance( - &self, - components: &[(::frame_benchmarking::BenchmarkParameter, u32)], - verify: bool, - ) -> Result Result<(), &'static str>>, &'static str> { - Ok(Box::new(move || -> Result<(), &'static str> { - {}; - if verify { - {}; - } - Ok(()) - })) - } - } - fn test_benchmark_open_signed_phase() -> Result<(), &'static str> - where - T: frame_system::Trait, - ExtendedBalance: From>>, - { - let selected_benchmark = SelectedBenchmark::open_signed_phase; - let components = - >::components( - &selected_benchmark, - ); - let execute_benchmark = | c : Vec < ( :: frame_benchmarking :: BenchmarkParameter , u32 ) > | -> Result < ( ) , & 'static str > { let closure_to_verify = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T , _ > > :: instance ( & selected_benchmark , & c , true ) ? ; if :: frame_benchmarking :: Zero :: is_zero ( & frame_system :: Module :: < T > :: block_number ( ) ) { frame_system :: Module :: < T > :: set_block_number ( 1 . into ( ) ) ; } closure_to_verify ( ) ? ; :: frame_benchmarking :: benchmarking :: wipe_db ( ) ; Ok ( ( ) ) } ; - if components.is_empty() { - execute_benchmark(Default::default())?; - } else { - for (_, (name, low, high)) in components.iter().enumerate() { - for component_value in <[_]>::into_vec(box [low, high]) { - let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = components - .iter() - .enumerate() - .map(|(_, (n, _, h))| { - if n == name { - (*n, *component_value) - } else { - (*n, *h) - } - }) - .collect(); - execute_benchmark(c)?; - } - } - } - Ok(()) - } - #[allow(non_camel_case_types)] - struct close_signed_phase; - #[allow(unused_variables)] - impl ::frame_benchmarking::BenchmarkingSetup for close_signed_phase - where - ExtendedBalance: From>>, - { - fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { - ::alloc::vec::Vec::new() - } - fn instance( - &self, - components: &[(::frame_benchmarking::BenchmarkParameter, u32)], - verify: bool, - ) -> Result Result<(), &'static str>>, &'static str> { - Ok(Box::new(move || -> Result<(), &'static str> { - {}; - if verify { - {}; - } - Ok(()) - })) - } - } - fn test_benchmark_close_signed_phase() -> Result<(), &'static str> - where - T: frame_system::Trait, - ExtendedBalance: From>>, - { - let selected_benchmark = SelectedBenchmark::close_signed_phase; - let components = - >::components( - &selected_benchmark, - ); - let execute_benchmark = | c : Vec < ( :: frame_benchmarking :: BenchmarkParameter , u32 ) > | -> Result < ( ) , & 'static str > { let closure_to_verify = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T , _ > > :: instance ( & selected_benchmark , & c , true ) ? ; if :: frame_benchmarking :: Zero :: is_zero ( & frame_system :: Module :: < T > :: block_number ( ) ) { frame_system :: Module :: < T > :: set_block_number ( 1 . into ( ) ) ; } closure_to_verify ( ) ? ; :: frame_benchmarking :: benchmarking :: wipe_db ( ) ; Ok ( ( ) ) } ; - if components.is_empty() { - execute_benchmark(Default::default())?; - } else { - for (_, (name, low, high)) in components.iter().enumerate() { - for component_value in <[_]>::into_vec(box [low, high]) { - let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = components - .iter() - .enumerate() - .map(|(_, (n, _, h))| { - if n == name { - (*n, *component_value) - } else { - (*n, *h) - } - }) - .collect(); - execute_benchmark(c)?; - } - } - } - Ok(()) - } - #[allow(non_camel_case_types)] - struct feasibility_check; - #[allow(unused_variables)] - impl ::frame_benchmarking::BenchmarkingSetup for feasibility_check - where - ExtendedBalance: From>>, - { - fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { - <[_]>::into_vec(box [ - (::frame_benchmarking::BenchmarkParameter::v, 200, 300), - (::frame_benchmarking::BenchmarkParameter::t, 50, 80), - (::frame_benchmarking::BenchmarkParameter::a, 20, 80), - (::frame_benchmarking::BenchmarkParameter::d, 20, 40), - ]) - } - fn instance( - &self, - components: &[(::frame_benchmarking::BenchmarkParameter, u32)], - verify: bool, - ) -> Result Result<(), &'static str>>, &'static str> { - let v = components - .iter() - .find(|&c| c.0 == ::frame_benchmarking::BenchmarkParameter::v) - .ok_or("Could not find component in benchmark preparation.")? - .1; - let t = components - .iter() - .find(|&c| c.0 == ::frame_benchmarking::BenchmarkParameter::t) - .ok_or("Could not find component in benchmark preparation.")? - .1; - let a = components - .iter() - .find(|&c| c.0 == ::frame_benchmarking::BenchmarkParameter::a) - .ok_or("Could not find component in benchmark preparation.")? - .1; - let d = components - .iter() - .find(|&c| c.0 == ::frame_benchmarking::BenchmarkParameter::d) - .ok_or("Could not find component in benchmark preparation.")? - .1; - (); - (); - (); - (); - { - ::std::io::_print(::core::fmt::Arguments::new_v1( - &["running v ", ", t ", ", a ", ", d ", "\n"], - &match (&v, &t, &a, &d) { - (arg0, arg1, arg2, arg3) => [ - ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), - ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Display::fmt), - ::core::fmt::ArgumentV1::new(arg2, ::core::fmt::Display::fmt), - ::core::fmt::ArgumentV1::new(arg3, ::core::fmt::Display::fmt), - ], - }, - )); - }; - let witness = WitnessData { - voters: v, - targets: t, - }; - put_mock_snapshot::(witness, d); - let voters = >::snapshot_voters().unwrap(); - let targets = >::snapshot_targets().unwrap(); - let voter_index = - |who: &T::AccountId| -> Option> { - voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < T > > > :: try_into ( i ) . ok ( ) ) - }; - let voter_at = - |i: crate::two_phase::CompactVoterIndexOf| -> Option { - < crate :: two_phase :: CompactVoterIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | voters . get ( i ) . map ( | ( x , _ , _ ) | x ) . cloned ( ) ) - }; - let target_at = - |i: crate::two_phase::CompactTargetIndexOf| -> Option { - < crate :: two_phase :: CompactTargetIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | targets . get ( i ) . cloned ( ) ) - }; - let stake_of = |who: &T::AccountId| -> crate::VoteWeight { - voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - }; - let RawSolution { compact, score: _ } = >::mine_solution(0).unwrap(); - let compact = >::trim_compact(a, compact, voter_index).unwrap(); - { - match (&(compact.len() as u32), &a) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&(compact.unique_targets().len() as u32), &d) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let winners = compact - .unique_targets() - .iter() - .map(|i| target_at(*i).unwrap()) - .collect::>(); - let score = compact - .clone() - .score(&winners, stake_of, voter_at, target_at) - .unwrap(); - let raw_solution = RawSolution { compact, score }; - let compute = ElectionCompute::Unsigned; - Ok(Box::new(move || -> Result<(), &'static str> { - { - let is = >::feasibility_check(raw_solution, compute); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: - ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: - ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - }; - if verify { - {}; - } - Ok(()) - })) - } - } - fn test_benchmark_feasibility_check() -> Result<(), &'static str> - where - T: frame_system::Trait, - ExtendedBalance: From>>, - { - let selected_benchmark = SelectedBenchmark::feasibility_check; - let components = - >::components( - &selected_benchmark, - ); - let execute_benchmark = | c : Vec < ( :: frame_benchmarking :: BenchmarkParameter , u32 ) > | -> Result < ( ) , & 'static str > { let closure_to_verify = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T , _ > > :: instance ( & selected_benchmark , & c , true ) ? ; if :: frame_benchmarking :: Zero :: is_zero ( & frame_system :: Module :: < T > :: block_number ( ) ) { frame_system :: Module :: < T > :: set_block_number ( 1 . into ( ) ) ; } closure_to_verify ( ) ? ; :: frame_benchmarking :: benchmarking :: wipe_db ( ) ; Ok ( ( ) ) } ; - if components.is_empty() { - execute_benchmark(Default::default())?; - } else { - for (_, (name, low, high)) in components.iter().enumerate() { - for component_value in <[_]>::into_vec(box [low, high]) { - let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = components - .iter() - .enumerate() - .map(|(_, (n, _, h))| { - if n == name { - (*n, *component_value) - } else { - (*n, *h) - } - }) - .collect(); - execute_benchmark(c)?; - } - } - } - Ok(()) - } - #[allow(non_camel_case_types)] - enum SelectedBenchmark { - submit_signed, - submit_unsigned, - open_signed_phase, - close_signed_phase, - feasibility_check, - } - impl ::frame_benchmarking::BenchmarkingSetup for SelectedBenchmark - where - ExtendedBalance: From>>, - { - fn components(&self) -> Vec<(::frame_benchmarking::BenchmarkParameter, u32, u32)> { - match self { Self :: submit_signed => < submit_signed as :: frame_benchmarking :: BenchmarkingSetup < T > > :: components ( & submit_signed ) , Self :: submit_unsigned => < submit_unsigned as :: frame_benchmarking :: BenchmarkingSetup < T > > :: components ( & submit_unsigned ) , Self :: open_signed_phase => < open_signed_phase as :: frame_benchmarking :: BenchmarkingSetup < T > > :: components ( & open_signed_phase ) , Self :: close_signed_phase => < close_signed_phase as :: frame_benchmarking :: BenchmarkingSetup < T > > :: components ( & close_signed_phase ) , Self :: feasibility_check => < feasibility_check as :: frame_benchmarking :: BenchmarkingSetup < T > > :: components ( & feasibility_check ) , } - } - fn instance( - &self, - components: &[(::frame_benchmarking::BenchmarkParameter, u32)], - verify: bool, - ) -> Result Result<(), &'static str>>, &'static str> { - match self { - Self::submit_signed => { - >::instance( - &submit_signed, - components, - verify, - ) - } - Self::submit_unsigned => { - >::instance( - &submit_unsigned, - components, - verify, - ) - } - Self::open_signed_phase => { - >::instance( - &open_signed_phase, - components, - verify, - ) - } - Self::close_signed_phase => { - >::instance( - &close_signed_phase, - components, - verify, - ) - } - Self::feasibility_check => { - >::instance( - &feasibility_check, - components, - verify, - ) - } - } - } - } - impl ::frame_benchmarking::Benchmarking<::frame_benchmarking::BenchmarkResults> - for Module - where - T: frame_system::Trait, - ExtendedBalance: From>>, - { - fn benchmarks(extra: bool) -> Vec<&'static [u8]> { - let mut all = <[_]>::into_vec(box [ - "submit_signed".as_ref(), - "submit_unsigned".as_ref(), - "open_signed_phase".as_ref(), - "close_signed_phase".as_ref(), - "feasibility_check".as_ref(), - ]); - if !extra { - let extra = []; - all.retain(|x| !extra.contains(x)); - } - all - } - fn run_benchmark( - extrinsic: &[u8], - lowest_range_values: &[u32], - highest_range_values: &[u32], - steps: &[u32], - repeat: u32, - whitelist: &[::frame_benchmarking::TrackedStorageKey], - verify: bool, - ) -> Result, &'static str> { - let extrinsic = sp_std::str::from_utf8(extrinsic) - .map_err(|_| "`extrinsic` is not a valid utf8 string!")?; - let selected_benchmark = match extrinsic { - "submit_signed" => SelectedBenchmark::submit_signed, - "submit_unsigned" => SelectedBenchmark::submit_unsigned, - "open_signed_phase" => SelectedBenchmark::open_signed_phase, - "close_signed_phase" => SelectedBenchmark::close_signed_phase, - "feasibility_check" => SelectedBenchmark::feasibility_check, - _ => return Err("Could not find extrinsic."), - }; - let mut results: Vec<::frame_benchmarking::BenchmarkResults> = Vec::new(); - if repeat == 0 { - return Ok(results); - } - let mut whitelist = whitelist.to_vec(); - let whitelisted_caller_key = < frame_system :: Account < T > as frame_support :: storage :: StorageMap < _ , _ > > :: hashed_key_for ( :: frame_benchmarking :: whitelisted_caller :: < T :: AccountId > ( ) ) ; - whitelist.push(whitelisted_caller_key.into()); - ::frame_benchmarking::benchmarking::set_whitelist(whitelist); - ::frame_benchmarking::benchmarking::commit_db(); - ::frame_benchmarking::benchmarking::wipe_db(); - let components = >::components(&selected_benchmark); - let mut prev_steps = 10; - let repeat_benchmark = |repeat: u32, - c: &[(::frame_benchmarking::BenchmarkParameter, u32)], - results: &mut Vec< - ::frame_benchmarking::BenchmarkResults, - >, - verify: bool| - -> Result<(), &'static str> { - for _ in 0..repeat { - let closure_to_benchmark = < SelectedBenchmark as :: frame_benchmarking :: BenchmarkingSetup < T > > :: instance ( & selected_benchmark , c , verify ) ? ; - if ::frame_benchmarking::Zero::is_zero( - &frame_system::Module::::block_number(), - ) { - frame_system::Module::::set_block_number(1.into()); - } - ::frame_benchmarking::benchmarking::commit_db(); - ::frame_benchmarking::benchmarking::reset_read_write_count(); - if verify { - closure_to_benchmark()?; - } else { - { - let lvl = ::log::Level::Trace; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - :: log :: __private_api_log ( :: core :: fmt :: Arguments :: new_v1 ( & [ "Start Benchmark: " ] , & match ( & c , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } ) , lvl , & ( "benchmark" , "frame_election_providers::two_phase::benchmarking" , "frame/election-providers/src/two_phase/benchmarking.rs" , 81u32 ) ) ; - } - }; - let start_extrinsic = - ::frame_benchmarking::benchmarking::current_time(); - closure_to_benchmark()?; - let finish_extrinsic = - ::frame_benchmarking::benchmarking::current_time(); - let elapsed_extrinsic = finish_extrinsic - start_extrinsic; - ::frame_benchmarking::benchmarking::commit_db(); - { - let lvl = ::log::Level::Trace; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - :: log :: __private_api_log ( :: core :: fmt :: Arguments :: new_v1 ( & [ "End Benchmark: " , " ns" ] , & match ( & elapsed_extrinsic , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Display :: fmt ) ] , } ) , lvl , & ( "benchmark" , "frame_election_providers::two_phase::benchmarking" , "frame/election-providers/src/two_phase/benchmarking.rs" , 81u32 ) ) ; - } - }; - let read_write_count = - ::frame_benchmarking::benchmarking::read_write_count(); - { - let lvl = ::log::Level::Trace; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - :: log :: __private_api_log ( :: core :: fmt :: Arguments :: new_v1 ( & [ "Read/Write Count " ] , & match ( & read_write_count , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } ) , lvl , & ( "benchmark" , "frame_election_providers::two_phase::benchmarking" , "frame/election-providers/src/two_phase/benchmarking.rs" , 81u32 ) ) ; - } - }; - let start_storage_root = - ::frame_benchmarking::benchmarking::current_time(); - ::frame_benchmarking::storage_root(); - let finish_storage_root = - ::frame_benchmarking::benchmarking::current_time(); - let elapsed_storage_root = finish_storage_root - start_storage_root; - results.push(::frame_benchmarking::BenchmarkResults { - components: c.to_vec(), - extrinsic_time: elapsed_extrinsic, - storage_root_time: elapsed_storage_root, - reads: read_write_count.0, - repeat_reads: read_write_count.1, - writes: read_write_count.2, - repeat_writes: read_write_count.3, - }); - } - ::frame_benchmarking::benchmarking::wipe_db(); - } - Ok(()) - }; - if components.is_empty() { - if verify { - repeat_benchmark(1, Default::default(), &mut Vec::new(), true)?; - } - repeat_benchmark(repeat, Default::default(), &mut results, false)?; - } else { - for (idx, (name, low, high)) in components.iter().enumerate() { - let steps = steps.get(idx).cloned().unwrap_or(prev_steps); - prev_steps = steps; - if steps == 0 { - continue; - } - let lowest = lowest_range_values.get(idx).cloned().unwrap_or(*low); - let highest = highest_range_values.get(idx).cloned().unwrap_or(*high); - let diff = highest - lowest; - let step_size = (diff / steps).max(1); - let num_of_steps = diff / step_size + 1; - for s in 0..num_of_steps { - let component_value = lowest + step_size * s; - let c: Vec<(::frame_benchmarking::BenchmarkParameter, u32)> = - components - .iter() - .enumerate() - .map(|(idx, (n, _, h))| { - if n == name { - (*n, component_value) - } else { - (*n, *highest_range_values.get(idx).unwrap_or(h)) - } - }) - .collect(); - if verify { - repeat_benchmark(1, &c, &mut Vec::new(), true)?; - } - repeat_benchmark(repeat, &c, &mut results, false)?; - } - } - } - return Ok(results); - } - } - #[cfg(test)] - mod test { - use super::*; - use crate::two_phase::mock::*; - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const test_benchmarks: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::benchmarking::test::test_benchmarks"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(test_benchmarks())), - }; - fn test_benchmarks() { - ExtBuilder::default().build_and_execute(|| { - let is = test_benchmark_feasibility_check::(); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - }) - } - } - } - #[cfg(test)] - mod mock { - use super::*; - pub use frame_support::{assert_noop, assert_ok}; - use frame_support::{parameter_types, traits::OnInitialize}; - use parking_lot::RwLock; - use sp_core::{ - offchain::{ - testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, - OffchainExt, TransactionPoolExt, - }, - H256, - }; - use sp_election_providers::ElectionDataProvider; - use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, to_without_backing, - CompactSolution, ElectionResult, EvaluateSupport, - }; - use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - PerU16, - }; - use std::{cell::RefCell, sync::Arc}; - pub struct Runtime; - impl ::core::marker::StructuralEq for Runtime {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Runtime { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - {} - } - } - impl ::core::marker::StructuralPartialEq for Runtime {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Runtime { - #[inline] - fn eq(&self, other: &Runtime) -> bool { - match *other { - Runtime => match *self { - Runtime => true, - }, - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Runtime { - #[inline] - fn clone(&self) -> Runtime { - match *self { - Runtime => Runtime, - } - } - } - pub(crate) type Balances = pallet_balances::Module; - pub(crate) type System = frame_system::Module; - pub(crate) type TwoPhase = super::Module; - pub(crate) type Balance = u64; - pub(crate) type AccountId = u64; - extern crate sp_npos_elections as _npos; - /// A struct to encode a election assignment in a compact way. - impl _npos::codec::Encode for TestCompact { - fn encode(&self) -> Vec { - let mut r = ::alloc::vec::Vec::new(); - let votes1 = self - .votes1 - .iter() - .map(|(v, t)| { - ( - _npos::codec::Compact(v.clone()), - _npos::codec::Compact(t.clone()), - ) - }) - .collect::>(); - votes1.encode_to(&mut r); - let votes2 = self - .votes2 - .iter() - .map(|(v, (t1, w), t2)| { - ( - _npos::codec::Compact(v.clone()), - ( - _npos::codec::Compact(t1.clone()), - _npos::codec::Compact(w.clone()), - ), - _npos::codec::Compact(t2.clone()), - ) - }) - .collect::>(); - votes2.encode_to(&mut r); - let votes3 = self - .votes3 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes3.encode_to(&mut r); - let votes4 = self - .votes4 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes4.encode_to(&mut r); - let votes5 = self - .votes5 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes5.encode_to(&mut r); - let votes6 = self - .votes6 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes6.encode_to(&mut r); - let votes7 = self - .votes7 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes7.encode_to(&mut r); - let votes8 = self - .votes8 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes8.encode_to(&mut r); - let votes9 = self - .votes9 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes9.encode_to(&mut r); - let votes10 = self - .votes10 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes10.encode_to(&mut r); - let votes11 = self - .votes11 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes11.encode_to(&mut r); - let votes12 = self - .votes12 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes12.encode_to(&mut r); - let votes13 = self - .votes13 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes13.encode_to(&mut r); - let votes14 = self - .votes14 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[12usize].0.clone()), - _npos::codec::Compact(inner[12usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes14.encode_to(&mut r); - let votes15 = self - .votes15 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[12usize].0.clone()), - _npos::codec::Compact(inner[12usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[13usize].0.clone()), - _npos::codec::Compact(inner[13usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes15.encode_to(&mut r); - let votes16 = self - .votes16 - .iter() - .map(|(v, inner, t_last)| { - ( - _npos::codec::Compact(v.clone()), - [ - ( - _npos::codec::Compact(inner[0usize].0.clone()), - _npos::codec::Compact(inner[0usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[1usize].0.clone()), - _npos::codec::Compact(inner[1usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[2usize].0.clone()), - _npos::codec::Compact(inner[2usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[3usize].0.clone()), - _npos::codec::Compact(inner[3usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[4usize].0.clone()), - _npos::codec::Compact(inner[4usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[5usize].0.clone()), - _npos::codec::Compact(inner[5usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[6usize].0.clone()), - _npos::codec::Compact(inner[6usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[7usize].0.clone()), - _npos::codec::Compact(inner[7usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[8usize].0.clone()), - _npos::codec::Compact(inner[8usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[9usize].0.clone()), - _npos::codec::Compact(inner[9usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[10usize].0.clone()), - _npos::codec::Compact(inner[10usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[11usize].0.clone()), - _npos::codec::Compact(inner[11usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[12usize].0.clone()), - _npos::codec::Compact(inner[12usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[13usize].0.clone()), - _npos::codec::Compact(inner[13usize].1.clone()), - ), - ( - _npos::codec::Compact(inner[14usize].0.clone()), - _npos::codec::Compact(inner[14usize].1.clone()), - ), - ], - _npos::codec::Compact(t_last.clone()), - ) - }) - .collect::>(); - votes16.encode_to(&mut r); - r - } - } - impl _npos::codec::Decode for TestCompact { - fn decode(value: &mut I) -> Result { - let votes1 = < Vec < ( _npos :: codec :: Compact < u32 > , _npos :: codec :: Compact < u16 > ) > as _npos :: codec :: Decode > :: decode ( value ) ? ; - let votes1 = votes1 - .into_iter() - .map(|(v, t)| (v.0, t.0)) - .collect::>(); - let votes2 = , - (_npos::codec::Compact, _npos::codec::Compact), - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes2 = votes2 - .into_iter() - .map(|(v, (t1, w), t2)| (v.0, (t1.0, w.0), t2.0)) - .collect::>(); - let votes3 = , - [(_npos::codec::Compact, _npos::codec::Compact); 3usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes3 = votes3 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes4 = , - [(_npos::codec::Compact, _npos::codec::Compact); 4usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes4 = votes4 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes5 = , - [(_npos::codec::Compact, _npos::codec::Compact); 5usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes5 = votes5 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes6 = , - [(_npos::codec::Compact, _npos::codec::Compact); 6usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes6 = votes6 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes7 = , - [(_npos::codec::Compact, _npos::codec::Compact); 7usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes7 = votes7 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes8 = , - [(_npos::codec::Compact, _npos::codec::Compact); 8usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes8 = votes8 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes9 = , - [(_npos::codec::Compact, _npos::codec::Compact); 9usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes9 = votes9 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes10 = , - [(_npos::codec::Compact, _npos::codec::Compact); 10usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes10 = votes10 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes11 = , - [(_npos::codec::Compact, _npos::codec::Compact); 11usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes11 = votes11 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes12 = , - [(_npos::codec::Compact, _npos::codec::Compact); 12usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes12 = votes12 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes13 = , - [(_npos::codec::Compact, _npos::codec::Compact); 13usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes13 = votes13 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes14 = , - [(_npos::codec::Compact, _npos::codec::Compact); 14usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes14 = votes14 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ((inner[12usize].0).0, (inner[12usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes15 = , - [(_npos::codec::Compact, _npos::codec::Compact); 15usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes15 = votes15 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ((inner[12usize].0).0, (inner[12usize].1).0), - ((inner[13usize].0).0, (inner[13usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - let votes16 = , - [(_npos::codec::Compact, _npos::codec::Compact); 16usize - 1], - _npos::codec::Compact, - )> as _npos::codec::Decode>::decode(value)?; - let votes16 = votes16 - .into_iter() - .map(|(v, inner, t_last)| { - ( - v.0, - [ - ((inner[0usize].0).0, (inner[0usize].1).0), - ((inner[1usize].0).0, (inner[1usize].1).0), - ((inner[2usize].0).0, (inner[2usize].1).0), - ((inner[3usize].0).0, (inner[3usize].1).0), - ((inner[4usize].0).0, (inner[4usize].1).0), - ((inner[5usize].0).0, (inner[5usize].1).0), - ((inner[6usize].0).0, (inner[6usize].1).0), - ((inner[7usize].0).0, (inner[7usize].1).0), - ((inner[8usize].0).0, (inner[8usize].1).0), - ((inner[9usize].0).0, (inner[9usize].1).0), - ((inner[10usize].0).0, (inner[10usize].1).0), - ((inner[11usize].0).0, (inner[11usize].1).0), - ((inner[12usize].0).0, (inner[12usize].1).0), - ((inner[13usize].0).0, (inner[13usize].1).0), - ((inner[14usize].0).0, (inner[14usize].1).0), - ], - t_last.0, - ) - }) - .collect::>(); - Ok(TestCompact { - votes1, - votes2, - votes3, - votes4, - votes5, - votes6, - votes7, - votes8, - votes9, - votes10, - votes11, - votes12, - votes13, - votes14, - votes15, - votes16, - }) - } - } - pub struct TestCompact { - votes1: Vec<(u32, u16)>, - votes2: Vec<(u32, (u16, PerU16), u16)>, - votes3: Vec<(u32, [(u16, PerU16); 2usize], u16)>, - votes4: Vec<(u32, [(u16, PerU16); 3usize], u16)>, - votes5: Vec<(u32, [(u16, PerU16); 4usize], u16)>, - votes6: Vec<(u32, [(u16, PerU16); 5usize], u16)>, - votes7: Vec<(u32, [(u16, PerU16); 6usize], u16)>, - votes8: Vec<(u32, [(u16, PerU16); 7usize], u16)>, - votes9: Vec<(u32, [(u16, PerU16); 8usize], u16)>, - votes10: Vec<(u32, [(u16, PerU16); 9usize], u16)>, - votes11: Vec<(u32, [(u16, PerU16); 10usize], u16)>, - votes12: Vec<(u32, [(u16, PerU16); 11usize], u16)>, - votes13: Vec<(u32, [(u16, PerU16); 12usize], u16)>, - votes14: Vec<(u32, [(u16, PerU16); 13usize], u16)>, - votes15: Vec<(u32, [(u16, PerU16); 14usize], u16)>, - votes16: Vec<(u32, [(u16, PerU16); 15usize], u16)>, - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for TestCompact { - #[inline] - fn default() -> TestCompact { - TestCompact { - votes1: ::core::default::Default::default(), - votes2: ::core::default::Default::default(), - votes3: ::core::default::Default::default(), - votes4: ::core::default::Default::default(), - votes5: ::core::default::Default::default(), - votes6: ::core::default::Default::default(), - votes7: ::core::default::Default::default(), - votes8: ::core::default::Default::default(), - votes9: ::core::default::Default::default(), - votes10: ::core::default::Default::default(), - votes11: ::core::default::Default::default(), - votes12: ::core::default::Default::default(), - votes13: ::core::default::Default::default(), - votes14: ::core::default::Default::default(), - votes15: ::core::default::Default::default(), - votes16: ::core::default::Default::default(), - } - } - } - impl ::core::marker::StructuralPartialEq for TestCompact {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for TestCompact { - #[inline] - fn eq(&self, other: &TestCompact) -> bool { - match *other { - TestCompact { - votes1: ref __self_1_0, - votes2: ref __self_1_1, - votes3: ref __self_1_2, - votes4: ref __self_1_3, - votes5: ref __self_1_4, - votes6: ref __self_1_5, - votes7: ref __self_1_6, - votes8: ref __self_1_7, - votes9: ref __self_1_8, - votes10: ref __self_1_9, - votes11: ref __self_1_10, - votes12: ref __self_1_11, - votes13: ref __self_1_12, - votes14: ref __self_1_13, - votes15: ref __self_1_14, - votes16: ref __self_1_15, - } => { - match *self { - TestCompact { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) && (*__self_0_2) == (*__self_1_2) - && (*__self_0_3) == (*__self_1_3) && (*__self_0_4) == (*__self_1_4) - && (*__self_0_5) == (*__self_1_5) && (*__self_0_6) == (*__self_1_6) - && (*__self_0_7) == (*__self_1_7) && (*__self_0_8) == (*__self_1_8) - && (*__self_0_9) == (*__self_1_9) && (*__self_0_10) - == (*__self_1_10) && (*__self_0_11) == (*__self_1_11) - && (*__self_0_12) == (*__self_1_12) && (*__self_0_13) - == (*__self_1_13) && (*__self_0_14) == (*__self_1_14) - && (*__self_0_15) == (*__self_1_15) - } - } - } - } - } - #[inline] - fn ne(&self, other: &TestCompact) -> bool { - match *other { - TestCompact { - votes1: ref __self_1_0, - votes2: ref __self_1_1, - votes3: ref __self_1_2, - votes4: ref __self_1_3, - votes5: ref __self_1_4, - votes6: ref __self_1_5, - votes7: ref __self_1_6, - votes8: ref __self_1_7, - votes9: ref __self_1_8, - votes10: ref __self_1_9, - votes11: ref __self_1_10, - votes12: ref __self_1_11, - votes13: ref __self_1_12, - votes14: ref __self_1_13, - votes15: ref __self_1_14, - votes16: ref __self_1_15, - } => { - match *self { - TestCompact { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) || (*__self_0_2) != (*__self_1_2) - || (*__self_0_3) != (*__self_1_3) || (*__self_0_4) != (*__self_1_4) - || (*__self_0_5) != (*__self_1_5) || (*__self_0_6) != (*__self_1_6) - || (*__self_0_7) != (*__self_1_7) || (*__self_0_8) != (*__self_1_8) - || (*__self_0_9) != (*__self_1_9) || (*__self_0_10) - != (*__self_1_10) || (*__self_0_11) != (*__self_1_11) - || (*__self_0_12) != (*__self_1_12) || (*__self_0_13) - != (*__self_1_13) || (*__self_0_14) != (*__self_1_14) - || (*__self_0_15) != (*__self_1_15) - } - } - } - } - } - } - impl ::core::marker::StructuralEq for TestCompact {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for TestCompact { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq>; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for TestCompact { - #[inline] - fn clone(&self) -> TestCompact { - match *self { - TestCompact { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => TestCompact { - votes1: ::core::clone::Clone::clone(&(*__self_0_0)), - votes2: ::core::clone::Clone::clone(&(*__self_0_1)), - votes3: ::core::clone::Clone::clone(&(*__self_0_2)), - votes4: ::core::clone::Clone::clone(&(*__self_0_3)), - votes5: ::core::clone::Clone::clone(&(*__self_0_4)), - votes6: ::core::clone::Clone::clone(&(*__self_0_5)), - votes7: ::core::clone::Clone::clone(&(*__self_0_6)), - votes8: ::core::clone::Clone::clone(&(*__self_0_7)), - votes9: ::core::clone::Clone::clone(&(*__self_0_8)), - votes10: ::core::clone::Clone::clone(&(*__self_0_9)), - votes11: ::core::clone::Clone::clone(&(*__self_0_10)), - votes12: ::core::clone::Clone::clone(&(*__self_0_11)), - votes13: ::core::clone::Clone::clone(&(*__self_0_12)), - votes14: ::core::clone::Clone::clone(&(*__self_0_13)), - votes15: ::core::clone::Clone::clone(&(*__self_0_14)), - votes16: ::core::clone::Clone::clone(&(*__self_0_15)), - }, - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::fmt::Debug for TestCompact { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - match *self { - TestCompact { - votes1: ref __self_0_0, - votes2: ref __self_0_1, - votes3: ref __self_0_2, - votes4: ref __self_0_3, - votes5: ref __self_0_4, - votes6: ref __self_0_5, - votes7: ref __self_0_6, - votes8: ref __self_0_7, - votes9: ref __self_0_8, - votes10: ref __self_0_9, - votes11: ref __self_0_10, - votes12: ref __self_0_11, - votes13: ref __self_0_12, - votes14: ref __self_0_13, - votes15: ref __self_0_14, - votes16: ref __self_0_15, - } => { - let mut debug_trait_builder = f.debug_struct("TestCompact"); - let _ = debug_trait_builder.field("votes1", &&(*__self_0_0)); - let _ = debug_trait_builder.field("votes2", &&(*__self_0_1)); - let _ = debug_trait_builder.field("votes3", &&(*__self_0_2)); - let _ = debug_trait_builder.field("votes4", &&(*__self_0_3)); - let _ = debug_trait_builder.field("votes5", &&(*__self_0_4)); - let _ = debug_trait_builder.field("votes6", &&(*__self_0_5)); - let _ = debug_trait_builder.field("votes7", &&(*__self_0_6)); - let _ = debug_trait_builder.field("votes8", &&(*__self_0_7)); - let _ = debug_trait_builder.field("votes9", &&(*__self_0_8)); - let _ = debug_trait_builder.field("votes10", &&(*__self_0_9)); - let _ = debug_trait_builder.field("votes11", &&(*__self_0_10)); - let _ = debug_trait_builder.field("votes12", &&(*__self_0_11)); - let _ = debug_trait_builder.field("votes13", &&(*__self_0_12)); - let _ = debug_trait_builder.field("votes14", &&(*__self_0_13)); - let _ = debug_trait_builder.field("votes15", &&(*__self_0_14)); - let _ = debug_trait_builder.field("votes16", &&(*__self_0_15)); - debug_trait_builder.finish() - } - } - } - } - use _npos::__OrInvalidIndex; - impl _npos::CompactSolution for TestCompact { - const LIMIT: usize = 16usize; - type Voter = u32; - type Target = u16; - type VoteWeight = PerU16; - fn len(&self) -> usize { - let mut all_len = 0usize; - all_len = all_len.saturating_add(self.votes1.len()); - all_len = all_len.saturating_add(self.votes2.len()); - all_len = all_len.saturating_add(self.votes3.len()); - all_len = all_len.saturating_add(self.votes4.len()); - all_len = all_len.saturating_add(self.votes5.len()); - all_len = all_len.saturating_add(self.votes6.len()); - all_len = all_len.saturating_add(self.votes7.len()); - all_len = all_len.saturating_add(self.votes8.len()); - all_len = all_len.saturating_add(self.votes9.len()); - all_len = all_len.saturating_add(self.votes10.len()); - all_len = all_len.saturating_add(self.votes11.len()); - all_len = all_len.saturating_add(self.votes12.len()); - all_len = all_len.saturating_add(self.votes13.len()); - all_len = all_len.saturating_add(self.votes14.len()); - all_len = all_len.saturating_add(self.votes15.len()); - all_len = all_len.saturating_add(self.votes16.len()); - all_len - } - fn edge_count(&self) -> usize { - let mut all_edges = 0usize; - all_edges = - all_edges.saturating_add(self.votes1.len().saturating_mul(1usize as usize)); - all_edges = - all_edges.saturating_add(self.votes2.len().saturating_mul(2usize as usize)); - all_edges = - all_edges.saturating_add(self.votes3.len().saturating_mul(3usize as usize)); - all_edges = - all_edges.saturating_add(self.votes4.len().saturating_mul(4usize as usize)); - all_edges = - all_edges.saturating_add(self.votes5.len().saturating_mul(5usize as usize)); - all_edges = - all_edges.saturating_add(self.votes6.len().saturating_mul(6usize as usize)); - all_edges = - all_edges.saturating_add(self.votes7.len().saturating_mul(7usize as usize)); - all_edges = - all_edges.saturating_add(self.votes8.len().saturating_mul(8usize as usize)); - all_edges = - all_edges.saturating_add(self.votes9.len().saturating_mul(9usize as usize)); - all_edges = - all_edges.saturating_add(self.votes10.len().saturating_mul(10usize as usize)); - all_edges = - all_edges.saturating_add(self.votes11.len().saturating_mul(11usize as usize)); - all_edges = - all_edges.saturating_add(self.votes12.len().saturating_mul(12usize as usize)); - all_edges = - all_edges.saturating_add(self.votes13.len().saturating_mul(13usize as usize)); - all_edges = - all_edges.saturating_add(self.votes14.len().saturating_mul(14usize as usize)); - all_edges = - all_edges.saturating_add(self.votes15.len().saturating_mul(15usize as usize)); - all_edges = - all_edges.saturating_add(self.votes16.len().saturating_mul(16usize as usize)); - all_edges - } - fn unique_targets(&self) -> Vec { - let mut all_targets: Vec = - Vec::with_capacity(self.average_edge_count()); - let mut maybe_insert_target = |t: Self::Target| match all_targets.binary_search(&t) - { - Ok(_) => (), - Err(pos) => all_targets.insert(pos, t), - }; - self.votes1.iter().for_each(|(_, t)| { - maybe_insert_target(*t); - }); - self.votes2.iter().for_each(|(_, (t1, _), t2)| { - maybe_insert_target(*t1); - maybe_insert_target(*t2); - }); - self.votes3.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes4.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes5.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes6.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes7.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes8.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes9.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes10.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes11.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes12.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes13.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes14.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes15.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - self.votes16.iter().for_each(|(_, inners, t_last)| { - inners.iter().for_each(|(t, _)| { - maybe_insert_target(*t); - }); - maybe_insert_target(*t_last); - }); - all_targets - } - fn remove_voter(&mut self, to_remove: Self::Voter) -> bool { - if let Some(idx) = self.votes1.iter().position(|(x, _)| *x == to_remove) { - self.votes1.remove(idx); - return true; - } - if let Some(idx) = self.votes2.iter().position(|(x, _, _)| *x == to_remove) { - self.votes2.remove(idx); - return true; - } - if let Some(idx) = self.votes3.iter().position(|(x, _, _)| *x == to_remove) { - self.votes3.remove(idx); - return true; - } - if let Some(idx) = self.votes4.iter().position(|(x, _, _)| *x == to_remove) { - self.votes4.remove(idx); - return true; - } - if let Some(idx) = self.votes5.iter().position(|(x, _, _)| *x == to_remove) { - self.votes5.remove(idx); - return true; - } - if let Some(idx) = self.votes6.iter().position(|(x, _, _)| *x == to_remove) { - self.votes6.remove(idx); - return true; - } - if let Some(idx) = self.votes7.iter().position(|(x, _, _)| *x == to_remove) { - self.votes7.remove(idx); - return true; - } - if let Some(idx) = self.votes8.iter().position(|(x, _, _)| *x == to_remove) { - self.votes8.remove(idx); - return true; - } - if let Some(idx) = self.votes9.iter().position(|(x, _, _)| *x == to_remove) { - self.votes9.remove(idx); - return true; - } - if let Some(idx) = self.votes10.iter().position(|(x, _, _)| *x == to_remove) { - self.votes10.remove(idx); - return true; - } - if let Some(idx) = self.votes11.iter().position(|(x, _, _)| *x == to_remove) { - self.votes11.remove(idx); - return true; - } - if let Some(idx) = self.votes12.iter().position(|(x, _, _)| *x == to_remove) { - self.votes12.remove(idx); - return true; - } - if let Some(idx) = self.votes13.iter().position(|(x, _, _)| *x == to_remove) { - self.votes13.remove(idx); - return true; - } - if let Some(idx) = self.votes14.iter().position(|(x, _, _)| *x == to_remove) { - self.votes14.remove(idx); - return true; - } - if let Some(idx) = self.votes15.iter().position(|(x, _, _)| *x == to_remove) { - self.votes15.remove(idx); - return true; - } - if let Some(idx) = self.votes16.iter().position(|(x, _, _)| *x == to_remove) { - self.votes16.remove(idx); - return true; - } - return false; - } - fn from_assignment( - assignments: Vec<_npos::Assignment>, - index_of_voter: FV, - index_of_target: FT, - ) -> Result - where - A: _npos::IdentifierT, - for<'r> FV: Fn(&'r A) -> Option, - for<'r> FT: Fn(&'r A) -> Option, - { - let mut compact: TestCompact = Default::default(); - for _npos::Assignment { who, distribution } in assignments { - match distribution.len() { - 0 => continue, - 1 => compact.votes1.push(( - index_of_voter(&who).or_invalid_index()?, - index_of_target(&distribution[0].0).or_invalid_index()?, - )), - 2 => compact.votes2.push(( - index_of_voter(&who).or_invalid_index()?, - ( - index_of_target(&distribution[0].0).or_invalid_index()?, - distribution[0].1, - ), - index_of_target(&distribution[1].0).or_invalid_index()?, - )), - 3usize => compact.votes3.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ], - index_of_target(&distribution[2usize].0).or_invalid_index()?, - )), - 4usize => compact.votes4.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ], - index_of_target(&distribution[3usize].0).or_invalid_index()?, - )), - 5usize => compact.votes5.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ], - index_of_target(&distribution[4usize].0).or_invalid_index()?, - )), - 6usize => compact.votes6.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ], - index_of_target(&distribution[5usize].0).or_invalid_index()?, - )), - 7usize => compact.votes7.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ], - index_of_target(&distribution[6usize].0).or_invalid_index()?, - )), - 8usize => compact.votes8.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ], - index_of_target(&distribution[7usize].0).or_invalid_index()?, - )), - 9usize => compact.votes9.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ], - index_of_target(&distribution[8usize].0).or_invalid_index()?, - )), - 10usize => compact.votes10.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ], - index_of_target(&distribution[9usize].0).or_invalid_index()?, - )), - 11usize => compact.votes11.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ], - index_of_target(&distribution[10usize].0).or_invalid_index()?, - )), - 12usize => compact.votes12.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ], - index_of_target(&distribution[11usize].0).or_invalid_index()?, - )), - 13usize => compact.votes13.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), - ], - index_of_target(&distribution[12usize].0).or_invalid_index()?, - )), - 14usize => compact.votes14.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), - ( - index_of_target(&distribution[12usize].0).or_invalid_index()?, - distribution[12usize].1, - ), - ], - index_of_target(&distribution[13usize].0).or_invalid_index()?, - )), - 15usize => compact.votes15.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), - ( - index_of_target(&distribution[12usize].0).or_invalid_index()?, - distribution[12usize].1, - ), - ( - index_of_target(&distribution[13usize].0).or_invalid_index()?, - distribution[13usize].1, - ), - ], - index_of_target(&distribution[14usize].0).or_invalid_index()?, - )), - 16usize => compact.votes16.push(( - index_of_voter(&who).or_invalid_index()?, - [ - ( - index_of_target(&distribution[0usize].0).or_invalid_index()?, - distribution[0usize].1, - ), - ( - index_of_target(&distribution[1usize].0).or_invalid_index()?, - distribution[1usize].1, - ), - ( - index_of_target(&distribution[2usize].0).or_invalid_index()?, - distribution[2usize].1, - ), - ( - index_of_target(&distribution[3usize].0).or_invalid_index()?, - distribution[3usize].1, - ), - ( - index_of_target(&distribution[4usize].0).or_invalid_index()?, - distribution[4usize].1, - ), - ( - index_of_target(&distribution[5usize].0).or_invalid_index()?, - distribution[5usize].1, - ), - ( - index_of_target(&distribution[6usize].0).or_invalid_index()?, - distribution[6usize].1, - ), - ( - index_of_target(&distribution[7usize].0).or_invalid_index()?, - distribution[7usize].1, - ), - ( - index_of_target(&distribution[8usize].0).or_invalid_index()?, - distribution[8usize].1, - ), - ( - index_of_target(&distribution[9usize].0).or_invalid_index()?, - distribution[9usize].1, - ), - ( - index_of_target(&distribution[10usize].0).or_invalid_index()?, - distribution[10usize].1, - ), - ( - index_of_target(&distribution[11usize].0).or_invalid_index()?, - distribution[11usize].1, - ), - ( - index_of_target(&distribution[12usize].0).or_invalid_index()?, - distribution[12usize].1, - ), - ( - index_of_target(&distribution[13usize].0).or_invalid_index()?, - distribution[13usize].1, - ), - ( - index_of_target(&distribution[14usize].0).or_invalid_index()?, - distribution[14usize].1, - ), - ], - index_of_target(&distribution[15usize].0).or_invalid_index()?, - )), - _ => { - return Err(_npos::Error::CompactTargetOverflow); - } - } - } - Ok(compact) - } - fn into_assignment( - self, - voter_at: impl Fn(Self::Voter) -> Option, - target_at: impl Fn(Self::Target) -> Option, - ) -> Result>, _npos::Error> { - let mut assignments: Vec<_npos::Assignment> = Default::default(); - for (voter_index, target_index) in self.votes1 { - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: <[_]>::into_vec(box [( - target_at(target_index).or_invalid_index()?, - PerU16::one(), - )]), - }) - } - for (voter_index, (t1_idx, p1), t2_idx) in self.votes2 { - if p1 >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p2 = - _npos::sp_arithmetic::traits::Saturating::saturating_sub(PerU16::one(), p1); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: <[_]>::into_vec(box [ - (target_at(t1_idx).or_invalid_index()?, p1), - (target_at(t2_idx).or_invalid_index()?, p2), - ]), - }); - } - for (voter_index, inners, t_last_idx) in self.votes3 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes4 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes5 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes6 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes7 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes8 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes9 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes10 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes11 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes12 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes13 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes14 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes15 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - for (voter_index, inners, t_last_idx) in self.votes16 { - let mut sum = PerU16::zero(); - let mut inners_parsed = inners - .iter() - .map(|(ref t_idx, p)| { - sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p); - let target = target_at(*t_idx).or_invalid_index()?; - Ok((target, *p)) - }) - .collect::, _npos::Error>>()?; - if sum >= PerU16::one() { - return Err(_npos::Error::CompactStakeOverflow); - } - let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub( - PerU16::one(), - sum, - ); - inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last)); - assignments.push(_npos::Assignment { - who: voter_at(voter_index).or_invalid_index()?, - distribution: inners_parsed, - }); - } - Ok(assignments) - } - } - /// To from `now` to block `n`. - pub fn roll_to(n: u64) { - let now = System::block_number(); - for i in now + 1..=n { - System::set_block_number(i); - TwoPhase::on_initialize(i); - } - } - /// Get the free and reserved balance of some account. - pub fn balances(who: &AccountId) -> (Balance, Balance) { - (Balances::free_balance(who), Balances::reserved_balance(who)) - } - /// Spit out a verifiable raw solution. - /// - /// This is a good example of what an offchain miner would do. - pub fn raw_solution() -> RawSolution> { - let voters = TwoPhase::snapshot_voters().unwrap(); - let targets = TwoPhase::snapshot_targets().unwrap(); - let desired = TwoPhase::desired_targets() as usize; - let voter_index = - |who: &AccountId| -> Option> { - voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < Runtime > > > :: try_into ( i ) . ok ( ) ) - }; - let target_index = - |who: &AccountId| -> Option> { - targets . iter ( ) . position ( | x | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactTargetIndexOf < Runtime > > > :: try_into ( i ) . ok ( ) ) - }; - let stake_of = |who: &AccountId| -> crate::VoteWeight { - voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - }; - let ElectionResult { - winners, - assignments, - } = seq_phragmen::<_, CompactAccuracyOf>( - desired, - targets.clone(), - voters.clone(), - None, - ) - .unwrap(); - let winners = to_without_backing(winners); - let score = { - let staked = - assignment_ratio_to_staked_normalized(assignments.clone(), &stake_of).unwrap(); - to_supports(&winners, &staked).unwrap().evaluate() - }; - let compact = - >::from_assignment(assignments, &voter_index, &target_index) - .unwrap(); - RawSolution { compact, score } - } - /// Creates a **valid** solution with exactly the given size. - /// - /// The snapshot size must be bigger, otherwise this will panic. - pub fn solution_with_size( - active_voters: u32, - winners_count: u32, - ) -> RawSolution> { - use rand::seq::SliceRandom; - let voters = TwoPhase::snapshot_voters().unwrap(); - let targets = TwoPhase::snapshot_targets().unwrap(); - if !(active_voters >= winners_count) { - { - ::std::rt::begin_panic("assertion failed: active_voters >= winners_count") - } - }; - if !(voters.len() >= active_voters as usize) { - { - ::std::rt::begin_panic( - "assertion failed: voters.len() >= active_voters as usize", - ) - } - }; - if !(targets.len() >= winners_count as usize) { - { - ::std::rt::begin_panic( - "assertion failed: targets.len() >= winners_count as usize", - ) - } - }; - let voter_index = - |who: &AccountId| -> Option> { - voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < Runtime > > > :: try_into ( i ) . ok ( ) ) - }; - let voter_at = - |i: crate::two_phase::CompactVoterIndexOf| -> Option { - < crate :: two_phase :: CompactVoterIndexOf < Runtime > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | voters . get ( i ) . map ( | ( x , _ , _ ) | x ) . cloned ( ) ) - }; - let target_at = - |i: crate::two_phase::CompactTargetIndexOf| -> Option { - < crate :: two_phase :: CompactTargetIndexOf < Runtime > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | targets . get ( i ) . cloned ( ) ) - }; - let stake_of = |who: &AccountId| -> crate::VoteWeight { - voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - }; - let mut rng = rand::thread_rng(); - let winners = targets - .as_slice() - .choose_multiple(&mut rng, winners_count as usize) - .cloned() - .collect::>(); - let mut assignments = winners - .iter() - .map(|w| sp_npos_elections::Assignment { - who: w, - distribution: <[_]>::into_vec(box [(w, PerU16::one())]), - }) - .collect::>(); - let mut voters_pool = voters - .iter() - .filter(|(x, _, z)| *x != z[0]) - .cloned() - .collect::>(); - while assignments.len() < active_voters as usize { - let voter = voters_pool.remove(rand::random::() % voters_pool.len()); - } - { - ::std::rt::begin_panic("not implemented") - } - } - pub enum OuterCall { - TwoPhase(::frame_support::dispatch::CallableCallFor), - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for OuterCall { - #[inline] - fn clone(&self) -> OuterCall { - match (&*self,) { - (&OuterCall::TwoPhase(ref __self_0),) => { - OuterCall::TwoPhase(::core::clone::Clone::clone(&(*__self_0))) - } - } - } - } - impl ::core::marker::StructuralPartialEq for OuterCall {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for OuterCall { - #[inline] - fn eq(&self, other: &OuterCall) -> bool { - match (&*self, &*other) { - (&OuterCall::TwoPhase(ref __self_0), &OuterCall::TwoPhase(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - } - } - #[inline] - fn ne(&self, other: &OuterCall) -> bool { - match (&*self, &*other) { - (&OuterCall::TwoPhase(ref __self_0), &OuterCall::TwoPhase(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - } - } - } - impl ::core::marker::StructuralEq for OuterCall {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for OuterCall { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq< - ::frame_support::dispatch::CallableCallFor, - >; - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for OuterCall { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - OuterCall::TwoPhase(ref aa) => { - dest.push_byte(0usize as u8); - dest.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for OuterCall {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for OuterCall { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(OuterCall::TwoPhase({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err( - "Error decoding field OuterCall :: TwoPhase.0".into() - ) - } - Ok(a) => a, - } - })), - x => Err("No such variant in enum OuterCall".into()), - } - } - } - }; - impl core::fmt::Debug for OuterCall { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::TwoPhase(ref a0) => { - fmt.debug_tuple("OuterCall::TwoPhase").field(a0).finish() - } - _ => Ok(()), - } - } - } - impl ::frame_support::dispatch::GetDispatchInfo for OuterCall { - fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { - match self { - OuterCall::TwoPhase(call) => call.get_dispatch_info(), - } - } - } - impl ::frame_support::dispatch::GetCallMetadata for OuterCall { - fn get_call_metadata(&self) -> ::frame_support::dispatch::CallMetadata { - use ::frame_support::dispatch::GetCallName; - match self { - OuterCall::TwoPhase(call) => { - let function_name = call.get_call_name(); - let pallet_name = "TwoPhase"; - ::frame_support::dispatch::CallMetadata { - function_name, - pallet_name, - } - } - } - } - fn get_module_names() -> &'static [&'static str] { - &["TwoPhase"] - } - fn get_call_names(module: &str) -> &'static [&'static str] { - use ::frame_support::dispatch::{Callable, GetCallName}; - match module { - "TwoPhase" => { - <>::Call as GetCallName>::get_call_names() - } - _ => ::std::rt::begin_panic("internal error: entered unreachable code"), - } - } - } - impl ::frame_support::dispatch::Dispatchable for OuterCall { - type Origin = Origin; - type Trait = OuterCall; - type Info = ::frame_support::weights::DispatchInfo; - type PostInfo = ::frame_support::weights::PostDispatchInfo; - fn dispatch( - self, - origin: Origin, - ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { - if !::filter_call( - &origin, &self, - ) { - return ::frame_support::sp_std::result::Result::Err( - ::frame_support::dispatch::DispatchError::BadOrigin.into(), - ); - } - ::frame_support::traits::UnfilteredDispatchable::dispatch_bypass_filter( - self, origin, - ) - } - } - impl ::frame_support::traits::UnfilteredDispatchable for OuterCall { - type Origin = Origin; - fn dispatch_bypass_filter( - self, - origin: Origin, - ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { - match self { - OuterCall::TwoPhase(call) => { - ::frame_support::traits::UnfilteredDispatchable::dispatch_bypass_filter( - call, origin, - ) - } - } - } - } - impl - ::frame_support::dispatch::IsSubType< - ::frame_support::dispatch::CallableCallFor, - > for OuterCall - { - #[allow(unreachable_patterns)] - fn is_sub_type( - &self, - ) -> Option<&::frame_support::dispatch::CallableCallFor> { - match *self { - OuterCall::TwoPhase(ref r) => Some(r), - _ => None, - } - } - } - impl From<::frame_support::dispatch::CallableCallFor> for OuterCall { - fn from(call: ::frame_support::dispatch::CallableCallFor) -> Self { - OuterCall::TwoPhase(call) - } - } - pub struct Origin { - caller: OriginCaller, - filter: ::frame_support::sp_std::rc::Rc< - Box::Call) -> bool>, - >, - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Origin { - #[inline] - fn clone(&self) -> Origin { - match *self { - Origin { - caller: ref __self_0_0, - filter: ref __self_0_1, - } => Origin { - caller: ::core::clone::Clone::clone(&(*__self_0_0)), - filter: ::core::clone::Clone::clone(&(*__self_0_1)), - }, - } - } - } - #[cfg(feature = "std")] - impl ::frame_support::sp_std::fmt::Debug for Origin { - fn fmt( - &self, - fmt: &mut ::frame_support::sp_std::fmt::Formatter, - ) -> ::frame_support::sp_std::result::Result<(), ::frame_support::sp_std::fmt::Error> { - fmt.debug_struct("Origin") - .field("caller", &self.caller) - .field("filter", &"[function ptr]") - .finish() - } - } - impl ::frame_support::traits::OriginTrait for Origin { - type Call = ::Call; - type PalletsOrigin = OriginCaller; - type AccountId = ::AccountId; - fn add_filter(&mut self, filter: impl Fn(&Self::Call) -> bool + 'static) { - let f = self.filter.clone(); - self.filter = ::frame_support::sp_std::rc::Rc::new(Box::new(move |call| { - f(call) && filter(call) - })); - } - fn reset_filter(&mut self) { - let filter = < < Runtime as frame_system :: Trait > :: BaseCallFilter as :: frame_support :: traits :: Filter < < Runtime as frame_system :: Trait > :: Call > > :: filter ; - self.filter = ::frame_support::sp_std::rc::Rc::new(Box::new(filter)); - } - fn set_caller_from(&mut self, other: impl Into) { - self.caller = other.into().caller - } - fn filter_call(&self, call: &Self::Call) -> bool { - (self.filter)(call) - } - fn caller(&self) -> &Self::PalletsOrigin { - &self.caller - } - /// Create with system none origin and `frame-system::Trait::BaseCallFilter`. - fn none() -> Self { - frame_system::RawOrigin::None.into() - } - /// Create with system root origin and no filter. - fn root() -> Self { - frame_system::RawOrigin::Root.into() - } - /// Create with system signed origin and `frame-system::Trait::BaseCallFilter`. - fn signed(by: ::AccountId) -> Self { - frame_system::RawOrigin::Signed(by).into() - } - } - #[allow(non_camel_case_types)] - pub enum OriginCaller { - system(frame_system::Origin), - #[allow(dead_code)] - Void(::frame_support::Void), - } - #[automatically_derived] - #[allow(unused_qualifications)] - #[allow(non_camel_case_types)] - impl ::core::clone::Clone for OriginCaller { - #[inline] - fn clone(&self) -> OriginCaller { - match (&*self,) { - (&OriginCaller::system(ref __self_0),) => { - OriginCaller::system(::core::clone::Clone::clone(&(*__self_0))) - } - (&OriginCaller::Void(ref __self_0),) => { - OriginCaller::Void(::core::clone::Clone::clone(&(*__self_0))) - } - } - } - } - #[allow(non_camel_case_types)] - impl ::core::marker::StructuralPartialEq for OriginCaller {} - #[automatically_derived] - #[allow(unused_qualifications)] - #[allow(non_camel_case_types)] - impl ::core::cmp::PartialEq for OriginCaller { - #[inline] - fn eq(&self, other: &OriginCaller) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &OriginCaller::system(ref __self_0), - &OriginCaller::system(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - ( - &OriginCaller::Void(ref __self_0), - &OriginCaller::Void(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - _ => unsafe { ::core::intrinsics::unreachable() }, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &OriginCaller) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &OriginCaller::system(ref __self_0), - &OriginCaller::system(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - ( - &OriginCaller::Void(ref __self_0), - &OriginCaller::Void(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - _ => unsafe { ::core::intrinsics::unreachable() }, - } - } else { - true - } - } - } - } - #[allow(non_camel_case_types)] - impl ::core::marker::StructuralEq for OriginCaller {} - #[automatically_derived] - #[allow(unused_qualifications)] - #[allow(non_camel_case_types)] - impl ::core::cmp::Eq for OriginCaller { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq<::frame_support::Void>; - } - } - } - impl core::fmt::Debug for OriginCaller { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::system(ref a0) => { - fmt.debug_tuple("OriginCaller::system").field(a0).finish() - } - Self::Void(ref a0) => fmt.debug_tuple("OriginCaller::Void").field(a0).finish(), - _ => Ok(()), - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for OriginCaller { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - OriginCaller::system(ref aa) => { - dest.push_byte(0usize as u8); - dest.push(aa); - } - OriginCaller::Void(ref aa) => { - dest.push_byte(1usize as u8); - dest.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for OriginCaller {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for OriginCaller { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(OriginCaller::system({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err( - "Error decoding field OriginCaller :: system.0".into() - ) - } - Ok(a) => a, - } - })), - x if x == 1usize as u8 => Ok(OriginCaller::Void({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field OriginCaller :: Void.0".into()) - } - Ok(a) => a, - } - })), - x => Err("No such variant in enum OriginCaller".into()), - } - } - } - }; - #[allow(dead_code)] - impl Origin { - /// Create with system none origin and `frame-system::Trait::BaseCallFilter`. - pub fn none() -> Self { - ::none() - } - /// Create with system root origin and no filter. - pub fn root() -> Self { - ::root() - } - /// Create with system signed origin and `frame-system::Trait::BaseCallFilter`. - pub fn signed(by: ::AccountId) -> Self { - ::signed(by) - } - } - impl From> for OriginCaller { - fn from(x: frame_system::Origin) -> Self { - OriginCaller::system(x) - } - } - impl From> for Origin { - /// Convert to runtime origin: - /// * root origin is built with no filter - /// * others use `frame-system::Trait::BaseCallFilter` - fn from(x: frame_system::Origin) -> Self { - let o: OriginCaller = x.into(); - o.into() - } - } - impl From for Origin { - fn from(x: OriginCaller) -> Self { - let mut o = Origin { - caller: x, - filter: ::frame_support::sp_std::rc::Rc::new(Box::new(|_| true)), - }; - if !match o.caller { - OriginCaller::system(frame_system::Origin::::Root) => true, - _ => false, - } { - ::frame_support::traits::OriginTrait::reset_filter(&mut o); - } - o - } - } - impl Into<::frame_support::sp_std::result::Result, Origin>> - for Origin - { - /// NOTE: converting to pallet origin loses the origin filter information. - fn into( - self, - ) -> ::frame_support::sp_std::result::Result, Self> { - if let OriginCaller::system(l) = self.caller { - Ok(l) - } else { - Err(self) - } - } - } - impl From::AccountId>> for Origin { - /// Convert to runtime origin with caller being system signed or none and use filter - /// `frame-system::Trait::BaseCallFilter`. - fn from(x: Option<::AccountId>) -> Self { - >::from(x).into() - } - } - impl frame_system::Trait for Runtime { - type BaseCallFilter = (); - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Call = OuterCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type Event = (); - type BlockHashCount = (); - type MaximumBlockWeight = (); - type DbWeight = (); - type BlockExecutionWeight = (); - type ExtrinsicBaseWeight = (); - type MaximumExtrinsicWeight = (); - type MaximumBlockLength = (); - type AvailableBlockRatio = (); - type Version = (); - type PalletInfo = (); - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - } - pub struct ExistentialDeposit; - impl ExistentialDeposit { - /// Returns the value of this parameter type. - pub const fn get() -> u64 { - 1 - } - } - impl> ::frame_support::traits::Get for ExistentialDeposit { - fn get() -> I { - I::from(1) - } - } - impl pallet_balances::Trait for Runtime { - type Balance = Balance; - type Event = (); - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type MaxLocks = (); - type WeightInfo = (); - } - use paste::paste; - const SIGNED_PHASE: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(10) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const UNSIGNED_PHASE: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(5) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const MAX_SIGNED_SUBMISSIONS: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(5) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const TARGETS: ::std::thread::LocalKey>> = { - #[inline] - fn __init() -> RefCell> { - RefCell::new(<[_]>::into_vec(box [10, 20, 30, 40])) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell>> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner>> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const VOTERS: ::std::thread::LocalKey< - RefCell)>>, - > = { - #[inline] - fn __init() -> RefCell)>> { - RefCell::new(<[_]>::into_vec(box [ - (1, 10, <[_]>::into_vec(box [10, 20])), - (2, 10, <[_]>::into_vec(box [30, 40])), - (3, 10, <[_]>::into_vec(box [40])), - (4, 10, <[_]>::into_vec(box [10, 20, 30, 40])), - (10, 10, <[_]>::into_vec(box [10])), - (20, 20, <[_]>::into_vec(box [20])), - (30, 30, <[_]>::into_vec(box [30])), - (40, 40, <[_]>::into_vec(box [40])), - ])) - } - unsafe fn __getit( - ) -> ::std::option::Option<&'static RefCell)>>> - { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner< - RefCell)>>, - > = ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const DESIRED_TARGETS: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(2) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const SIGNED_DEPOSIT_BASE: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(5) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const SIGNED_REWARD_BASE: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(7) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const MAX_UNSIGNED_ITERATIONS: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(5) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const UNSIGNED_PRIORITY: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(100) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - const SOLUTION_IMPROVEMENT_THRESHOLD: ::std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(Perbill::zero()) - } - unsafe fn __getit() -> ::std::option::Option<&'static RefCell> { - #[thread_local] - #[cfg(all( - target_thread_local, - not(all(target_arch = "wasm32", not(target_feature = "atomics"))), - ))] - static __KEY: ::std::thread::__FastLocalKeyInner> = - ::std::thread::__FastLocalKeyInner::new(); - #[allow(unused_unsafe)] - unsafe { - __KEY.get(__init) - } - } - unsafe { ::std::thread::LocalKey::new(__getit) } - }; - pub struct SignedPhase; - impl Get for SignedPhase { - fn get() -> u64 { - SIGNED_PHASE.with(|v| v.borrow().clone()) - } - } - pub struct UnsignedPhase; - impl Get for UnsignedPhase { - fn get() -> u64 { - UNSIGNED_PHASE.with(|v| v.borrow().clone()) - } - } - pub struct MaxSignedSubmissions; - impl Get for MaxSignedSubmissions { - fn get() -> u32 { - MAX_SIGNED_SUBMISSIONS.with(|v| v.borrow().clone()) - } - } - pub struct Targets; - impl Get> for Targets { - fn get() -> Vec { - TARGETS.with(|v| v.borrow().clone()) - } - } - pub struct Voters; - impl Get)>> for Voters { - fn get() -> Vec<(AccountId, VoteWeight, Vec)> { - VOTERS.with(|v| v.borrow().clone()) - } - } - pub struct DesiredTargets; - impl Get for DesiredTargets { - fn get() -> u32 { - DESIRED_TARGETS.with(|v| v.borrow().clone()) - } - } - pub struct SignedDepositBase; - impl Get for SignedDepositBase { - fn get() -> Balance { - SIGNED_DEPOSIT_BASE.with(|v| v.borrow().clone()) - } - } - pub struct SignedRewardBase; - impl Get for SignedRewardBase { - fn get() -> Balance { - SIGNED_REWARD_BASE.with(|v| v.borrow().clone()) - } - } - pub struct MaxUnsignedIterations; - impl Get for MaxUnsignedIterations { - fn get() -> u32 { - MAX_UNSIGNED_ITERATIONS.with(|v| v.borrow().clone()) - } - } - pub struct UnsignedPriority; - impl Get for UnsignedPriority { - fn get() -> u64 { - UNSIGNED_PRIORITY.with(|v| v.borrow().clone()) - } - } - pub struct SolutionImprovementThreshold; - impl Get for SolutionImprovementThreshold { - fn get() -> Perbill { - SOLUTION_IMPROVEMENT_THRESHOLD.with(|v| v.borrow().clone()) - } - } - impl crate::two_phase::Trait for Runtime { - type Event = (); - type Currency = Balances; - type SignedPhase = SignedPhase; - type UnsignedPhase = UnsignedPhase; - type MaxSignedSubmissions = MaxSignedSubmissions; - type SignedRewardBase = SignedRewardBase; - type SignedRewardFactor = (); - type SignedRewardMax = (); - type SignedDepositBase = SignedDepositBase; - type SignedDepositByte = (); - type SignedDepositWeight = (); - type SolutionImprovementThreshold = SolutionImprovementThreshold; - type SlashHandler = (); - type RewardHandler = (); - type UnsignedMaxIterations = MaxUnsignedIterations; - type UnsignedPriority = UnsignedPriority; - type ElectionDataProvider = StakingMock; - type WeightInfo = (); - } - impl frame_system::offchain::SendTransactionTypes for Runtime - where - OuterCall: From, - { - type OverarchingCall = OuterCall; - type Extrinsic = Extrinsic; - } - pub type Extrinsic = sp_runtime::testing::TestXt; - pub struct ExtBuilder {} - impl Default for ExtBuilder { - fn default() -> Self { - Self {} - } - } - pub struct StakingMock; - impl ElectionDataProvider for StakingMock { - type CompactSolution = TestCompact; - fn targets() -> Vec { - Targets::get() - } - fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { - Voters::get() - } - fn desired_targets() -> u32 { - DesiredTargets::get() - } - fn feasibility_check_assignment( - _: &AccountId, - _: &[(AccountId, P)], - ) -> bool { - true - } - fn next_election_prediction(now: u64) -> u64 { - now + 20 - now % 20 - } - } - impl ExtBuilder { - pub fn max_signed_submission(self, count: u32) -> Self { - MAX_SIGNED_SUBMISSIONS.with(|v| *v.borrow_mut() = count); - self - } - pub fn unsigned_priority(self, p: u64) -> Self { - UNSIGNED_PRIORITY.with(|v| *v.borrow_mut() = p); - self - } - pub fn solution_improvement_threshold(self, p: Perbill) -> Self { - SOLUTION_IMPROVEMENT_THRESHOLD.with(|v| *v.borrow_mut() = p); - self - } - pub fn desired_targets(self, t: u32) -> Self { - DESIRED_TARGETS.with(|v| *v.borrow_mut() = t); - self - } - pub fn add_voter( - self, - who: AccountId, - stake: Balance, - targets: Vec, - ) -> Self { - VOTERS.with(|v| v.borrow_mut().push((who, stake, targets))); - self - } - pub fn build(self) -> sp_io::TestExternalities { - sp_tracing::try_init_simple(); - let mut storage = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - let _ = pallet_balances::GenesisConfig:: { - balances: <[_]>::into_vec(box [(99, 100), (999, 100), (9999, 100)]), - } - .assimilate_storage(&mut storage); - sp_io::TestExternalities::from(storage) - } - pub fn build_offchainify( - self, - iters: u32, - ) -> (sp_io::TestExternalities, Arc>) { - let mut ext = self.build(); - let (offchain, offchain_state) = TestOffchainExt::new(); - let (pool, pool_state) = TestTransactionPoolExt::new(); - let mut seed = [0_u8; 32]; - seed[0..4].copy_from_slice(&iters.to_le_bytes()); - offchain_state.write().seed = seed; - ext.register_extension(OffchainExt::new(offchain)); - ext.register_extension(TransactionPoolExt::new(pool)); - (ext, pool_state) - } - pub fn build_and_execute(self, test: impl FnOnce() -> ()) { - self.build().execute_with(test) - } - } - } - #[macro_use] - pub(crate) mod macros { - //! Some helper macros for this crate. - } - pub mod signed { - //! The signed phase implementation. - use crate::two_phase::*; - use codec::Encode; - use sp_arithmetic::traits::SaturatedConversion; - use sp_npos_elections::is_score_better; - use sp_runtime::Perbill; - impl Module - where - ExtendedBalance: From>>, - { - /// Start the signed phase. - /// - /// Upon calling this, auxillary data for election is stored and signed solutions will be - /// accepted. - /// - /// The signed phase must always start before the unsigned phase. - pub fn start_signed_phase() { - let targets = T::ElectionDataProvider::targets(); - let voters = T::ElectionDataProvider::voters(); - let desired_targets = T::ElectionDataProvider::desired_targets(); - >::put(targets); - >::put(voters); - DesiredTargets::put(desired_targets); - } - /// Finish the singed phase. Process the signed submissions from best to worse until a valid one - /// is found, rewarding the best oen and slashing the invalid ones along the way. - /// - /// Returns true if we have a good solution in the signed phase. - /// - /// This drains the [`SignedSubmissions`], potentially storing the best valid one in - /// [`QueuedSolution`]. - pub fn finalize_signed_phase() -> bool { - let mut all_submission: Vec> = - >::take(); - let mut found_solution = false; - while let Some(best) = all_submission.pop() { - let SignedSubmission { - solution, - who, - deposit, - reward, - } = best; - match Self::feasibility_check(solution, ElectionCompute::Signed) { - Ok(ready_solution) => { - >::put(ready_solution); - let _remaining = T::Currency::unreserve(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic( - "assertion failed: _remaining.is_zero()", - ) - } - }; - }; - let positive_imbalance = T::Currency::deposit_creating(&who, reward); - T::RewardHandler::on_unbalanced(positive_imbalance); - found_solution = true; - break; - } - Err(_) => { - let (negative_imbalance, _remaining) = - T::Currency::slash_reserved(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic( - "assertion failed: _remaining.is_zero()", - ) - } - }; - }; - T::SlashHandler::on_unbalanced(negative_imbalance); - } - } - } - all_submission.into_iter().for_each(|not_processed| { - let SignedSubmission { who, deposit, .. } = not_processed; - let _remaining = T::Currency::unreserve(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic("assertion failed: _remaining.is_zero()") - } - }; - }; - }); - found_solution - } - /// Find a proper position in the queue for the signed queue, whilst maintaining the order of - /// solution quality. - /// - /// The length of the queue will always be kept less than or equal to `T::MaxSignedSubmissions`. - pub fn insert_submission( - who: &T::AccountId, - queue: &mut Vec, CompactOf>>, - solution: RawSolution>, - ) -> Option { - let outcome = queue - .iter() - .enumerate() - .rev() - .find_map(|(i, s)| { - if is_score_better::( - solution.score, - s.solution.score, - T::SolutionImprovementThreshold::get(), - ) { - Some(i + 1) - } else { - None - } - }) - .or(Some(0)) - .and_then(|at| { - if at == 0 && queue.len() as u32 >= T::MaxSignedSubmissions::get() { - None - } else { - let reward = Self::reward_for(&solution); - let deposit = Self::deposit_for(&solution); - let submission = SignedSubmission { - who: who.clone(), - deposit, - reward, - solution, - }; - queue.insert(at, submission); - if queue.len() as u32 > T::MaxSignedSubmissions::get() { - queue.remove(0); - Some(at - 1) - } else { - Some(at) - } - } - }); - if true { - if !(queue.len() as u32 <= T::MaxSignedSubmissions::get()) { - { - :: std :: rt :: begin_panic ( "assertion failed: queue.len() as u32 <= T::MaxSignedSubmissions::get()" ) - } - }; - }; - outcome - } - /// Collect sufficient deposit to store this solution this chain. - /// - /// The deposit is composed of 3 main elements: - /// - /// 1. base deposit, fixed for all submissions. - /// 2. a per-byte deposit, for renting the state usage. - /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize - pub fn deposit_for(solution: &RawSolution>) -> BalanceOf { - let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); - let feasibility_weight = T::WeightInfo::feasibility_check(); - let len_deposit = T::SignedDepositByte::get() * encoded_len; - let weight_deposit = - T::SignedDepositWeight::get() * feasibility_weight.saturated_into(); - T::SignedDepositBase::get() + len_deposit + weight_deposit - } - /// The reward for this solution, if successfully chosen as the best one at the end of the - /// signed phase. - pub fn reward_for(solution: &RawSolution>) -> BalanceOf { - T::SignedRewardBase::get() - + T::SignedRewardFactor::get() - * solution.score[0].saturated_into::>() - } - } - #[cfg(test)] - mod tests { - use super::{mock::*, *}; - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const cannot_submit_too_early: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::signed::tests::cannot_submit_too_early"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(cannot_submit_too_early())), - }; - fn cannot_submit_too_early() { - ExtBuilder::default().build_and_execute(|| { - roll_to(2); - { - match (&TwoPhase::current_phase(), &Phase::Off) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - TwoPhase::start_signed_phase(); - let solution = raw_solution(); - let h = ::frame_support::storage_root(); - { - match ( - &TwoPhase::submit(Origin::signed(10), solution), - &Err(PalletError::::EarlySubmission.into()), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&h, &::frame_support::storage_root()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const should_pay_deposit: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::signed::tests::should_pay_deposit"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(should_pay_deposit())), - }; - fn should_pay_deposit() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let solution = raw_solution(); - { - match (&balances(&99), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - { - match (&balances(&99), &(95, 5)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&TwoPhase::signed_submissions().first().unwrap().deposit, &5) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const good_solution_is_rewarded: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::good_solution_is_rewarded", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn( - || test::assert_test_result(good_solution_is_rewarded()), - ), - }; - fn good_solution_is_rewarded() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let solution = raw_solution(); - { - match (&balances(&99), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - { - match (&balances(&99), &(95, 5)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::finalize_signed_phase() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::finalize_signed_phase()", - ) - } - }; - { - match (&balances(&99), &(100 + 7, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const bad_solution_is_slashed: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::signed::tests::bad_solution_is_slashed"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(bad_solution_is_slashed())), - }; - fn bad_solution_is_slashed() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let mut solution = raw_solution(); - { - match (&balances(&99), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - solution.score[0] += 1; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - { - match (&balances(&99), &(95, 5)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !!TwoPhase::finalize_signed_phase() { - { - ::std::rt::begin_panic( - "assertion failed: !TwoPhase::finalize_signed_phase()", - ) - } - }; - { - match (&balances(&99), &(95, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const suppressed_solution_gets_bond_back: test::TestDescAndFn = - test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::suppressed_solution_gets_bond_back", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(suppressed_solution_gets_bond_back()) - }), - }; - fn suppressed_solution_gets_bond_back() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let mut solution = raw_solution(); - { - match (&balances(&99), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&balances(&999), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let is = TwoPhase::submit(Origin::signed(99), solution.clone()); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - solution.score[0] -= 1; - let is = TwoPhase::submit(Origin::signed(999), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - { - match (&balances(&99), &(95, 5)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&balances(&999), &(95, 5)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::finalize_signed_phase() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::finalize_signed_phase()", - ) - } - }; - { - match (&balances(&99), &(100 + 7, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&balances(&999), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const queue_is_always_sorted: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::signed::tests::queue_is_always_sorted"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(queue_is_always_sorted())), - }; - fn queue_is_always_sorted() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let solution = RawSolution { - score: [5, 0, 0], - ..Default::default() - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - let solution = RawSolution { - score: [4, 0, 0], - ..Default::default() - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - let solution = RawSolution { - score: [6, 0, 0], - ..Default::default() - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - { - match ( - &TwoPhase::signed_submissions() - .iter() - .map(|x| x.solution.score[0]) - .collect::>(), - &<[_]>::into_vec(box [4, 5, 6]), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const cannot_submit_worse_with_full_queue: test::TestDescAndFn = - test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::cannot_submit_worse_with_full_queue", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(cannot_submit_worse_with_full_queue()) - }), - }; - fn cannot_submit_worse_with_full_queue() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - for s in 0..MaxSignedSubmissions::get() { - let solution = RawSolution { - score: [(5 + s).into(), 0, 0], - ..Default::default() - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: - ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: - ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - } - let solution = RawSolution { - score: [4, 0, 0], - ..Default::default() - }; - let h = ::frame_support::storage_root(); - { - match ( - &TwoPhase::submit(Origin::signed(99), solution), - &Err("QueueFull".into()), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&h, &::frame_support::storage_root()) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const weakest_is_removed_if_better_provided: test::TestDescAndFn = - test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::weakest_is_removed_if_better_provided", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(weakest_is_removed_if_better_provided()) - }), - }; - fn weakest_is_removed_if_better_provided() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - for s in 0..MaxSignedSubmissions::get() { - let solution = RawSolution { - score: [(5 + s).into(), 0, 0], - ..Default::default() - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: - ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: - ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - } - { - match ( - &TwoPhase::signed_submissions() - .into_iter() - .map(|s| s.solution.score[0]) - .collect::>(), - &<[_]>::into_vec(box [5, 6, 7, 8, 9]), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let solution = RawSolution { - score: [20, 0, 0], - ..Default::default() - }; - let is = TwoPhase::submit(Origin::signed(99), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - { - match ( - &TwoPhase::signed_submissions() - .into_iter() - .map(|s| s.solution.score[0]) - .collect::>(), - &<[_]>::into_vec(box [6, 7, 8, 9, 20]), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const equally_good_is_not_accepted: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::equally_good_is_not_accepted", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(equally_good_is_not_accepted()) - }), - }; - fn equally_good_is_not_accepted() { - ExtBuilder :: default ( ) . max_signed_submission ( 3 ) . build_and_execute ( | | { roll_to ( 5 ) ; for i in 0 .. MaxSignedSubmissions :: get ( ) { let solution = RawSolution { score : [ ( 5 + i ) . into ( ) , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; } { match ( & TwoPhase :: signed_submissions ( ) . into_iter ( ) . map ( | s | s . solution . score [ 0 ] ) . collect :: < Vec < _ > > ( ) , & < [ _ ] > :: into_vec ( box [ 5 , 6 , 7 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 5 , 0 , 0 ] , .. Default :: default ( ) } ; let h = :: frame_support :: storage_root ( ) ; { match ( & TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) , & Err ( "QueueFull" . into ( ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; { match ( & h , & :: frame_support :: storage_root ( ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; } ) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const solutions_are_always_sorted: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::solutions_are_always_sorted", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(solutions_are_always_sorted()) - }), - }; - fn solutions_are_always_sorted() { - ExtBuilder :: default ( ) . max_signed_submission ( 3 ) . build_and_execute ( | | { let scores = | | TwoPhase :: signed_submissions ( ) . into_iter ( ) . map ( | s | s . solution . score [ 0 ] ) . collect :: < Vec < _ > > ( ) ; roll_to ( 5 ) ; let solution = RawSolution { score : [ 5 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 5 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 8 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 5 , 8 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 3 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 3 , 5 , 8 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 6 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 5 , 6 , 8 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 6 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 6 , 6 , 8 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 10 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 6 , 8 , 10 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution { score : [ 12 , 0 , 0 ] , .. Default :: default ( ) } ; let is = TwoPhase :: submit ( Origin :: signed ( 99 ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & scores ( ) , & < [ _ ] > :: into_vec ( box [ 8 , 10 , 12 ] ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; } ) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const all_in_one_singed_submission_scenario: test::TestDescAndFn = - test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::signed::tests::all_in_one_singed_submission_scenario", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(all_in_one_singed_submission_scenario()) - }), - }; - fn all_in_one_singed_submission_scenario() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&balances(&99), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&balances(&999), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&balances(&9999), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let mut solution = raw_solution(); - let is = TwoPhase::submit(Origin::signed(99), solution.clone()); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - solution.score[0] += 1; - let is = TwoPhase::submit(Origin::signed(999), solution.clone()); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - solution.score[0] -= 1; - let is = TwoPhase::submit(Origin::signed(9999), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - { - match ( - &TwoPhase::signed_submissions() - .iter() - .map(|x| x.who) - .collect::>(), - &<[_]>::into_vec(box [9999, 99, 999]), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::finalize_signed_phase() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::finalize_signed_phase()", - ) - } - }; - { - match (&balances(&99), &(100 + 7, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&balances(&999), &(95, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&balances(&9999), &(100, 0)) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - } - } - pub mod unsigned { - //! The unsigned phase implementation. - use crate::two_phase::*; - use frame_support::{dispatch::DispatchResult, unsigned::ValidateUnsigned}; - use frame_system::offchain::SubmitTransaction; - use sp_npos_elections::{seq_phragmen, CompactSolution, ElectionResult}; - use sp_runtime::{ - offchain::storage::StorageValueRef, - traits::TrailingZeroInput, - transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionValidity, - TransactionValidityError, ValidTransaction, - }, - SaturatedConversion, - }; - use sp_std::cmp::Ordering; - /// Storage key used to store the persistent offchain worker status. - pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; - /// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice - /// within a window of 5 blocks. - pub(crate) const OFFCHAIN_REPEAT: u32 = 5; - /// Default number of blocks for which the unsigned transaction should stay in the pool - pub(crate) const DEFAULT_LONGEVITY: u64 = 25; - impl Module - where - ExtendedBalance: From>>, - { - /// Min a new npos solution. - pub fn mine_solution(iters: usize) -> Result>, Error> { - let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - seq_phragmen::<_, CompactAccuracyOf>( - desired_targets, - targets, - voters, - Some((iters, 0)), - ) - .map_err(Into::into) - .and_then(Self::prepare_election_result) - } - /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which - /// is ready to be submitted to the chain. - /// - /// Will always reduce the solution as well. - pub fn prepare_election_result( - election_result: ElectionResult>, - ) -> Result>, Error> { - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - let voter_index = - |who: &T::AccountId| -> Option> { - voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < T > > > :: try_into ( i ) . ok ( ) ) - }; - let target_index = - |who: &T::AccountId| -> Option> { - targets . iter ( ) . position ( | x | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactTargetIndexOf < T > > > :: try_into ( i ) . ok ( ) ) - }; - let voter_at = - |i: crate::two_phase::CompactVoterIndexOf| -> Option { - < crate :: two_phase :: CompactVoterIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | voters . get ( i ) . map ( | ( x , _ , _ ) | x ) . cloned ( ) ) - }; - let target_at = - |i: crate::two_phase::CompactTargetIndexOf| -> Option { - < crate :: two_phase :: CompactTargetIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | targets . get ( i ) . cloned ( ) ) - }; - let stake_of = |who: &T::AccountId| -> crate::VoteWeight { - voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - }; - let ElectionResult { - assignments, - winners, - } = election_result; - let mut staked = sp_npos_elections::assignment_ratio_to_staked_normalized( - assignments, - &stake_of, - ) - .map_err::(Into::into)?; - sp_npos_elections::reduce(&mut staked); - let ratio = sp_npos_elections::assignment_staked_to_ratio_normalized(staked)?; - let compact = >::from_assignment(ratio, &voter_index, &target_index)?; - let maximum_allowed_voters = - Self::maximum_compact_len::(0, Default::default(), 0); - let compact = Self::trim_compact(compact.len() as u32, compact, &voter_index)?; - let winners = sp_npos_elections::to_without_backing(winners); - let score = compact - .clone() - .score(&winners, stake_of, voter_at, target_at)?; - Ok(RawSolution { compact, score }) - } - /// Get a random number of iterations to run the balancing in the OCW. - /// - /// Uses the offchain seed to generate a random number, maxed with `T::UnsignedMaxIterations`. - pub fn get_balancing_iters() -> usize { - match T::UnsignedMaxIterations::get() { - 0 => 0, - max @ _ => { - let seed = sp_io::offchain::random_seed(); - let random = ::decode(&mut TrailingZeroInput::new(seed.as_ref())) - .expect("input is padded with zeroes; qed") - % max.saturating_add(1); - random as usize - } - } - } - /// Greedily reduce the size of the a solution to fit into the block, w.r.t. weight. - /// - /// The weight of the solution is foremost a function of the number of voters (i.e. - /// `compact.len()`). Aside from this, the other components of the weight are invariant. The - /// number of winners shall not be changed (otherwise the solution is invalid) and the - /// `ElectionSize` is merely a representation of the total number of stakers. - /// - /// Thus, we reside to stripping away some voters. This means only changing the `compact` - /// struct. - /// - /// Note that the solution is already computed, and the winners are elected based on the merit - /// of teh entire stake in the system. Nonetheless, some of the voters will be removed further - /// down the line. - /// - /// Indeed, the score must be computed **after** this step. If this step reduces the score too - /// much, then the solution will be discarded. - pub fn trim_compact( - maximum_allowed_voters: u32, - mut compact: CompactOf, - nominator_index: FN, - ) -> Result, Error> - where - for<'r> FN: Fn(&'r T::AccountId) -> Option>, - { - match compact.len().checked_sub(maximum_allowed_voters as usize) { - Some(to_remove) if to_remove > 0 => { - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let mut voters_sorted = voters - .into_iter() - .map(|(who, stake, _)| (who.clone(), stake)) - .collect::>(); - voters_sorted.sort_by_key(|(_, y)| *y); - let mut removed = 0; - for (maybe_index, _stake) in voters_sorted - .iter() - .map(|(who, stake)| (nominator_index(&who), stake)) - { - let index = maybe_index.ok_or(Error::SnapshotUnAvailable)?; - if compact.remove_voter(index) { - removed += 1 - } - if removed >= to_remove { - break; - } - } - Ok(compact) - } - _ => Ok(compact), - } - } - /// Find the maximum `len` that a compact can have in order to fit into the block weight. - /// - /// This only returns a value between zero and `size.nominators`. - pub fn maximum_compact_len( - _winners_len: u32, - witness: WitnessData, - max_weight: Weight, - ) -> u32 { - if witness.voters < 1 { - return witness.voters; - } - let max_voters = witness.voters.max(1); - let mut voters = max_voters; - let weight_with = |_voters: u32| -> Weight { W::submit_unsigned() }; - let next_voters = - |current_weight: Weight, voters: u32, step: u32| -> Result { - match current_weight.cmp(&max_weight) { - Ordering::Less => { - let next_voters = voters.checked_add(step); - match next_voters { - Some(voters) if voters < max_voters => Ok(voters), - _ => Err(()), - } - } - Ordering::Greater => voters.checked_sub(step).ok_or(()), - Ordering::Equal => Ok(voters), - } - }; - let mut step = voters / 2; - let mut current_weight = weight_with(voters); - while step > 0 { - match next_voters(current_weight, voters, step) { - Ok(next) if next != voters => { - voters = next; - } - Err(()) => { - break; - } - Ok(next) => return next, - } - step = step / 2; - current_weight = weight_with(voters); - } - while voters + 1 <= max_voters && weight_with(voters + 1) < max_weight { - voters += 1; - } - while voters.checked_sub(1).is_some() && weight_with(voters) > max_weight { - voters -= 1; - } - if true { - if !(weight_with(voters.min(witness.voters)) <= max_weight) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["weight_with(", ") <= "], - &match (&voters.min(witness.voters), &max_weight) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Display::fmt, - ), - ], - }, - )) - } - }; - }; - voters.min(witness.voters) - } - /// Checks if an execution of the offchain worker is permitted at the given block number, or not. - /// - /// This essentially makes sure that we don't run on previous blocks in case of a re-org, and we - /// don't run twice within a window of length [`OFFCHAIN_REPEAT`]. - /// - /// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise. - pub(crate) fn set_check_offchain_execution_status( - now: T::BlockNumber, - ) -> Result<(), &'static str> { - let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); - let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); - let mutate_stat = storage.mutate::<_, &'static str, _>( - |maybe_head: Option>| match maybe_head { - Some(Some(head)) if now < head => Err("fork."), - Some(Some(head)) if now >= head && now <= head + threshold => { - Err("recently executed.") - } - Some(Some(head)) if now > head + threshold => Ok(now), - _ => Ok(now), - }, - ); - match mutate_stat { - Ok(Ok(_)) => Ok(()), - Ok(Err(_)) => Err("failed to write to offchain db."), - Err(why) => Err(why), - } - } - /// Mine a new solution, and submit it back to the chian as an unsigned transaction. - pub(crate) fn mine_and_submit() -> Result<(), Error> { - let balancing = Self::get_balancing_iters(); - Self::mine_solution(balancing).and_then(|raw_solution| { - let call = Call::submit_unsigned(raw_solution).into(); - SubmitTransaction::>::submit_unsigned_transaction(call) - .map_err(|_| Error::PoolSubmissionFailed) - }) - } - pub(crate) fn pre_dispatch_checks( - solution: &RawSolution>, - ) -> DispatchResult { - { - if !Self::current_phase().is_unsigned_open() { - { - return Err(PalletError::::EarlySubmission.into()); - }; - } - }; - { - if !Self::queued_solution().map_or(true, |q: ReadySolution<_>| { - is_score_better::( - solution.score, - q.score, - T::SolutionImprovementThreshold::get(), - ) - }) { - { - return Err(PalletError::::WeakSubmission.into()); - }; - } - }; - Ok(()) - } - } - #[allow(deprecated)] - impl ValidateUnsigned for Module - where - ExtendedBalance: From>>, - { - type Call = Call; - fn validate_unsigned( - source: TransactionSource, - call: &Self::Call, - ) -> TransactionValidity { - if let Call::submit_unsigned(solution) = call { - match source { - TransactionSource::Local | TransactionSource::InBlock => {} - _ => { - return InvalidTransaction::Call.into(); - } - } - if let Err(_why) = Self::pre_dispatch_checks(solution) { - return InvalidTransaction::Custom(99).into(); - } - ValidTransaction::with_tag_prefix("OffchainElection") - .priority( - T::UnsignedPriority::get() - .saturating_add(solution.score[0].saturated_into()), - ) - .longevity(DEFAULT_LONGEVITY) - .propagate(false) - .build() - } else { - InvalidTransaction::Call.into() - } - } - fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { - if let Call::submit_unsigned(solution) = call { - Self::pre_dispatch_checks(solution) - .map_err(|_| InvalidTransaction::Custom(99).into()) - } else { - Err(InvalidTransaction::Call.into()) - } - } - } - #[cfg(test)] - mod tests { - use super::{mock::*, *}; - use frame_support::traits::OffchainWorker; - use sp_runtime::PerU16; - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const validate_unsigned_retracts_wrong_phase: test::TestDescAndFn = - test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::unsigned::tests::validate_unsigned_retracts_wrong_phase", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(validate_unsigned_retracts_wrong_phase()) - }), - }; - fn validate_unsigned_retracts_wrong_phase() { - ExtBuilder :: default ( ) . build_and_execute ( | | { let solution = RawSolution :: < TestCompact > { score : [ 5 , 0 , 0 ] , .. Default :: default ( ) } ; let call = Call :: submit_unsigned ( solution . clone ( ) ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Off ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; match < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; match < TwoPhase as ValidateUnsigned > :: pre_dispatch ( & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; roll_to ( 5 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Signed ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; match < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; match < TwoPhase as ValidateUnsigned > :: pre_dispatch ( & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; roll_to ( 15 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Unsigned ( ( true , 15 ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; if ! < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: ::validate_unsigned(TransactionSource::Local,\n &call).is_ok()" ) } } ; if ! < TwoPhase as ValidateUnsigned > :: pre_dispatch ( & call ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: ::pre_dispatch(&call).is_ok()" ) } } ; } ) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const validate_unsigned_retracts_low_score: test::TestDescAndFn = - test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::unsigned::tests::validate_unsigned_retracts_low_score", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(validate_unsigned_retracts_low_score()) - }), - }; - fn validate_unsigned_retracts_low_score() { - ExtBuilder :: default ( ) . build_and_execute ( | | { roll_to ( 15 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Unsigned ( ( true , 15 ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution :: < TestCompact > { score : [ 5 , 0 , 0 ] , .. Default :: default ( ) } ; let call = Call :: submit_unsigned ( solution . clone ( ) ) ; if ! < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: ::validate_unsigned(TransactionSource::Local,\n &call).is_ok()" ) } } ; if ! < TwoPhase as ValidateUnsigned > :: pre_dispatch ( & call ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: ::pre_dispatch(&call).is_ok()" ) } } ; let ready = ReadySolution { score : [ 10 , 0 , 0 ] , .. Default :: default ( ) } ; < QueuedSolution < Runtime > > :: put ( ready ) ; match < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; match < TwoPhase as ValidateUnsigned > :: pre_dispatch ( & call ) . unwrap_err ( ) { TransactionValidityError :: Invalid ( InvalidTransaction :: Custom ( 99 ) ) => true , _ => false , } ; } ) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const priority_is_set: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::unsigned::tests::priority_is_set"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(priority_is_set())), - }; - fn priority_is_set() { - ExtBuilder :: default ( ) . unsigned_priority ( 20 ) . build_and_execute ( | | { roll_to ( 15 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Unsigned ( ( true , 15 ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let solution = RawSolution :: < TestCompact > { score : [ 5 , 0 , 0 ] , .. Default :: default ( ) } ; let call = Call :: submit_unsigned ( solution . clone ( ) ) ; { match ( & < TwoPhase as ValidateUnsigned > :: validate_unsigned ( TransactionSource :: Local , & call ) . unwrap ( ) . priority , & 25 ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; } ) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const invalid_solution_panics : test :: TestDescAndFn = test :: TestDescAndFn { desc : test :: TestDesc { name : test :: StaticTestName ( "two_phase::unsigned::tests::invalid_solution_panics" ) , ignore : false , allow_fail : false , should_panic : test :: ShouldPanic :: YesWithMessage ( "Invalid unsigned submission must produce invalid block and deprive validator from their authoring reward.: FeasibilityError::WrongWinnerCount" ) , test_type : test :: TestType :: UnitTest , } , testfn : test :: StaticTestFn ( | | test :: assert_test_result ( invalid_solution_panics ( ) ) ) , } ; - #[should_panic( - expected = "Invalid unsigned submission must produce invalid block and deprive \ - validator from their authoring reward.: FeasibilityError::WrongWinnerCount" - )] - fn invalid_solution_panics() { - ExtBuilder::default().build_and_execute(|| { - use frame_support::dispatch::Dispatchable; - roll_to(15); - { - match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let solution = RawSolution:: { - score: [5, 0, 0], - ..Default::default() - }; - let call = Call::submit_unsigned(solution.clone()); - let outer_call: OuterCall = call.into(); - let _ = outer_call.dispatch(Origin::none()); - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const miner_works: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::unsigned::tests::miner_works"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(miner_works())), - }; - fn miner_works() { - ExtBuilder::default().build_and_execute(|| { - roll_to(15); - { - match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::snapshot_voters().is_some() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::snapshot_voters().is_some()", - ) - } - }; - if !TwoPhase::snapshot_targets().is_some() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::snapshot_targets().is_some()", - ) - } - }; - { - match (&TwoPhase::desired_targets(), &2) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let solution = TwoPhase::mine_solution(2).unwrap(); - if !TwoPhase::queued_solution().is_none() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::queued_solution().is_none()", - ) - } - }; - let is = TwoPhase::submit_unsigned(Origin::none(), solution); - match is { - Ok(_) => (), - _ => { - if !false { - { - ::std::rt::begin_panic_fmt( - &::core::fmt::Arguments::new_v1_formatted( - &["Expected Ok(_). Got "], - &match (&is,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - &[::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }], - ), - ) - } - } - } - }; - if !TwoPhase::queued_solution().is_some() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::queued_solution().is_some()", - ) - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const ocw_will_only_submit_if_feasible: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::unsigned::tests::ocw_will_only_submit_if_feasible", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(ocw_will_only_submit_if_feasible()) - }), - }; - fn ocw_will_only_submit_if_feasible() {} - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const can_only_submit_threshold_better: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::unsigned::tests::can_only_submit_threshold_better", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(can_only_submit_threshold_better()) - }), - }; - fn can_only_submit_threshold_better() { - ExtBuilder :: default ( ) . desired_targets ( 1 ) . add_voter ( 7 , 2 , < [ _ ] > :: into_vec ( box [ 10 ] ) ) . add_voter ( 8 , 5 , < [ _ ] > :: into_vec ( box [ 10 ] ) ) . solution_improvement_threshold ( Perbill :: from_percent ( 50 ) ) . build_and_execute ( | | { roll_to ( 15 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Unsigned ( ( true , 15 ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; { match ( & TwoPhase :: desired_targets ( ) , & 1 ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let result = ElectionResult { winners : < [ _ ] > :: into_vec ( box [ ( 10 , 10 ) ] ) , assignments : < [ _ ] > :: into_vec ( box [ Assignment { who : 10 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } ] ) , } ; let is = TwoPhase :: submit_unsigned ( Origin :: none ( ) , TwoPhase :: prepare_election_result ( result ) . unwrap ( ) ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; { match ( & TwoPhase :: queued_solution ( ) . unwrap ( ) . score [ 0 ] , & 10 ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let result = ElectionResult { winners : < [ _ ] > :: into_vec ( box [ ( 10 , 12 ) ] ) , assignments : < [ _ ] > :: into_vec ( box [ Assignment { who : 10 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } , Assignment { who : 7 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } ] ) , } ; let solution = TwoPhase :: prepare_election_result ( result ) . unwrap ( ) ; { match ( & solution . score [ 0 ] , & 12 ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let h = :: frame_support :: storage_root ( ) ; { match ( & TwoPhase :: submit_unsigned ( Origin :: none ( ) , solution ) , & Err ( PalletError :: < Runtime > :: WeakSubmission . into ( ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; { match ( & h , & :: frame_support :: storage_root ( ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let result = ElectionResult { winners : < [ _ ] > :: into_vec ( box [ ( 10 , 12 ) ] ) , assignments : < [ _ ] > :: into_vec ( box [ Assignment { who : 10 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } , Assignment { who : 7 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } , Assignment { who : 8 , distribution : < [ _ ] > :: into_vec ( box [ ( 10 , PerU16 :: one ( ) ) ] ) , } ] ) , } ; let solution = TwoPhase :: prepare_election_result ( result ) . unwrap ( ) ; { match ( & solution . score [ 0 ] , & 17 ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; let is = TwoPhase :: submit_unsigned ( Origin :: none ( ) , solution ) ; match is { Ok ( _ ) => ( ) , _ => if ! false { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1_formatted ( & [ "Expected Ok(_). Got " ] , & match ( & is , ) { ( arg0 , ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) ] , } , & [ :: core :: fmt :: rt :: v1 :: Argument { position : 0usize , format : :: core :: fmt :: rt :: v1 :: FormatSpec { fill : ' ' , align : :: core :: fmt :: rt :: v1 :: Alignment :: Unknown , flags : 4u32 , precision : :: core :: fmt :: rt :: v1 :: Count :: Implied , width : :: core :: fmt :: rt :: v1 :: Count :: Implied , } , } ] ) ) } } , } ; } ) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const ocw_check_prevent_duplicate: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::unsigned::tests::ocw_check_prevent_duplicate", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(ocw_check_prevent_duplicate()) - }), - }; - fn ocw_check_prevent_duplicate() { - let (mut ext, _) = ExtBuilder::default().build_offchainify(0); - ext . execute_with ( | | { roll_to ( 15 ) ; { match ( & TwoPhase :: current_phase ( ) , & Phase :: Unsigned ( ( true , 15 ) ) ) { ( left_val , right_val ) => { if ! ( * left_val == * right_val ) { { :: std :: rt :: begin_panic_fmt ( & :: core :: fmt :: Arguments :: new_v1 ( & [ "assertion failed: `(left == right)`\n left: `" , "`,\n right: `" , "`" ] , & match ( & & * left_val , & & * right_val ) { ( arg0 , arg1 ) => [ :: core :: fmt :: ArgumentV1 :: new ( arg0 , :: core :: fmt :: Debug :: fmt ) , :: core :: fmt :: ArgumentV1 :: new ( arg1 , :: core :: fmt :: Debug :: fmt ) ] , } ) ) } } } } } ; if ! TwoPhase :: set_check_offchain_execution_status ( 15 ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status(15).is_ok()" ) } } ; if ! TwoPhase :: set_check_offchain_execution_status ( 16 ) . is_err ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status(16).is_err()" ) } } ; if ! TwoPhase :: set_check_offchain_execution_status ( ( 16 + OFFCHAIN_REPEAT ) . into ( ) ) . is_ok ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status((16 +\n OFFCHAIN_REPEAT).into()).is_ok()" ) } } ; if ! TwoPhase :: set_check_offchain_execution_status ( ( 16 + OFFCHAIN_REPEAT - 3 ) . into ( ) ) . is_err ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status((16 + OFFCHAIN_REPEAT -\n 3).into()).is_err()" ) } } ; if ! TwoPhase :: set_check_offchain_execution_status ( ( 16 + OFFCHAIN_REPEAT - 2 ) . into ( ) ) . is_err ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status((16 + OFFCHAIN_REPEAT -\n 2).into()).is_err()" ) } } ; if ! TwoPhase :: set_check_offchain_execution_status ( ( 16 + OFFCHAIN_REPEAT - 1 ) . into ( ) ) . is_err ( ) { { :: std :: rt :: begin_panic ( "assertion failed: TwoPhase::set_check_offchain_execution_status((16 + OFFCHAIN_REPEAT -\n 1).into()).is_err()" ) } } ; } ) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const ocw_only_runs_when_signed_open_now: test::TestDescAndFn = - test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::unsigned::tests::ocw_only_runs_when_signed_open_now", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| { - test::assert_test_result(ocw_only_runs_when_signed_open_now()) - }), - }; - fn ocw_only_runs_when_signed_open_now() { - let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); - ext.execute_with(|| { - roll_to(15); - { - match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let mut storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); - TwoPhase::offchain_worker(14); - if !pool.read().transactions.len().is_zero() { - { - ::std::rt::begin_panic( - "assertion failed: pool.read().transactions.len().is_zero()", - ) - } - }; - storage.clear(); - TwoPhase::offchain_worker(16); - if !pool.read().transactions.len().is_zero() { - { - ::std::rt::begin_panic( - "assertion failed: pool.read().transactions.len().is_zero()", - ) - } - }; - storage.clear(); - TwoPhase::offchain_worker(15); - if !!pool.read().transactions.len().is_zero() { - { - ::std::rt::begin_panic( - "assertion failed: !pool.read().transactions.len().is_zero()", - ) - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const ocw_can_submit_to_pool: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName( - "two_phase::unsigned::tests::ocw_can_submit_to_pool", - ), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(ocw_can_submit_to_pool())), - }; - fn ocw_can_submit_to_pool() { - let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); - ext.execute_with(|| { - roll_to(15); - { - match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - TwoPhase::offchain_worker(15); - let encoded = pool.read().transactions[0].clone(); - let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); - let call = extrinsic.call; - match call { - OuterCall::TwoPhase(Call::submit_unsigned(_)) => true, - _ => false, - }; - }) - } - } - } - /// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] - /// implementer. - pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< - ::AccountId, - ::BlockNumber, - >>::CompactSolution; - /// The voter index. Derived from [`CompactOf`]. - pub type CompactVoterIndexOf = as CompactSolution>::Voter; - /// The target index. Derived from [`CompactOf`]. - pub type CompactTargetIndexOf = as CompactSolution>::Target; - /// The accuracy of the election. Derived from [`CompactOf`]. - pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; - type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - type PositiveImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::PositiveImbalance; - type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::NegativeImbalance; - /// Current phase of the pallet. - pub enum Phase { - /// Nothing, the election is not happening. - Off, - /// Signed phase is open. - Signed, - /// Unsigned phase is open. - Unsigned((bool, Bn)), - } - impl ::core::marker::StructuralPartialEq for Phase {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Phase { - #[inline] - fn eq(&self, other: &Phase) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &Phase) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - _ => false, - } - } else { - true - } - } - } - } - impl ::core::marker::StructuralEq for Phase {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Phase { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq<(bool, Bn)>; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Phase { - #[inline] - fn clone(&self) -> Phase { - match (&*self,) { - (&Phase::Off,) => Phase::Off, - (&Phase::Signed,) => Phase::Signed, - (&Phase::Unsigned(ref __self_0),) => { - Phase::Unsigned(::core::clone::Clone::clone(&(*__self_0))) - } - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for Phase {} - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Phase - where - Bn: _parity_scale_codec::Encode, - (bool, Bn): _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - Phase::Off => { - dest.push_byte(0usize as u8); - } - Phase::Signed => { - dest.push_byte(1usize as u8); - } - Phase::Unsigned(ref aa) => { - dest.push_byte(2usize as u8); - dest.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for Phase - where - Bn: _parity_scale_codec::Encode, - (bool, Bn): _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Phase - where - Bn: _parity_scale_codec::Decode, - (bool, Bn): _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(Phase::Off), - x if x == 1usize as u8 => Ok(Phase::Signed), - x if x == 2usize as u8 => Ok(Phase::Unsigned({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field Phase :: Unsigned.0".into()), - Ok(a) => a, - } - })), - x => Err("No such variant in enum Phase".into()), - } - } - } - }; - impl core::fmt::Debug for Phase - where - Bn: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::Off => fmt.debug_tuple("Phase::Off").finish(), - Self::Signed => fmt.debug_tuple("Phase::Signed").finish(), - Self::Unsigned(ref a0) => fmt.debug_tuple("Phase::Unsigned").field(a0).finish(), - _ => Ok(()), - } - } - } - impl Default for Phase { - fn default() -> Self { - Phase::Off - } - } - impl Phase { - /// Weather the phase is signed or not. - pub fn is_signed(&self) -> bool { - match self { - Phase::Signed => true, - _ => false, - } - } - /// Weather the phase is unsigned or not. - pub fn is_unsigned(&self) -> bool { - match self { - Phase::Unsigned(_) => true, - _ => false, - } - } - /// Weather the phase is unsigned and open or not, with specific start. - pub fn is_unsigned_open_at(&self, at: Bn) -> bool { - match self { - Phase::Unsigned((true, real)) if *real == at => true, - _ => false, - } - } - /// Weather the phase is unsigned and open or not. - pub fn is_unsigned_open(&self) -> bool { - match self { - Phase::Unsigned((true, _)) => true, - _ => false, - } - } - /// Weather the phase is off or not. - pub fn is_off(&self) -> bool { - match self { - Phase::Off => true, - _ => false, - } - } - } - /// The type of `Computation` that provided this election data. - pub enum ElectionCompute { - /// Election was computed on-chain. - OnChain, - /// Election was computed with a signed submission. - Signed, - /// Election was computed with an unsigned submission. - Unsigned, - } - impl ::core::marker::StructuralPartialEq for ElectionCompute {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for ElectionCompute { - #[inline] - fn eq(&self, other: &ElectionCompute) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - _ => true, - } - } else { - false - } - } - } - } - impl ::core::marker::StructuralEq for ElectionCompute {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for ElectionCompute { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - {} - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for ElectionCompute { - #[inline] - fn clone(&self) -> ElectionCompute { - { - *self - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for ElectionCompute {} - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for ElectionCompute { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - ElectionCompute::OnChain => { - dest.push_byte(0usize as u8); - } - ElectionCompute::Signed => { - dest.push_byte(1usize as u8); - } - ElectionCompute::Unsigned => { - dest.push_byte(2usize as u8); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for ElectionCompute {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for ElectionCompute { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(ElectionCompute::OnChain), - x if x == 1usize as u8 => Ok(ElectionCompute::Signed), - x if x == 2usize as u8 => Ok(ElectionCompute::Unsigned), - x => Err("No such variant in enum ElectionCompute".into()), - } - } - } - }; - impl core::fmt::Debug for ElectionCompute { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::OnChain => fmt.debug_tuple("ElectionCompute::OnChain").finish(), - Self::Signed => fmt.debug_tuple("ElectionCompute::Signed").finish(), - Self::Unsigned => fmt.debug_tuple("ElectionCompute::Unsigned").finish(), - _ => Ok(()), - } - } - } - impl Default for ElectionCompute { - fn default() -> Self { - ElectionCompute::OnChain - } - } - /// A raw, unchecked solution. - /// - /// Such a solution should never become effective in anyway before being checked by the - /// [`Module::feasibility_check`] - pub struct RawSolution { - /// Compact election edges. - compact: C, - /// The _claimed_ score of the solution. - score: ElectionScore, - } - impl ::core::marker::StructuralPartialEq for RawSolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for RawSolution { - #[inline] - fn eq(&self, other: &RawSolution) -> bool { - match *other { - RawSolution { - compact: ref __self_1_0, - score: ref __self_1_1, - } => match *self { - RawSolution { - compact: ref __self_0_0, - score: ref __self_0_1, - } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), - }, - } - } - #[inline] - fn ne(&self, other: &RawSolution) -> bool { - match *other { - RawSolution { - compact: ref __self_1_0, - score: ref __self_1_1, - } => match *self { - RawSolution { - compact: ref __self_0_0, - score: ref __self_0_1, - } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), - }, - } - } - } - impl ::core::marker::StructuralEq for RawSolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for RawSolution { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for RawSolution { - #[inline] - fn clone(&self) -> RawSolution { - match *self { - RawSolution { - compact: ref __self_0_0, - score: ref __self_0_1, - } => RawSolution { - compact: ::core::clone::Clone::clone(&(*__self_0_0)), - score: ::core::clone::Clone::clone(&(*__self_0_1)), - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for RawSolution - where - C: _parity_scale_codec::Encode, - C: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.compact); - dest.push(&self.score); - } - } - impl _parity_scale_codec::EncodeLike for RawSolution - where - C: _parity_scale_codec::Encode, - C: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for RawSolution - where - C: _parity_scale_codec::Decode, - C: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(RawSolution { - compact: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field RawSolution.compact".into()), - Ok(a) => a, - } - }, - score: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field RawSolution.score".into()), - Ok(a) => a, - } - }, - }) - } - } - }; - impl core::fmt::Debug for RawSolution - where - C: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("RawSolution") - .field("compact", &self.compact) - .field("score", &self.score) - .finish() - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for RawSolution { - #[inline] - fn default() -> RawSolution { - RawSolution { - compact: ::core::default::Default::default(), - score: ::core::default::Default::default(), - } - } - } - /// A raw, unchecked signed submission. - /// - /// This is just a wrapper around [`RawSolution`] and some additional info. - pub struct SignedSubmission { - /// Who submitted this solution. - who: A, - /// The deposit reserved for storing this solution. - deposit: B, - /// The reward that should be given to this solution, if chosen the as the final one. - reward: B, - /// The raw solution itself. - solution: RawSolution, - } - impl ::core::marker::StructuralPartialEq for SignedSubmission {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl< - A: ::core::cmp::PartialEq, - B: ::core::cmp::PartialEq + HasCompact, - C: ::core::cmp::PartialEq, - > ::core::cmp::PartialEq for SignedSubmission - { - #[inline] - fn eq(&self, other: &SignedSubmission) -> bool { - match *other { - SignedSubmission { - who: ref __self_1_0, - deposit: ref __self_1_1, - reward: ref __self_1_2, - solution: ref __self_1_3, - } => match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - && (*__self_0_3) == (*__self_1_3) - } - }, - } - } - #[inline] - fn ne(&self, other: &SignedSubmission) -> bool { - match *other { - SignedSubmission { - who: ref __self_1_0, - deposit: ref __self_1_1, - reward: ref __self_1_2, - solution: ref __self_1_3, - } => match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) - || (*__self_0_2) != (*__self_1_2) - || (*__self_0_3) != (*__self_1_3) - } - }, - } - } - } - impl ::core::marker::StructuralEq for SignedSubmission {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq - for SignedSubmission - { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq>; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl< - A: ::core::clone::Clone, - B: ::core::clone::Clone + HasCompact, - C: ::core::clone::Clone, - > ::core::clone::Clone for SignedSubmission - { - #[inline] - fn clone(&self) -> SignedSubmission { - match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => SignedSubmission { - who: ::core::clone::Clone::clone(&(*__self_0_0)), - deposit: ::core::clone::Clone::clone(&(*__self_0_1)), - reward: ::core::clone::Clone::clone(&(*__self_0_2)), - solution: ::core::clone::Clone::clone(&(*__self_0_3)), - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for SignedSubmission - where - A: _parity_scale_codec::Encode, - A: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.who); - dest.push(&self.deposit); - dest.push(&self.reward); - dest.push(&self.solution); - } - } - impl _parity_scale_codec::EncodeLike for SignedSubmission - where - A: _parity_scale_codec::Encode, - A: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for SignedSubmission - where - A: _parity_scale_codec::Decode, - A: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - RawSolution: _parity_scale_codec::Decode, - RawSolution: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(SignedSubmission { - who: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.who".into()) - } - Ok(a) => a, - } - }, - deposit: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.deposit".into()) - } - Ok(a) => a, - } - }, - reward: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.reward".into()) - } - Ok(a) => a, - } - }, - solution: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field SignedSubmission.solution".into()) - } - Ok(a) => a, - } - }, - }) - } - } - }; - impl core::fmt::Debug for SignedSubmission - where - A: core::fmt::Debug, - B: core::fmt::Debug, - C: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("SignedSubmission") - .field("who", &self.who) - .field("deposit", &self.deposit) - .field("reward", &self.reward) - .field("solution", &self.solution) - .finish() - } - } - /// A checked and parsed solution, ready to be enacted. - pub struct ReadySolution { - /// The final supports of the solution. This is target-major vector, storing each winners, total - /// backing, and each individual backer. - supports: Supports, - /// The score of the solution. - /// - /// This is needed to potentially challenge the solution. - score: ElectionScore, - /// How this election was computed. - compute: ElectionCompute, - } - impl ::core::marker::StructuralPartialEq for ReadySolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for ReadySolution { - #[inline] - fn eq(&self, other: &ReadySolution) -> bool { - match *other { - ReadySolution { - supports: ref __self_1_0, - score: ref __self_1_1, - compute: ref __self_1_2, - } => match *self { - ReadySolution { - supports: ref __self_0_0, - score: ref __self_0_1, - compute: ref __self_0_2, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - } - }, - } - } - #[inline] - fn ne(&self, other: &ReadySolution) -> bool { - match *other { - ReadySolution { - supports: ref __self_1_0, - score: ref __self_1_1, - compute: ref __self_1_2, - } => match *self { - ReadySolution { - supports: ref __self_0_0, - score: ref __self_0_1, - compute: ref __self_0_2, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) - || (*__self_0_2) != (*__self_1_2) - } - }, - } - } - } - impl ::core::marker::StructuralEq for ReadySolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for ReadySolution { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for ReadySolution { - #[inline] - fn clone(&self) -> ReadySolution { - match *self { - ReadySolution { - supports: ref __self_0_0, - score: ref __self_0_1, - compute: ref __self_0_2, - } => ReadySolution { - supports: ::core::clone::Clone::clone(&(*__self_0_0)), - score: ::core::clone::Clone::clone(&(*__self_0_1)), - compute: ::core::clone::Clone::clone(&(*__self_0_2)), - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for ReadySolution - where - Supports: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - dest.push(&self.supports); - dest.push(&self.score); - dest.push(&self.compute); - } - } - impl _parity_scale_codec::EncodeLike for ReadySolution - where - Supports: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for ReadySolution - where - Supports: _parity_scale_codec::Decode, - Supports: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(ReadySolution { - supports: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field ReadySolution.supports".into()) - } - Ok(a) => a, - } - }, - score: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field ReadySolution.score".into()), - Ok(a) => a, - } - }, - compute: { - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field ReadySolution.compute".into()) - } - Ok(a) => a, - } - }, - }) - } - } - }; - impl core::fmt::Debug for ReadySolution - where - A: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("ReadySolution") - .field("supports", &self.supports) - .field("score", &self.score) - .field("compute", &self.compute) - .finish() - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for ReadySolution { - #[inline] - fn default() -> ReadySolution { - ReadySolution { - supports: ::core::default::Default::default(), - score: ::core::default::Default::default(), - compute: ::core::default::Default::default(), - } - } - } - /// Witness data about the size of the election. - /// - /// This is needed for proper weight calculation. - pub struct WitnessData { - /// Number of all voters. - /// - /// This must match the on-chain snapshot. - #[codec(compact)] - voters: u32, - /// Number of all targets. - /// - /// This must match the on-chain snapshot. - #[codec(compact)] - targets: u32, - } - impl ::core::marker::StructuralPartialEq for WitnessData {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for WitnessData { - #[inline] - fn eq(&self, other: &WitnessData) -> bool { - match *other { - WitnessData { - voters: ref __self_1_0, - targets: ref __self_1_1, - } => match *self { - WitnessData { - voters: ref __self_0_0, - targets: ref __self_0_1, - } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), - }, - } - } - #[inline] - fn ne(&self, other: &WitnessData) -> bool { - match *other { - WitnessData { - voters: ref __self_1_0, - targets: ref __self_1_1, - } => match *self { - WitnessData { - voters: ref __self_0_0, - targets: ref __self_0_1, - } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), - }, - } - } - } - impl ::core::marker::StructuralEq for WitnessData {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for WitnessData { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for WitnessData { - #[inline] - fn clone(&self) -> WitnessData { - { - let _: ::core::clone::AssertParamIsClone; - let _: ::core::clone::AssertParamIsClone; - *self - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for WitnessData {} - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for WitnessData { - fn encode_to(&self, dest: &mut EncOut) { - { - dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . voters ) ) ; - } - { - dest . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . targets ) ) ; - } - } - } - impl _parity_scale_codec::EncodeLike for WitnessData {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for WitnessData { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(WitnessData { - voters: { - let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; - match res { - Err(_) => return Err("Error decoding field WitnessData.voters".into()), - Ok(a) => a.into(), - } - }, - targets: { - let res = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( input ) ; - match res { - Err(_) => return Err("Error decoding field WitnessData.targets".into()), - Ok(a) => a.into(), - } - }, - }) - } - } - }; - impl core::fmt::Debug for WitnessData { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("WitnessData") - .field("voters", &self.voters) - .field("targets", &self.targets) - .finish() - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for WitnessData { - #[inline] - fn default() -> WitnessData { - WitnessData { - voters: ::core::default::Default::default(), - targets: ::core::default::Default::default(), - } - } - } - /// The crate errors. Note that this is different from the [`PalletError`]. - pub enum Error { - /// A feasibility error. - Feasibility(FeasibilityError), - /// An error in the on-chain fallback. - OnChainFallback(crate::onchain::Error), - /// An internal error in the NPoS elections crate. - NposElections(sp_npos_elections::Error), - /// Snapshot data was unavailable unexpectedly. - SnapshotUnAvailable, - /// Submitting a transaction to the pool failed. - /// - /// This can only happen in the unsigned phase. - PoolSubmissionFailed, - } - impl core::fmt::Debug for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::Feasibility(ref a0) => { - fmt.debug_tuple("Error::Feasibility").field(a0).finish() - } - Self::OnChainFallback(ref a0) => { - fmt.debug_tuple("Error::OnChainFallback").field(a0).finish() - } - Self::NposElections(ref a0) => { - fmt.debug_tuple("Error::NposElections").field(a0).finish() - } - Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), - Self::PoolSubmissionFailed => { - fmt.debug_tuple("Error::PoolSubmissionFailed").finish() - } - _ => Ok(()), - } - } - } - impl ::core::marker::StructuralEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Error { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - impl ::core::marker::StructuralPartialEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Error { - #[inline] - fn eq(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - ( - &Error::OnChainFallback(ref __self_0), - &Error::OnChainFallback(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - ( - &Error::NposElections(ref __self_0), - &Error::NposElections(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - ( - &Error::OnChainFallback(ref __self_0), - &Error::OnChainFallback(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - ( - &Error::NposElections(ref __self_0), - &Error::NposElections(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - _ => false, - } - } else { - true - } - } - } - } - impl From for Error { - fn from(e: crate::onchain::Error) -> Self { - Error::OnChainFallback(e) - } - } - impl From for Error { - fn from(e: sp_npos_elections::Error) -> Self { - Error::NposElections(e) - } - } - /// Errors that can happen in the feasibility check. - pub enum FeasibilityError { - /// Wrong number of winners presented. - WrongWinnerCount, - /// The snapshot is not available. - /// - /// This must be an internal error of the chain. - SnapshotUnavailable, - /// Internal error from the election crate. - NposElectionError(sp_npos_elections::Error), - /// A vote is invalid. - InvalidVote, - /// A voter is invalid. - InvalidVoter, - /// A winner is invalid. - InvalidWinner, - /// The given score was invalid. - InvalidScore, - } - impl core::fmt::Debug for FeasibilityError { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::WrongWinnerCount => fmt - .debug_tuple("FeasibilityError::WrongWinnerCount") - .finish(), - Self::SnapshotUnavailable => fmt - .debug_tuple("FeasibilityError::SnapshotUnavailable") - .finish(), - Self::NposElectionError(ref a0) => fmt - .debug_tuple("FeasibilityError::NposElectionError") - .field(a0) - .finish(), - Self::InvalidVote => fmt.debug_tuple("FeasibilityError::InvalidVote").finish(), - Self::InvalidVoter => fmt.debug_tuple("FeasibilityError::InvalidVoter").finish(), - Self::InvalidWinner => fmt.debug_tuple("FeasibilityError::InvalidWinner").finish(), - Self::InvalidScore => fmt.debug_tuple("FeasibilityError::InvalidScore").finish(), - _ => Ok(()), - } - } - } - impl ::core::marker::StructuralEq for FeasibilityError {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for FeasibilityError { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - } - } - } - impl ::core::marker::StructuralPartialEq for FeasibilityError {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for FeasibilityError { - #[inline] - fn eq(&self, other: &FeasibilityError) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &FeasibilityError::NposElectionError(ref __self_0), - &FeasibilityError::NposElectionError(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &FeasibilityError) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &FeasibilityError::NposElectionError(ref __self_0), - &FeasibilityError::NposElectionError(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - _ => false, - } - } else { - true - } - } - } - } - impl From for FeasibilityError { - fn from(e: sp_npos_elections::Error) -> Self { - FeasibilityError::NposElectionError(e) - } - } - /// The weights for this pallet. - pub trait WeightInfo { - fn feasibility_check() -> Weight; - fn submit() -> Weight; - fn submit_unsigned() -> Weight; - } - impl WeightInfo for () { - fn feasibility_check() -> Weight { - Default::default() - } - fn submit() -> Weight { - Default::default() - } - fn submit_unsigned() -> Weight { - Default::default() - } - } - pub trait Trait: frame_system::Trait + SendTransactionTypes> - where - ExtendedBalance: From>>, - { - /// Event type. - type Event: From> + Into<::Event>; - /// Currency type. - type Currency: ReservableCurrency + Currency; - /// Duration of the signed phase. - type SignedPhase: Get; - /// Duration of the unsigned phase. - type UnsignedPhase: Get; - /// Maximum number of singed submissions that can be queued. - type MaxSignedSubmissions: Get; - type SignedRewardBase: Get>; - type SignedRewardFactor: Get; - type SignedRewardMax: Get>>; - type SignedDepositBase: Get>; - type SignedDepositByte: Get>; - type SignedDepositWeight: Get>; - /// The minimum amount of improvement to the solution score that defines a solution as "better". - type SolutionImprovementThreshold: Get; - type UnsignedMaxIterations: Get; - type UnsignedPriority: Get; - /// Handler for the slashed deposits. - type SlashHandler: OnUnbalanced>; - /// Handler for the rewards. - type RewardHandler: OnUnbalanced>; - /// Something that will provide the election data. - type ElectionDataProvider: ElectionDataProvider; - /// The weight of the pallet. - type WeightInfo: WeightInfo; - } - use self::sp_api_hidden_includes_decl_storage::hidden_include::{ - IterableStorageDoubleMap as _, IterableStorageMap as _, StorageDoubleMap as _, - StorageMap as _, StoragePrefixedMap as _, StorageValue as _, - }; - #[doc(hidden)] - mod sp_api_hidden_includes_decl_storage { - pub extern crate frame_support as hidden_include; - } - trait Store { - type Round; - type CurrentPhase; - type SignedSubmissions; - type QueuedSolution; - type SnapshotTargets; - type SnapshotVoters; - type DesiredTargets; - } - impl Store for Module - where - ExtendedBalance: From>>, - { - type Round = Round; - type CurrentPhase = CurrentPhase; - type SignedSubmissions = SignedSubmissions; - type QueuedSolution = QueuedSolution; - type SnapshotTargets = SnapshotTargets; - type SnapshotVoters = SnapshotVoters; - type DesiredTargets = DesiredTargets; - } - impl Module - where - ExtendedBalance: From>>, - { - /// Internal counter ofr the number of rounds. - /// - /// This is useful for de-duplication of transactions submitted to the pool, and general - /// diagnostics of the module. - /// - /// This is merely incremented once per every time that signed phase starts. - pub fn round() -> u32 { - < Round < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) - } - /// Current phase. - pub fn current_phase() -> Phase { - < CurrentPhase < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase < T :: BlockNumber > > > :: get ( ) - } - /// Sorted (worse -> best) list of unchecked, signed solutions. - pub fn signed_submissions( - ) -> Vec, CompactOf>> { - < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > > > :: get ( ) - } - /// Current best solution, signed or unsigned. - pub fn queued_solution() -> Option> { - < QueuedSolution < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < ReadySolution < T :: AccountId > > > :: get ( ) - } - /// Snapshot of all Voters. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn snapshot_targets() -> Option> { - < SnapshotTargets < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < T :: AccountId > > > :: get ( ) - } - /// Snapshot of all targets. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn snapshot_voters() -> Option)>> { - < SnapshotVoters < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < ( T :: AccountId , VoteWeight , Vec < T :: AccountId > ) > > > :: get ( ) - } - /// Desired number of targets to elect. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn desired_targets() -> u32 { - < DesiredTargets < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) - } - } - #[doc(hidden)] - pub struct __GetByteStructRound( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_Round: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructRound - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_Round - .get_or_init(|| { - let def_val: u32 = 0; - ::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructRound where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructRound where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructCurrentPhase( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_CurrentPhase: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructCurrentPhase - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_CurrentPhase - .get_or_init(|| { - let def_val: Phase = Phase::Off; - as Encode>::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructCurrentPhase where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructCurrentPhase where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructSignedSubmissions( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_SignedSubmissions: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructSignedSubmissions - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SignedSubmissions . get_or_init ( | | { let def_val : Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > = Default :: default ( ) ; < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > as Encode > :: encode ( & def_val ) } ) . clone ( ) - } - } - unsafe impl Send for __GetByteStructSignedSubmissions where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructSignedSubmissions where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructQueuedSolution( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_QueuedSolution: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructQueuedSolution - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_QueuedSolution - .get_or_init(|| { - let def_val: Option> = Default::default(); - > as Encode>::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructQueuedSolution where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructQueuedSolution where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructSnapshotTargets( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_SnapshotTargets: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructSnapshotTargets - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SnapshotTargets - .get_or_init(|| { - let def_val: Option> = Default::default(); - > as Encode>::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructSnapshotTargets where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructSnapshotTargets where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructSnapshotVoters( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_SnapshotVoters: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructSnapshotVoters - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SnapshotVoters - .get_or_init(|| { - let def_val: Option)>> = - Default::default(); - )>> as Encode>::encode( - &def_val, - ) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructSnapshotVoters where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructSnapshotVoters where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructDesiredTargets( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_DesiredTargets: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructDesiredTargets - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_DesiredTargets - .get_or_init(|| { - let def_val: u32 = Default::default(); - ::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructDesiredTargets where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructDesiredTargets where - ExtendedBalance: From>> - { - } - impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - pub fn storage_metadata( - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::StorageMetadata { - self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Round" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructRound :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Internal counter ofr the number of rounds." , "" , " This is useful for de-duplication of transactions submitted to the pool, and general" , " diagnostics of the module." , "" , " This is merely incremented once per every time that signed phase starts." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec, CompactOf>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted (worse -> best) list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current best solution, signed or unsigned." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all Voters." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SnapshotVoters" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec<(T::AccountId, VoteWeight, Vec)>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshotVoters :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot of all targets." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "DesiredTargets" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructDesiredTargets :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Desired number of targets to elect." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } ] [ .. ] ) , } - } - } - /// Hidden instance generated to be internally used when module is used without - /// instance. - #[doc(hidden)] - pub struct __InherentHiddenInstance; - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for __InherentHiddenInstance { - #[inline] - fn clone(&self) -> __InherentHiddenInstance { - match *self { - __InherentHiddenInstance => __InherentHiddenInstance, - } - } - } - impl ::core::marker::StructuralEq for __InherentHiddenInstance {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for __InherentHiddenInstance { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - {} - } - } - impl ::core::marker::StructuralPartialEq for __InherentHiddenInstance {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for __InherentHiddenInstance { - #[inline] - fn eq(&self, other: &__InherentHiddenInstance) -> bool { - match *other { - __InherentHiddenInstance => match *self { - __InherentHiddenInstance => true, - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for __InherentHiddenInstance { - fn encode_to(&self, dest: &mut EncOut) {} - } - impl _parity_scale_codec::EncodeLike for __InherentHiddenInstance {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for __InherentHiddenInstance { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - Ok(__InherentHiddenInstance) - } - } - }; - impl core::fmt::Debug for __InherentHiddenInstance { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_tuple("__InherentHiddenInstance").finish() - } - } - impl self::sp_api_hidden_includes_decl_storage::hidden_include::traits::Instance - for __InherentHiddenInstance - { - const PREFIX: &'static str = "TwoPhaseElectionProvider"; - } - /// Internal counter ofr the number of rounds. - /// - /// This is useful for de-duplication of transactions submitted to the pool, and general - /// diagnostics of the module. - /// - /// This is merely incremented once per every time that signed phase starts. - pub struct Round( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, - ); - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - u32, - > for Round - { - type Query = u32; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"Round" - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - v.unwrap_or_else(|| 0) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - Some(v) - } - } - /// Current phase. - pub struct CurrentPhase( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Phase, - > for CurrentPhase - where - ExtendedBalance: From>>, - { - type Query = Phase; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"CurrentPhase" - } - fn from_optional_value_to_query(v: Option>) -> Self::Query { - v.unwrap_or_else(|| Phase::Off) - } - fn from_query_to_optional_value(v: Self::Query) -> Option> { - Some(v) - } - } - /// Sorted (worse -> best) list of unchecked, signed solutions. - pub struct SignedSubmissions( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec, CompactOf>>, - > for SignedSubmissions - where - ExtendedBalance: From>>, - { - type Query = Vec, CompactOf>>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"SignedSubmissions" - } - fn from_optional_value_to_query( - v: Option, CompactOf>>>, - ) -> Self::Query { - v.unwrap_or_else(|| Default::default()) - } - fn from_query_to_optional_value( - v: Self::Query, - ) -> Option, CompactOf>>> { - Some(v) - } - } - /// Current best solution, signed or unsigned. - pub struct QueuedSolution( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - ReadySolution, - > for QueuedSolution - where - ExtendedBalance: From>>, - { - type Query = Option>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"QueuedSolution" - } - fn from_optional_value_to_query(v: Option>) -> Self::Query { - v.or_else(|| Default::default()) - } - fn from_query_to_optional_value(v: Self::Query) -> Option> { - v - } - } - /// Snapshot of all Voters. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub struct SnapshotTargets( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec, - > for SnapshotTargets - where - ExtendedBalance: From>>, - { - type Query = Option>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"SnapshotTargets" - } - fn from_optional_value_to_query(v: Option>) -> Self::Query { - v.or_else(|| Default::default()) - } - fn from_query_to_optional_value(v: Self::Query) -> Option> { - v - } - } - /// Snapshot of all targets. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub struct SnapshotVoters( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec<(T::AccountId, VoteWeight, Vec)>, - > for SnapshotVoters - where - ExtendedBalance: From>>, - { - type Query = Option)>>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"SnapshotVoters" - } - fn from_optional_value_to_query( - v: Option)>>, - ) -> Self::Query { - v.or_else(|| Default::default()) - } - fn from_query_to_optional_value( - v: Self::Query, - ) -> Option)>> { - v - } - } - /// Desired number of targets to elect. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub struct DesiredTargets( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, - ); - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - u32, - > for DesiredTargets - { - type Query = u32; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"DesiredTargets" - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - v.unwrap_or_else(|| Default::default()) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - Some(v) - } - } - /// [`RawEvent`] specialized for the configuration [`Trait`] - /// - /// [`RawEvent`]: enum.RawEvent.html - /// [`Trait`]: trait.Trait.html - pub type Event = RawEvent<::AccountId>; - /// Events for this module. - /// - pub enum RawEvent { - /// A solution was stored with the given compute. - /// - /// If the solution is signed, this means that it hasn't yet been processed. If the solution - /// is unsigned, this means that it has also been processed. - SolutionStored(ElectionCompute), - /// The election has been finalized, with `Some` of the given computation, or else if the - /// election failed, `None`. - ElectionFinalized(Option), - /// An account has been rewarded for their signed submission being finalized. - Rewarded(AccountId), - /// An account has been slashed for submitting an invalid signed submission. - Slashed(AccountId), - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for RawEvent { - #[inline] - fn clone(&self) -> RawEvent { - match (&*self,) { - (&RawEvent::SolutionStored(ref __self_0),) => { - RawEvent::SolutionStored(::core::clone::Clone::clone(&(*__self_0))) - } - (&RawEvent::ElectionFinalized(ref __self_0),) => { - RawEvent::ElectionFinalized(::core::clone::Clone::clone(&(*__self_0))) - } - (&RawEvent::Rewarded(ref __self_0),) => { - RawEvent::Rewarded(::core::clone::Clone::clone(&(*__self_0))) - } - (&RawEvent::Slashed(ref __self_0),) => { - RawEvent::Slashed(::core::clone::Clone::clone(&(*__self_0))) - } - } - } - } - impl ::core::marker::StructuralPartialEq for RawEvent {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for RawEvent { - #[inline] - fn eq(&self, other: &RawEvent) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &RawEvent::SolutionStored(ref __self_0), - &RawEvent::SolutionStored(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - ( - &RawEvent::ElectionFinalized(ref __self_0), - &RawEvent::ElectionFinalized(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - _ => unsafe { ::core::intrinsics::unreachable() }, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &RawEvent) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &RawEvent::SolutionStored(ref __self_0), - &RawEvent::SolutionStored(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - ( - &RawEvent::ElectionFinalized(ref __self_0), - &RawEvent::ElectionFinalized(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - _ => unsafe { ::core::intrinsics::unreachable() }, - } - } else { - true - } - } - } - } - impl ::core::marker::StructuralEq for RawEvent {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for RawEvent { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for RawEvent - where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - RawEvent::SolutionStored(ref aa) => { - dest.push_byte(0usize as u8); - dest.push(aa); - } - RawEvent::ElectionFinalized(ref aa) => { - dest.push_byte(1usize as u8); - dest.push(aa); - } - RawEvent::Rewarded(ref aa) => { - dest.push_byte(2usize as u8); - dest.push(aa); - } - RawEvent::Slashed(ref aa) => { - dest.push_byte(3usize as u8); - dest.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for RawEvent - where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for RawEvent - where - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(RawEvent::SolutionStored({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err( - "Error decoding field RawEvent :: SolutionStored.0".into() - ) - } - Ok(a) => a, - } - })), - x if x == 1usize as u8 => Ok(RawEvent::ElectionFinalized({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err( - "Error decoding field RawEvent :: ElectionFinalized.0".into() - ) - } - Ok(a) => a, - } - })), - x if x == 2usize as u8 => Ok(RawEvent::Rewarded({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field RawEvent :: Rewarded.0".into()) - } - Ok(a) => a, - } - })), - x if x == 3usize as u8 => Ok(RawEvent::Slashed({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field RawEvent :: Slashed.0".into()) - } - Ok(a) => a, - } - })), - x => Err("No such variant in enum RawEvent".into()), - } - } - } - }; - impl core::fmt::Debug for RawEvent - where - AccountId: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::SolutionStored(ref a0) => fmt - .debug_tuple("RawEvent::SolutionStored") - .field(a0) - .finish(), - Self::ElectionFinalized(ref a0) => fmt - .debug_tuple("RawEvent::ElectionFinalized") - .field(a0) - .finish(), - Self::Rewarded(ref a0) => fmt.debug_tuple("RawEvent::Rewarded").field(a0).finish(), - Self::Slashed(ref a0) => fmt.debug_tuple("RawEvent::Slashed").field(a0).finish(), - _ => Ok(()), - } - } - } - impl From> for () { - fn from(_: RawEvent) -> () { - () - } - } - impl RawEvent { - #[allow(dead_code)] - #[doc(hidden)] - pub fn metadata() -> &'static [::frame_support::event::EventMetadata] { - &[ - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("SolutionStored"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&[ - "ElectionCompute", - ]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" A solution was stored with the given compute.", - r"", - r" If the solution is signed, this means that it hasn't yet been processed. If the solution", - r" is unsigned, this means that it has also been processed.", - ]), - }, - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("ElectionFinalized"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&[ - "Option", - ]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" The election has been finalized, with `Some` of the given computation, or else if the", - r" election failed, `None`.", - ]), - }, - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("Rewarded"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" An account has been rewarded for their signed submission being finalized.", - ]), - }, - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("Slashed"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" An account has been slashed for submitting an invalid signed submission.", - ]), - }, - ] - } - } - pub enum PalletError - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - __Ignore( - ::frame_support::sp_std::marker::PhantomData<(T,)>, - ::frame_support::Never, - ), - /// Submission was too early. - EarlySubmission, - /// Submission was too weak, score-wise. - WeakSubmission, - /// The queue was full, and the solution was not better than any of the existing ones. - QueueFull, - /// The origin failed to pay the deposit. - CannotPayDeposit, - } - impl ::frame_support::sp_std::fmt::Debug for PalletError - where - ExtendedBalance: From>>, - { - fn fmt( - &self, - f: &mut ::frame_support::sp_std::fmt::Formatter<'_>, - ) -> ::frame_support::sp_std::fmt::Result { - f.write_str(self.as_str()) - } - } - impl PalletError - where - ExtendedBalance: From>>, - { - fn as_u8(&self) -> u8 { - match self { - PalletError::__Ignore(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"`__Ignore` can never be constructed",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - PalletError::EarlySubmission => 0, - PalletError::WeakSubmission => 0 + 1, - PalletError::QueueFull => 0 + 1 + 1, - PalletError::CannotPayDeposit => 0 + 1 + 1 + 1, - } - } - fn as_str(&self) -> &'static str { - match self { - Self::__Ignore(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"`__Ignore` can never be constructed",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - PalletError::EarlySubmission => "EarlySubmission", - PalletError::WeakSubmission => "WeakSubmission", - PalletError::QueueFull => "QueueFull", - PalletError::CannotPayDeposit => "CannotPayDeposit", - } - } - } - impl From> for &'static str - where - ExtendedBalance: From>>, - { - fn from(err: PalletError) -> &'static str { - err.as_str() - } - } - impl From> for ::frame_support::sp_runtime::DispatchError - where - ExtendedBalance: From>>, - { - fn from(err: PalletError) -> Self { - let index = ::index::>() - .expect("Every active module has an index in the runtime; qed") as u8; - ::frame_support::sp_runtime::DispatchError::Module { - index, - error: err.as_u8(), - message: Some(err.as_str()), - } - } - } - impl ::frame_support::error::ModuleErrorMetadata for PalletError - where - ExtendedBalance: From>>, - { - fn metadata() -> &'static [::frame_support::error::ErrorMetadata] { - &[ - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("EarlySubmission"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[ - r" Submission was too early.", - ]), - }, - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("WeakSubmission"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[ - r" Submission was too weak, score-wise.", - ]), - }, - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("QueueFull"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[ - r" The queue was full, and the solution was not better than any of the existing ones.", - ]), - }, - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("CannotPayDeposit"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[ - r" The origin failed to pay the deposit.", - ]), - }, - ] - } - } - pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>) - where - ExtendedBalance: From>>; - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Module - where - ExtendedBalance: From>>, - { - #[inline] - fn clone(&self) -> Module { - match *self { - Module(ref __self_0_0) => Module(::core::clone::Clone::clone(&(*__self_0_0))), - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for Module where - ExtendedBalance: From>> - { - } - impl ::core::marker::StructuralPartialEq for Module where - ExtendedBalance: From>> - { - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Module - where - ExtendedBalance: From>>, - { - #[inline] - fn eq(&self, other: &Module) -> bool { - match *other { - Module(ref __self_1_0) => match *self { - Module(ref __self_0_0) => (*__self_0_0) == (*__self_1_0), - }, - } - } - #[inline] - fn ne(&self, other: &Module) -> bool { - match *other { - Module(ref __self_1_0) => match *self { - Module(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), - }, - } - } - } - impl ::core::marker::StructuralEq for Module where - ExtendedBalance: From>> - { - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Module - where - ExtendedBalance: From>>, - { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq< - ::frame_support::sp_std::marker::PhantomData<(T,)>, - >; - } - } - } - impl core::fmt::Debug for Module - where - ExtendedBalance: From>>, - T: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_tuple("Module").field(&self.0).finish() - } - } - impl - ::frame_support::traits::OnInitialize<::BlockNumber> for Module - where - ExtendedBalance: From>>, - { - fn on_initialize(now: T::BlockNumber) -> Weight { - let __within_span__ = { - use ::tracing::__macro_support::Callsite as _; - static CALLSITE: ::tracing::__macro_support::MacroCallsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "on_initialize", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(464u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - MacroCallsite::new(&META) - }; - let mut interest = ::tracing::subscriber::Interest::never(); - if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL - && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() - && { - interest = CALLSITE.interest(); - !interest.is_never() - } && CALLSITE.is_enabled(interest) - { - let meta = CALLSITE.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - let span = CALLSITE.disabled_span(); - {}; - span - } - }; - let __tracing_guard__ = __within_span__.enter(); - { - let next_election = T::ElectionDataProvider::next_election_prediction(now); - let next_election = next_election.max(now); - let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); - let unsigned_deadline = T::UnsignedPhase::get(); - let remaining = next_election - now; - match Self::current_phase() { - Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { - >::put(Phase::Signed); - Round::mutate(|r| *r += 1); - Self::start_signed_phase(); - { - let lvl = ::log::Level::Info; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::__private_api_log( - ::core::fmt::Arguments::new_v1( - &["\u{1f3e6} Starting signed phase at #", " , round "], - &match (&now, &Self::round()) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Display::fmt, - ), - ], - }, - ), - lvl, - &( - crate::LOG_TARGET, - "frame_election_providers::two_phase", - "frame/election-providers/src/two_phase/mod.rs", - 488u32, - ), - ); - } - }; - } - Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { - let found_solution = Self::finalize_signed_phase(); - >::put(Phase::Unsigned((!found_solution, now))); - { - let lvl = ::log::Level::Info; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::__private_api_log( - ::core::fmt::Arguments::new_v1( - &["\u{1f3e6} Starting unsigned phase at #"], - &match (&now,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - ), - lvl, - &( - crate::LOG_TARGET, - "frame_election_providers::two_phase", - "frame/election-providers/src/two_phase/mod.rs", - 497u32, - ), - ); - } - }; - } - _ => {} - } - Default::default() - } - } - } - impl ::frame_support::traits::OnRuntimeUpgrade for Module where - ExtendedBalance: From>> - { - } - impl - ::frame_support::traits::OnFinalize<::BlockNumber> for Module - where - ExtendedBalance: From>>, - { - } - impl - ::frame_support::traits::OffchainWorker<::BlockNumber> for Module - where - ExtendedBalance: From>>, - { - fn offchain_worker(n: T::BlockNumber) { - if Self::set_check_offchain_execution_status(n).is_ok() - && Self::current_phase().is_unsigned_open_at(n) - { - let _ = Self::mine_and_submit().map_err(|e| { - let lvl = ::log::Level::Error; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::__private_api_log( - ::core::fmt::Arguments::new_v1( - &["\u{1f3e6} error while submitting transaction in OCW: "], - &match (&e,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - ), - lvl, - &( - crate::LOG_TARGET, - "frame_election_providers::two_phase", - "frame/election-providers/src/two_phase/mod.rs", - 514u32, - ), - ); - } - }); - } - } - } - impl Module - where - ExtendedBalance: From>>, - { - /// Deposits an event using `frame_system::Module::deposit_event`. - fn deposit_event(event: impl Into<::Event>) { - >::deposit_event(event.into()) - } - } - #[cfg(feature = "std")] - impl ::frame_support::traits::IntegrityTest for Module where - ExtendedBalance: From>> - { - } - /// Can also be called using [`Call`]. - /// - /// [`Call`]: enum.Call.html - impl Module - where - ExtendedBalance: From>>, - { - /// Submit a solution for the signed phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// The solution potentially queued, based on the claimed score and processed at the end of - /// the signed phase. - /// - /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution - /// might be rewarded, slashed, or get all or a part of the deposit back. - /// - /// NOTE: Calling this function will bypass origin filters. - fn submit( - origin: T::Origin, - solution: RawSolution>, - ) -> DispatchResultWithPostInfo { - let __within_span__ = { - use ::tracing::__macro_support::Callsite as _; - static CALLSITE: ::tracing::__macro_support::MacroCallsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "submit", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(464u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - MacroCallsite::new(&META) - }; - let mut interest = ::tracing::subscriber::Interest::never(); - if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL - && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() - && { - interest = CALLSITE.interest(); - !interest.is_never() - } && CALLSITE.is_enabled(interest) - { - let meta = CALLSITE.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - let span = CALLSITE.disabled_span(); - {}; - span - } - }; - let __tracing_guard__ = __within_span__.enter(); - let who = ensure_signed(origin)?; - { - if !Self::current_phase().is_signed() { - { - return Err(PalletError::::EarlySubmission.into()); - }; - } - }; - let mut signed_submissions = Self::signed_submissions(); - let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution); - { - if !maybe_index.is_some() { - { - return Err("QueueFull".into()); - }; - } - }; - let index = maybe_index.expect("Option checked to be `Some`; qed."); - let deposit = signed_submissions[index].deposit; - T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; - if true { - if !(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()) { - { - :: std :: rt :: begin_panic ( "assertion failed: signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()" ) - } - }; - }; - >::put(signed_submissions); - Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Signed)); - Ok(None.into()) - } - #[allow(unreachable_code)] - /// Submit a solution for the unsigned phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. - /// Moreover, this unsigned solution is only validated when submitted to the pool from the - /// local process. Effectively, this means that only active validators can submit this - /// transaction when authoring a block. - /// - /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will - /// panic if the solution submitted by the validator is invalid, effectively putting their - /// authoring reward at risk. - /// - /// No deposit or reward is associated with this. - /// - /// NOTE: Calling this function will bypass origin filters. - fn submit_unsigned( - origin: T::Origin, - solution: RawSolution>, - ) -> ::frame_support::dispatch::DispatchResult { - let __within_span__ = { - use ::tracing::__macro_support::Callsite as _; - static CALLSITE: ::tracing::__macro_support::MacroCallsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "submit_unsigned", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(464u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - MacroCallsite::new(&META) - }; - let mut interest = ::tracing::subscriber::Interest::never(); - if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL - && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() - && { - interest = CALLSITE.interest(); - !interest.is_never() - } && CALLSITE.is_enabled(interest) - { - let meta = CALLSITE.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - let span = CALLSITE.disabled_span(); - {}; - span - } - }; - let __tracing_guard__ = __within_span__.enter(); - { - ensure_none(origin)?; - let _ = Self::pre_dispatch_checks(&solution)?; - let ready = Self::feasibility_check(solution, ElectionCompute::Unsigned).expect( - "Invalid unsigned submission must produce invalid block and deprive \ - validator from their authoring reward.", - ); - >::put(ready); - Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); - } - Ok(()) - } - } - /// Dispatchable calls. - /// - /// Each variant of this enum maps to a dispatchable function from the associated module. - pub enum Call - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[codec(skip)] - __PhantomItem( - ::frame_support::sp_std::marker::PhantomData<(T,)>, - ::frame_support::Never, - ), - #[allow(non_camel_case_types)] - /// Submit a solution for the signed phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// The solution potentially queued, based on the claimed score and processed at the end of - /// the signed phase. - /// - /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution - /// might be rewarded, slashed, or get all or a part of the deposit back. - submit(RawSolution>), - #[allow(non_camel_case_types)] - /// Submit a solution for the unsigned phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. - /// Moreover, this unsigned solution is only validated when submitted to the pool from the - /// local process. Effectively, this means that only active validators can submit this - /// transaction when authoring a block. - /// - /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will - /// panic if the solution submitted by the validator is invalid, effectively putting their - /// authoring reward at risk. - /// - /// No deposit or reward is associated with this. - submit_unsigned(RawSolution>), - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - { - fn encode_to(&self, dest: &mut EncOut) { - match *self { - Call::submit(ref aa) => { - dest.push_byte(0usize as u8); - dest.push(aa); - } - Call::submit_unsigned(ref aa) => { - dest.push_byte(1usize as u8); - dest.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - { - fn decode( - input: &mut DecIn, - ) -> core::result::Result { - match input.read_byte()? { - x if x == 0usize as u8 => Ok(Call::submit({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => return Err("Error decoding field Call :: submit.0".into()), - Ok(a) => a, - } - })), - x if x == 1usize as u8 => Ok(Call::submit_unsigned({ - let res = _parity_scale_codec::Decode::decode(input); - match res { - Err(_) => { - return Err("Error decoding field Call :: submit_unsigned.0".into()) - } - Ok(a) => a, - } - })), - x => Err("No such variant in enum Call".into()), - } - } - } - }; - impl ::frame_support::dispatch::GetDispatchInfo for Call - where - ExtendedBalance: From>>, - { - fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { - match *self { - Call::submit(ref solution) => { - let base_weight = T::WeightInfo::submit(); - let weight = >, - )>>::weigh_data(&base_weight, (solution,)); - let class = >, - )>>::classify_dispatch(&base_weight, (solution,)); - let pays_fee = >, - )>>::pays_fee(&base_weight, (solution,)); - ::frame_support::dispatch::DispatchInfo { - weight, - class, - pays_fee, - } - } - Call::submit_unsigned(ref solution) => { - let base_weight = T::WeightInfo::submit_unsigned(); - let weight = >, - )>>::weigh_data(&base_weight, (solution,)); - let class = >, - )>>::classify_dispatch(&base_weight, (solution,)); - let pays_fee = >, - )>>::pays_fee(&base_weight, (solution,)); - ::frame_support::dispatch::DispatchInfo { - weight, - class, - pays_fee, - } - } - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"__PhantomItem should never be used.",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - } - } - } - impl ::frame_support::dispatch::GetCallName for Call - where - ExtendedBalance: From>>, - { - fn get_call_name(&self) -> &'static str { - match *self { - Call::submit(ref solution) => { - let _ = (solution); - "submit" - } - Call::submit_unsigned(ref solution) => { - let _ = (solution); - "submit_unsigned" - } - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"__PhantomItem should never be used.",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - } - } - fn get_call_names() -> &'static [&'static str] { - &["submit", "submit_unsigned"] - } - } - impl ::frame_support::dispatch::Clone for Call - where - ExtendedBalance: From>>, - { - fn clone(&self) -> Self { - match *self { - Call::submit(ref solution) => Call::submit((*solution).clone()), - Call::submit_unsigned(ref solution) => Call::submit_unsigned((*solution).clone()), - _ => ::std::rt::begin_panic("internal error: entered unreachable code"), - } - } - } - impl ::frame_support::dispatch::PartialEq for Call - where - ExtendedBalance: From>>, - { - fn eq(&self, _other: &Self) -> bool { - match *self { - Call::submit(ref solution) => { - let self_params = (solution,); - if let Call::submit(ref solution) = *_other { - self_params == (solution,) - } else { - match *_other { - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic("internal error: entered unreachable code") - } - _ => false, - } - } - } - Call::submit_unsigned(ref solution) => { - let self_params = (solution,); - if let Call::submit_unsigned(ref solution) = *_other { - self_params == (solution,) - } else { - match *_other { - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic("internal error: entered unreachable code") - } - _ => false, - } - } - } - _ => ::std::rt::begin_panic("internal error: entered unreachable code"), - } - } - } - impl ::frame_support::dispatch::Eq for Call where - ExtendedBalance: From>> - { - } - impl ::frame_support::dispatch::fmt::Debug for Call - where - ExtendedBalance: From>>, - { - fn fmt( - &self, - _f: &mut ::frame_support::dispatch::fmt::Formatter, - ) -> ::frame_support::dispatch::result::Result<(), ::frame_support::dispatch::fmt::Error> { - match *self { - Call::submit(ref solution) => _f.write_fmt(::core::fmt::Arguments::new_v1( - &["", ""], - &match (&"submit", &(solution.clone(),)) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), - ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), - ], - }, - )), - Call::submit_unsigned(ref solution) => { - _f.write_fmt(::core::fmt::Arguments::new_v1( - &["", ""], - &match (&"submit_unsigned", &(solution.clone(),)) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), - ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), - ], - }, - )) - } - _ => ::std::rt::begin_panic("internal error: entered unreachable code"), - } - } - } - impl ::frame_support::traits::UnfilteredDispatchable for Call - where - ExtendedBalance: From>>, - { - type Origin = T::Origin; - fn dispatch_bypass_filter( - self, - _origin: Self::Origin, - ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { - match self { - Call::submit(solution) => >::submit(_origin, solution) - .map(Into::into) - .map_err(Into::into), - Call::submit_unsigned(solution) => >::submit_unsigned(_origin, solution) - .map(Into::into) - .map_err(Into::into), - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"__PhantomItem should never be used.",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - } - } - } - impl ::frame_support::dispatch::Callable for Module - where - ExtendedBalance: From>>, - { - type Call = Call; - } - impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[allow(dead_code)] - pub fn call_functions() -> &'static [::frame_support::dispatch::FunctionMetadata] { - &[ - ::frame_support::dispatch::FunctionMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("submit"), - arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - ::frame_support::dispatch::FunctionArgumentMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), - ty: ::frame_support::dispatch::DecodeDifferent::Encode( - "RawSolution>", - ), - }, - ]), - documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - r" Submit a solution for the signed phase.", - r"", - r" The dispatch origin fo this call must be __signed__.", - r"", - r" The solution potentially queued, based on the claimed score and processed at the end of", - r" the signed phase.", - r"", - r" A deposit is reserved and recorded for the solution. Based on the outcome, the solution", - r" might be rewarded, slashed, or get all or a part of the deposit back.", - ]), - }, - ::frame_support::dispatch::FunctionMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("submit_unsigned"), - arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - ::frame_support::dispatch::FunctionArgumentMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), - ty: ::frame_support::dispatch::DecodeDifferent::Encode( - "RawSolution>", - ), - }, - ]), - documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - r" Submit a solution for the unsigned phase.", - r"", - r" The dispatch origin fo this call must be __signed__.", - r"", - r" This submission is checked on the fly, thus it is likely yo be more limited and smaller.", - r" Moreover, this unsigned solution is only validated when submitted to the pool from the", - r" local process. Effectively, this means that only active validators can submit this", - r" transaction when authoring a block.", - r"", - r" To prevent any incorrect solution (and thus wasted time/weight), this transaction will", - r" panic if the solution submitted by the validator is invalid, effectively putting their", - r" authoring reward at risk.", - r"", - r" No deposit or reward is associated with this.", - ]), - }, - ] - } - } - impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[allow(dead_code)] - pub fn module_constants_metadata( - ) -> &'static [::frame_support::dispatch::ModuleConstantMetadata] { - &[] - } - } - impl ::frame_support::dispatch::ModuleErrorMetadata for Module - where - ExtendedBalance: From>>, - { - fn metadata() -> &'static [::frame_support::dispatch::ErrorMetadata] { - as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() - } - } - impl Module - where - ExtendedBalance: From>>, - { - /// Checks the feasibility of a solution. - /// - /// This checks the solution for the following: - /// - /// 0. **all** of the used indices must be correct. - /// 1. present correct number of winners. - /// 2. any assignment is checked to match with `SnapshotVoters`. - /// 3. for each assignment, the check of `ElectionDataProvider` is also examined. - /// 4. the claimed score is valid. - fn feasibility_check( - solution: RawSolution>, - compute: ElectionCompute, - ) -> Result, FeasibilityError> { - let RawSolution { compact, score } = solution; - let winners = compact.unique_targets(); - { - if !(winners.len() as u32 == Self::desired_targets()) { - { - return Err(FeasibilityError::WrongWinnerCount.into()); - }; - } - }; - let snapshot_voters = - Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; - let snapshot_targets = - Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - let voter_at = |i: crate::two_phase::CompactVoterIndexOf| -> Option { - as crate::TryInto>::try_into(i) - .ok() - .and_then(|i| snapshot_voters.get(i).map(|(x, _, _)| x).cloned()) - }; - let target_at = |i: crate::two_phase::CompactTargetIndexOf| -> Option { - as crate::TryInto>::try_into(i) - .ok() - .and_then(|i| snapshot_targets.get(i).cloned()) - }; - let winners = winners - .into_iter() - .map(|i| target_at(i).ok_or(FeasibilityError::InvalidWinner)) - .collect::, FeasibilityError>>()?; - let assignments = compact - .into_assignment(voter_at, target_at) - .map_err::(Into::into)?; - let _ = assignments - .iter() - .map(|Assignment { who, distribution }| { - snapshot_voters.iter().find(|(v, _, _)| v == who).map_or( - Err(FeasibilityError::InvalidVoter), - |(_, _, t)| { - if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) - && T::ElectionDataProvider::feasibility_check_assignment::< - CompactAccuracyOf, - >(who, distribution) - { - Ok(()) - } else { - Err(FeasibilityError::InvalidVote) - } - }, - ) - }) - .collect::>()?; - let stake_of = |who: &T::AccountId| -> crate::VoteWeight { - snapshot_voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - }; - let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) - .map_err::(Into::into)?; - let supports = sp_npos_elections::to_supports(&winners, &staked_assignments) - .map_err::(Into::into)?; - let known_score = supports.evaluate(); - ( - match known_score { - tmp => { - { - ::std::io::_eprint(::core::fmt::Arguments::new_v1_formatted( - &["[", ":", "] ", " = ", "\n"], - &match ( - &"frame/election-providers/src/two_phase/mod.rs", - &674u32, - &"known_score", - &&tmp, - ) { - (arg0, arg1, arg2, arg3) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg2, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new(arg3, ::core::fmt::Debug::fmt), - ], - }, - &[ - ::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 1usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 2usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 3usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ], - )); - }; - tmp - } - }, - match score { - tmp => { - { - ::std::io::_eprint(::core::fmt::Arguments::new_v1_formatted( - &["[", ":", "] ", " = ", "\n"], - &match ( - &"frame/election-providers/src/two_phase/mod.rs", - &674u32, - &"score", - &&tmp, - ) { - (arg0, arg1, arg2, arg3) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg2, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new(arg3, ::core::fmt::Debug::fmt), - ], - }, - &[ - ::core::fmt::rt::v1::Argument { - position: 0usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 1usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 2usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 0u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ::core::fmt::rt::v1::Argument { - position: 3usize, - format: ::core::fmt::rt::v1::FormatSpec { - fill: ' ', - align: ::core::fmt::rt::v1::Alignment::Unknown, - flags: 4u32, - precision: ::core::fmt::rt::v1::Count::Implied, - width: ::core::fmt::rt::v1::Count::Implied, - }, - }, - ], - )); - }; - tmp - } - }, - ); - { - if !(known_score == score) { - { - return Err(FeasibilityError::InvalidScore.into()); - }; - } - }; - Ok(ReadySolution { - supports, - compute, - score, - }) - } - /// On-chain fallback of election. - fn onchain_fallback() -> Result, Error> { - let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - >::elect::( - desired_targets, - targets, - voters, - ) - .map_err(Into::into) - } - } - impl ElectionProvider for Module - where - ExtendedBalance: From>>, - { - const NEEDS_ELECT_DATA: bool = false; - type Error = Error; - fn elect( - _to_elect: usize, - _targets: Vec, - _voters: Vec<(T::AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>, - { - Self::queued_solution() - .map_or_else( - || { - Self::onchain_fallback() - .map(|r| (r, ElectionCompute::OnChain)) - .map_err(Into::into) - }, - |ReadySolution { - supports, compute, .. - }| Ok((supports, compute)), - ) - .map(|(supports, compute)| { - >::put(Phase::Off); - >::kill(); - >::kill(); - Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); - { - let lvl = ::log::Level::Info; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::__private_api_log( - ::core::fmt::Arguments::new_v1( - &["\u{1f3e6} Finalized election round with compute ", "."], - &match (&compute,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - ), - lvl, - &( - crate::LOG_TARGET, - "frame_election_providers::two_phase", - "frame/election-providers/src/two_phase/mod.rs", - 731u32, - ), - ); - } - }; - supports - }) - .map_err(|err| { - Self::deposit_event(RawEvent::ElectionFinalized(None)); - { - let lvl = ::log::Level::Error; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::__private_api_log( - ::core::fmt::Arguments::new_v1( - &["\u{1f3e6} Failed to finalize election round. Error = "], - &match (&err,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - ), - lvl, - &( - crate::LOG_TARGET, - "frame_election_providers::two_phase", - "frame/election-providers/src/two_phase/mod.rs", - 736u32, - ), - ); - } - }; - err - }) - } - fn ongoing() -> bool { - match Self::current_phase() { - Phase::Signed | Phase::Unsigned(_) => true, - _ => false, - } - } - } - #[cfg(test)] - mod tests { - use super::{mock::*, *}; - use sp_election_providers::ElectionProvider; - use sp_npos_elections::Support; - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const phase_rotation_works: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::tests::phase_rotation_works"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(phase_rotation_works())), - }; - fn phase_rotation_works() { - ExtBuilder::default().build_and_execute(|| { - { - match (&System::block_number(), &0) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&TwoPhase::current_phase(), &Phase::Off) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - { - match (&TwoPhase::round(), &0) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - roll_to(4); - { - match (&TwoPhase::current_phase(), &Phase::Off) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::snapshot_voters().is_none() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::snapshot_voters().is_none()", - ) - } - }; - { - match (&TwoPhase::round(), &0) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::snapshot_voters().is_some() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::snapshot_voters().is_some()", - ) - } - }; - { - match (&TwoPhase::round(), &1) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - roll_to(14); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::snapshot_voters().is_some() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::snapshot_voters().is_some()", - ) - } - }; - { - match (&TwoPhase::round(), &1) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - roll_to(15); - { - match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::snapshot_voters().is_some() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::snapshot_voters().is_some()", - ) - } - }; - roll_to(19); - { - match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::snapshot_voters().is_some() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::snapshot_voters().is_some()", - ) - } - }; - roll_to(20); - { - match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::snapshot_voters().is_some() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::snapshot_voters().is_some()", - ) - } - }; - roll_to(21); - { - match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::snapshot_voters().is_some() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::snapshot_voters().is_some()", - ) - } - }; - TwoPhase::elect::(2, Default::default(), Default::default()) - .unwrap(); - { - match (&TwoPhase::current_phase(), &Phase::Off) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - if !TwoPhase::snapshot_voters().is_none() { - { - ::std::rt::begin_panic( - "assertion failed: TwoPhase::snapshot_voters().is_none()", - ) - } - }; - { - match (&TwoPhase::round(), &1) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - }) - } - extern crate test; - #[cfg(test)] - #[rustc_test_marker] - pub const onchain_backup_works: test::TestDescAndFn = test::TestDescAndFn { - desc: test::TestDesc { - name: test::StaticTestName("two_phase::tests::onchain_backup_works"), - ignore: false, - allow_fail: false, - should_panic: test::ShouldPanic::No, - test_type: test::TestType::UnitTest, - }, - testfn: test::StaticTestFn(|| test::assert_test_result(onchain_backup_works())), - }; - fn onchain_backup_works() { - ExtBuilder::default().build_and_execute(|| { - roll_to(5); - { - match (&TwoPhase::current_phase(), &Phase::Signed) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - roll_to(20); - { - match (&TwoPhase::current_phase(), &Phase::Unsigned((true, 15))) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - }; - let supports = TwoPhase::elect::( - 2, - Default::default(), - Default::default(), - ) - .unwrap(); - { - match ( - &supports, - &<[_]>::into_vec(box [ - ( - 30, - Support { - total: 40, - voters: <[_]>::into_vec(box [(2, 5), (4, 5), (30, 30)]), - }, - ), - ( - 40, - Support { - total: 60, - voters: <[_]>::into_vec(box [ - (2, 5), - (3, 10), - (4, 5), - (40, 40), - ]), - }, - ), - ]), - ) { - (left_val, right_val) => { - if !(*left_val == *right_val) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &[ - "assertion failed: `(left == right)`\n left: `", - "`,\n right: `", - "`", - ], - &match (&&*left_val, &&*right_val) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Debug::fmt, - ), - ], - }, - )) - } - } - } - } - } - }) - } - } -} -const LOG_TARGET: &'static str = "election-provider"; -#[doc(hidden)] -pub use sp_npos_elections::VoteWeight; -#[doc(hidden)] -pub use sp_runtime::traits::UniqueSaturatedInto; -#[doc(hidden)] -pub use sp_std::convert::TryInto; -#[main] -pub fn main() -> () { - extern crate test; - test::test_main_static(&[ - &test_benchmarks, - &cannot_submit_too_early, - &should_pay_deposit, - &good_solution_is_rewarded, - &bad_solution_is_slashed, - &suppressed_solution_gets_bond_back, - &queue_is_always_sorted, - &cannot_submit_worse_with_full_queue, - &weakest_is_removed_if_better_provided, - &equally_good_is_not_accepted, - &solutions_are_always_sorted, - &all_in_one_singed_submission_scenario, - &validate_unsigned_retracts_wrong_phase, - &validate_unsigned_retracts_low_score, - &priority_is_set, - &invalid_solution_panics, - &miner_works, - &ocw_will_only_submit_if_feasible, - &can_only_submit_threshold_better, - &ocw_check_prevent_duplicate, - &ocw_only_runs_when_signed_open_now, - &ocw_can_submit_to_pool, - &phase_rotation_works, - &onchain_backup_works, - ]) -} diff --git a/frame/election-providers/expanded.rs b/frame/election-providers/expanded.rs deleted file mode 100644 index d66dc691d10bf..0000000000000 --- a/frame/election-providers/expanded.rs +++ /dev/null @@ -1,4247 +0,0 @@ -#![feature(prelude_import)] -//! Various implementation for `ElectionProvider`. -//! -//! Two main election providers are implemented in this crate. -//! -//! 1. [`onchain`]: A `struct` that perform the election onchain (i.e. in the fly). This type is -//! likely to be expensive for most chains and damage the block time. Only use when you are sure -//! that the inputs are bounded and small enough. -//! 2. [`two_phase`]: An individual `pallet` that performs the election in two phases, signed and -//! unsigned. Needless to say, the pallet needs to be included in the final runtime. -#[prelude_import] -use std::prelude::v1::*; -#[macro_use] -extern crate std; -/// The onchain module. -pub mod onchain { - use sp_arithmetic::PerThing; - use sp_election_providers::ElectionProvider; - use sp_npos_elections::{ - ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Supports, VoteWeight, - }; - use sp_runtime::RuntimeDebug; - use sp_std::{collections::btree_map::BTreeMap, prelude::*}; - /// Errors of the on-chain election. - pub enum Error { - /// An internal error in the NPoS elections crate. - NposElections(sp_npos_elections::Error), - } - impl core::fmt::Debug for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::NposElections(ref a0) => { - fmt.debug_tuple("Error::NposElections").field(a0).finish() - } - _ => Ok(()), - } - } - } - impl ::core::marker::StructuralEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Error { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - } - } - } - impl ::core::marker::StructuralPartialEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Error { - #[inline] - fn eq(&self, other: &Error) -> bool { - match (&*self, &*other) { - (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - } - } - #[inline] - fn ne(&self, other: &Error) -> bool { - match (&*self, &*other) { - (&Error::NposElections(ref __self_0), &Error::NposElections(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - } - } - } - impl From for Error { - fn from(e: sp_npos_elections::Error) -> Self { - Error::NposElections(e) - } - } - /// A simple on-chian implementation of the election provider trait. - /// - /// This will accept voting data on the fly and produce the results immediately. - /// - /// ### Warning - /// - /// This can be very expensive to run frequently on-chain. Use with care. - pub struct OnChainSequentialPhragmen; - impl ElectionProvider for OnChainSequentialPhragmen { - type Error = Error; - const NEEDS_ELECT_DATA: bool = true; - fn elect( - to_elect: usize, - targets: Vec, - voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>, - { - let mut stake_map: BTreeMap = BTreeMap::new(); - voters.iter().for_each(|(v, s, _)| { - stake_map.insert(v.clone(), *s); - }); - let stake_of = Box::new(|w: &AccountId| -> VoteWeight { - stake_map.get(w).cloned().unwrap_or_default() - }); - sp_npos_elections::seq_phragmen::<_, P>(to_elect, targets, voters, None) - .and_then(|e| { - let ElectionResult { - winners, - assignments, - } = e; - let staked = sp_npos_elections::assignment_ratio_to_staked_normalized( - assignments, - &stake_of, - )?; - let winners = sp_npos_elections::to_without_backing(winners); - sp_npos_elections::to_supports(&winners, &staked) - }) - .map_err(From::from) - } - fn ongoing() -> bool { - false - } - } -} -/// The two-phase module. -pub mod two_phase { - //! # Two phase election provider pallet. - //! - //! As the name suggests, this election-provider has two distinct phases (see [`Phase`]), signed and - //! unsigned. - //! - //! ## Phases - //! - //! The timeline of pallet is as follows. At each block, - //! [`ElectionDataProvider::next_election_prediction`] is used to estimate the time remaining to the - //! next call to `elect`. Based on this, a phase is chosen. The timeline is as follows. - //! - //! ```ignore - //! elect() - //! + <--T::SignedPhase--> + <--T::UnsignedPhase--> + - //! +-------------------------------------------------------------------+ - //! Phase::Off + Phase::Signed + Phase::Unsigned + - //! - //! Note that the unsigned phase starts `T::UnsignedPhase` blocks before the - //! `next_election_prediction`, but only ends when a call to `ElectionProvider::elect` happens. - //! - //! ``` - //! ### Signed Phase - //! - //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A - //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution - //! on-chain for a number of blocks. A maximum of [`Config::MaxSignedSubmissions`] solutions are - //! stored. The queue is always sorted based on score (worse to best). - //! - //! Upon arrival of a new solution: - //! - //! 1. If the queue is not full, it is stored in the appropriate index. - //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the - //! worse solution is discarded (TODO: must return the bond here) and the new solution is stored - //! in the correct index. - //! 3. If the queue is full and the solution is not an improvement compared to any of the queued - //! ones, it is instantly rejected and no additional bond is reserved. - //! - //! A signed solution cannot be reversed, taken back, updated, or retracted. In other words, the - //! origin can not bail out in any way. - //! - //! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed - //! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure - //! the score claimed by this score was correct, among other checks. At each step, if the current - //! best solution passes the feasibility check, it is considered to be the best one. The sender - //! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without - //! being checked. - //! - //! The following example covers all of the cases at the end of the signed phase: - //! - //! ```ignore - //! Queue - //! +-------------------------------+ - //! |Solution(score=20, valid=false)| +--> Slashed - //! +-------------------------------+ - //! |Solution(score=15, valid=true )| +--> Rewarded - //! +-------------------------------+ - //! |Solution(score=10, valid=true )| +--> Discarded - //! +-------------------------------+ - //! |Solution(score=05, valid=false)| +--> Discarded - //! +-------------------------------+ - //! | None | - //! +-------------------------------+ - //! ``` - //! - //! TODO: what if length of some phase is zero? - //! - //! Note that both of the bottom solutions end up being discarded and get their deposit back, - //! despite one of them being invalid. - //! - //! ## Unsigned Phase - //! - //! If signed phase ends with a good solution, then the unsigned phase will be `active` - //! ([`Phase::Unsigned(true)`]), else the unsigned phase will be `passive`. - //! - //! TODO - //! - //! ### Fallback - //! - //! If we reach the end of both phases (i.e. call to `ElectionProvider::elect` happens) and no good - //! solution is queued, then we fallback to an on-chain election. The on-chain election is slow, and - //! contains to balancing or reduction post-processing. - //! - //! ## Correct Submission - //! - //! TODO - //! - //! ## Accuracy - //! - //! TODO - //! - use crate::onchain::OnChainSequentialPhragmen; - use codec::{Decode, Encode, HasCompact}; - use frame_support::{ - decl_event, decl_module, decl_storage, - dispatch::DispatchResultWithPostInfo, - ensure, - traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, - weights::Weight, - }; - use frame_system::{ensure_none, ensure_signed, offchain::SendTransactionTypes}; - use sp_election_providers::{ElectionDataProvider, ElectionProvider}; - use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, is_score_better, Assignment, CompactSolution, - ElectionScore, EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, - }; - use sp_runtime::{ - traits::Zero, transaction_validity::TransactionPriority, InnerOf, PerThing, Perbill, - RuntimeDebug, - }; - use sp_std::prelude::*; - #[macro_use] - pub(crate) mod macros { - //! Some helper macros for this crate. - } - pub mod signed { - //! The signed phase implementation. - use crate::two_phase::*; - use codec::Encode; - use sp_arithmetic::traits::SaturatedConversion; - use sp_npos_elections::is_score_better; - use sp_runtime::Perbill; - impl Module - where - ExtendedBalance: From>>, - { - /// Start the signed phase. - /// - /// Upon calling this, auxillary data for election is stored and signed solutions will be - /// accepted. - /// - /// The signed phase must always start before the unsigned phase. - pub fn start_signed_phase() { - let targets = T::ElectionDataProvider::targets(); - let voters = T::ElectionDataProvider::voters(); - let desired_targets = T::ElectionDataProvider::desired_targets(); - >::put(RoundSnapshot { - voters, - targets, - desired_targets, - }); - } - /// Finish the singed phase. Process the signed submissions from best to worse until a valid one - /// is found, rewarding the best oen and slashing the invalid ones along the way. - /// - /// Returns true if we have a good solution in the signed phase. - /// - /// This drains the [`SignedSubmissions`], potentially storing the best valid one in - /// [`QueuedSolution`]. - pub fn finalize_signed_phase() -> bool { - let mut all_submission: Vec> = - >::take(); - let mut found_solution = false; - while let Some(best) = all_submission.pop() { - let SignedSubmission { - solution, - who, - deposit, - reward, - } = best; - match Self::feasibility_check(solution, ElectionCompute::Signed) { - Ok(ready_solution) => { - >::put(ready_solution); - let _remaining = T::Currency::unreserve(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic( - "assertion failed: _remaining.is_zero()", - ) - } - }; - }; - let positive_imbalance = T::Currency::deposit_creating(&who, reward); - T::RewardHandler::on_unbalanced(positive_imbalance); - found_solution = true; - break; - } - Err(_) => { - let (negative_imbalance, _remaining) = - T::Currency::slash_reserved(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic( - "assertion failed: _remaining.is_zero()", - ) - } - }; - }; - T::SlashHandler::on_unbalanced(negative_imbalance); - } - } - } - all_submission.into_iter().for_each(|not_processed| { - let SignedSubmission { who, deposit, .. } = not_processed; - let _remaining = T::Currency::unreserve(&who, deposit); - if true { - if !_remaining.is_zero() { - { - ::std::rt::begin_panic("assertion failed: _remaining.is_zero()") - } - }; - }; - }); - found_solution - } - /// Find a proper position in the queue for the signed queue, whilst maintaining the order of - /// solution quality. - /// - /// The length of the queue will always be kept less than or equal to `T::MaxSignedSubmissions`. - pub fn insert_submission( - who: &T::AccountId, - queue: &mut Vec, CompactOf>>, - solution: RawSolution>, - ) -> Option { - let outcome = queue - .iter() - .enumerate() - .rev() - .find_map(|(i, s)| { - if is_score_better::( - solution.score, - s.solution.score, - T::SolutionImprovementThreshold::get(), - ) { - Some(i + 1) - } else { - None - } - }) - .or(Some(0)) - .and_then(|at| { - if at == 0 && queue.len() as u32 >= T::MaxSignedSubmissions::get() { - None - } else { - let reward = Self::reward_for(&solution); - let deposit = Self::deposit_for(&solution); - let submission = SignedSubmission { - who: who.clone(), - deposit, - reward, - solution, - }; - queue.insert(at, submission); - if queue.len() as u32 > T::MaxSignedSubmissions::get() { - queue.remove(0); - Some(at - 1) - } else { - Some(at) - } - } - }); - if true { - if !(queue.len() as u32 <= T::MaxSignedSubmissions::get()) { - { - :: std :: rt :: begin_panic ( "assertion failed: queue.len() as u32 <= T::MaxSignedSubmissions::get()" ) - } - }; - }; - outcome - } - /// Collect sufficient deposit to store this solution this chain. - /// - /// The deposit is composed of 3 main elements: - /// - /// 1. base deposit, fixed for all submissions. - /// 2. a per-byte deposit, for renting the state usage. - /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize - pub fn deposit_for(solution: &RawSolution>) -> BalanceOf { - let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); - let feasibility_weight = T::WeightInfo::feasibility_check(); - let len_deposit = T::SignedDepositByte::get() * encoded_len; - let weight_deposit = - T::SignedDepositWeight::get() * feasibility_weight.saturated_into(); - T::SignedDepositBase::get() + len_deposit + weight_deposit - } - /// The reward for this solution, if successfully chosen as the best one at the end of the - /// signed phase. - pub fn reward_for(solution: &RawSolution>) -> BalanceOf { - T::SignedRewardBase::get() - + T::SignedRewardFactor::get() - * solution.score[0].saturated_into::>() - } - } - } - pub mod unsigned { - //! The unsigned phase implementation. - use crate::two_phase::*; - use frame_support::{dispatch::DispatchResult, unsigned::ValidateUnsigned}; - use frame_system::offchain::SubmitTransaction; - use sp_npos_elections::{seq_phragmen, CompactSolution, ElectionResult}; - use sp_runtime::{ - offchain::storage::StorageValueRef, - traits::TrailingZeroInput, - transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionValidity, - TransactionValidityError, ValidTransaction, - }, - SaturatedConversion, - }; - use sp_std::cmp::Ordering; - /// Storage key used to store the persistent offchain worker status. - pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; - /// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice - /// within a window of 5 blocks. - pub(crate) const OFFCHAIN_REPEAT: u32 = 5; - /// Default number of blocks for which the unsigned transaction should stay in the pool - pub(crate) const DEFAULT_LONGEVITY: u64 = 25; - impl Module - where - ExtendedBalance: From>>, - { - /// Min a new npos solution. - pub fn mine_solution(iters: usize) -> Result>, Error> { - let desired_targets = Self::desired_targets() as usize; - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - seq_phragmen::<_, CompactAccuracyOf>( - desired_targets, - targets, - voters, - Some((iters, 0)), - ) - .map_err(Into::into) - .and_then(Self::prepare_election_result) - } - /// Convert a raw solution from [`sp_npos_elections::ElectionResult`] to [`RawSolution`], which - /// is ready to be submitted to the chain. - /// - /// Will always reduce the solution as well. - pub fn prepare_election_result( - election_result: ElectionResult>, - ) -> Result>, Error> { - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let targets = Self::snapshot_targets().ok_or(Error::SnapshotUnAvailable)?; - let voter_index = - |who: &T::AccountId| -> Option> { - voters . iter ( ) . position ( | ( x , _ , _ ) | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactVoterIndexOf < T > > > :: try_into ( i ) . ok ( ) ) - }; - let target_index = - |who: &T::AccountId| -> Option> { - targets . iter ( ) . position ( | x | x == who ) . and_then ( | i | < usize as crate :: TryInto < crate :: two_phase :: CompactTargetIndexOf < T > > > :: try_into ( i ) . ok ( ) ) - }; - let voter_at = - |i: crate::two_phase::CompactVoterIndexOf| -> Option { - < crate :: two_phase :: CompactVoterIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | voters . get ( i ) . map ( | ( x , _ , _ ) | x ) . cloned ( ) ) - }; - let target_at = - |i: crate::two_phase::CompactTargetIndexOf| -> Option { - < crate :: two_phase :: CompactTargetIndexOf < T > as crate :: TryInto < usize > > :: try_into ( i ) . ok ( ) . and_then ( | i | targets . get ( i ) . cloned ( ) ) - }; - let stake_of = |who: &T::AccountId| -> crate::VoteWeight { - voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - }; - let ElectionResult { - assignments, - winners, - } = election_result; - let mut staked = sp_npos_elections::assignment_ratio_to_staked_normalized( - assignments, - &stake_of, - ) - .map_err::(Into::into)?; - sp_npos_elections::reduce(&mut staked); - let ratio = sp_npos_elections::assignment_staked_to_ratio_normalized(staked)?; - let compact = >::from_assignment(ratio, &voter_index, &target_index)?; - let maximum_allowed_voters = - Self::maximum_compact_len::(0, Default::default(), 0); - let compact = Self::trim_compact(compact.len() as u32, compact, &voter_index)?; - let winners = sp_npos_elections::to_without_backing(winners); - let score = compact - .clone() - .score(&winners, stake_of, voter_at, target_at)?; - Ok(RawSolution { compact, score }) - } - /// Get a random number of iterations to run the balancing in the OCW. - /// - /// Uses the offchain seed to generate a random number, maxed with `T::UnsignedMaxIterations`. - pub fn get_balancing_iters() -> usize { - match T::UnsignedMaxIterations::get() { - 0 => 0, - max @ _ => { - let seed = sp_io::offchain::random_seed(); - let random = ::decode(&mut TrailingZeroInput::new(seed.as_ref())) - .expect("input is padded with zeroes; qed") - % max.saturating_add(1); - random as usize - } - } - } - /// Greedily reduce the size of the a solution to fit into the block, w.r.t. weight. - /// - /// The weight of the solution is foremost a function of the number of voters (i.e. - /// `compact.len()`). Aside from this, the other components of the weight are invariant. The - /// number of winners shall not be changed (otherwise the solution is invalid) and the - /// `ElectionSize` is merely a representation of the total number of stakers. - /// - /// Thus, we reside to stripping away some voters. This means only changing the `compact` - /// struct. - /// - /// Note that the solution is already computed, and the winners are elected based on the merit - /// of teh entire stake in the system. Nonetheless, some of the voters will be removed further - /// down the line. - /// - /// Indeed, the score must be computed **after** this step. If this step reduces the score too - /// much, then the solution will be discarded. - pub fn trim_compact( - maximum_allowed_voters: u32, - mut compact: CompactOf, - nominator_index: FN, - ) -> Result, Error> - where - for<'r> FN: Fn(&'r T::AccountId) -> Option>, - { - match compact.len().checked_sub(maximum_allowed_voters as usize) { - Some(to_remove) if to_remove > 0 => { - let voters = Self::snapshot_voters().ok_or(Error::SnapshotUnAvailable)?; - let mut voters_sorted = voters - .into_iter() - .map(|(who, stake, _)| (who.clone(), stake)) - .collect::>(); - voters_sorted.sort_by_key(|(_, y)| *y); - let mut removed = 0; - for (maybe_index, _stake) in voters_sorted - .iter() - .map(|(who, stake)| (nominator_index(&who), stake)) - { - let index = maybe_index.ok_or(Error::SnapshotUnAvailable)?; - if compact.remove_voter(index) { - removed += 1 - } - if removed >= to_remove { - break; - } - } - Ok(compact) - } - _ => Ok(compact), - } - } - /// Find the maximum `len` that a compact can have in order to fit into the block weight. - /// - /// This only returns a value between zero and `size.nominators`. - pub fn maximum_compact_len( - _winners_len: u32, - witness: WitnessData, - max_weight: Weight, - ) -> u32 { - if witness.voters < 1 { - return witness.voters; - } - let max_voters = witness.voters.max(1); - let mut voters = max_voters; - let weight_with = |_voters: u32| -> Weight { W::submit_unsigned() }; - let next_voters = - |current_weight: Weight, voters: u32, step: u32| -> Result { - match current_weight.cmp(&max_weight) { - Ordering::Less => { - let next_voters = voters.checked_add(step); - match next_voters { - Some(voters) if voters < max_voters => Ok(voters), - _ => Err(()), - } - } - Ordering::Greater => voters.checked_sub(step).ok_or(()), - Ordering::Equal => Ok(voters), - } - }; - let mut step = voters / 2; - let mut current_weight = weight_with(voters); - while step > 0 { - match next_voters(current_weight, voters, step) { - Ok(next) if next != voters => { - voters = next; - } - Err(()) => { - break; - } - Ok(next) => return next, - } - step = step / 2; - current_weight = weight_with(voters); - } - while voters + 1 <= max_voters && weight_with(voters + 1) < max_weight { - voters += 1; - } - while voters.checked_sub(1).is_some() && weight_with(voters) > max_weight { - voters -= 1; - } - if true { - if !(weight_with(voters.min(witness.voters)) <= max_weight) { - { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["weight_with(", ") <= "], - &match (&voters.min(witness.voters), &max_weight) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Display::fmt, - ), - ], - }, - )) - } - }; - }; - voters.min(witness.voters) - } - /// Checks if an execution of the offchain worker is permitted at the given block number, or not. - /// - /// This essentially makes sure that we don't run on previous blocks in case of a re-org, and we - /// don't run twice within a window of length [`OFFCHAIN_REPEAT`]. - /// - /// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise. - pub(crate) fn set_check_offchain_execution_status( - now: T::BlockNumber, - ) -> Result<(), &'static str> { - let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); - let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT); - let mutate_stat = storage.mutate::<_, &'static str, _>( - |maybe_head: Option>| match maybe_head { - Some(Some(head)) if now < head => Err("fork."), - Some(Some(head)) if now >= head && now <= head + threshold => { - Err("recently executed.") - } - Some(Some(head)) if now > head + threshold => Ok(now), - _ => Ok(now), - }, - ); - match mutate_stat { - Ok(Ok(_)) => Ok(()), - Ok(Err(_)) => Err("failed to write to offchain db."), - Err(why) => Err(why), - } - } - /// Mine a new solution, and submit it back to the chian as an unsigned transaction. - pub(crate) fn mine_and_submit() -> Result<(), Error> { - let balancing = Self::get_balancing_iters(); - let raw_solution = Self::mine_solution(balancing)?; - let call = Call::submit_unsigned(raw_solution).into(); - SubmitTransaction::>::submit_unsigned_transaction(call) - .map_err(|_| Error::PoolSubmissionFailed) - } - pub(crate) fn unsigned_pre_dispatch_checks( - solution: &RawSolution>, - ) -> DispatchResult { - { - if !Self::current_phase().is_unsigned_open() { - { - return Err(PalletError::::EarlySubmission.into()); - }; - } - }; - { - if !Self::queued_solution().map_or(true, |q: ReadySolution<_>| { - is_score_better::( - solution.score, - q.score, - T::SolutionImprovementThreshold::get(), - ) - }) { - { - return Err(PalletError::::WeakSubmission.into()); - }; - } - }; - Ok(()) - } - } - #[allow(deprecated)] - impl ValidateUnsigned for Module - where - ExtendedBalance: From>>, - { - type Call = Call; - fn validate_unsigned( - source: TransactionSource, - call: &Self::Call, - ) -> TransactionValidity { - if let Call::submit_unsigned(solution) = call { - match source { - TransactionSource::Local | TransactionSource::InBlock => {} - _ => { - return InvalidTransaction::Call.into(); - } - } - if let Err(_why) = Self::pre_dispatch_checks(solution) { - return InvalidTransaction::Custom(99).into(); - } - ValidTransaction::with_tag_prefix("OffchainElection") - .priority( - T::UnsignedPriority::get() - .saturating_add(solution.score[0].saturated_into()), - ) - .longevity(DEFAULT_LONGEVITY) - .propagate(false) - .build() - } else { - InvalidTransaction::Call.into() - } - } - fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { - if let Call::submit_unsigned(solution) = call { - Self::pre_dispatch_checks(solution) - .map_err(|_| InvalidTransaction::Custom(99).into()) - } else { - Err(InvalidTransaction::Call.into()) - } - } - } - } - /// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] - /// implementer. - pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< - ::AccountId, - ::BlockNumber, - >>::CompactSolution; - /// The voter index. Derived from [`CompactOf`]. - pub type CompactVoterIndexOf = as CompactSolution>::Voter; - /// The target index. Derived from [`CompactOf`]. - pub type CompactTargetIndexOf = as CompactSolution>::Target; - /// The accuracy of the election. Derived from [`CompactOf`]. - pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; - type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; - type PositiveImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::PositiveImbalance; - type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, - >>::NegativeImbalance; - /// Current phase of the pallet. - pub enum Phase { - /// Nothing, the election is not happening. - Off, - /// Signed phase is open. - Signed, - /// Unsigned phase. First element is whether it is open or not, second the starting block - /// number. - Unsigned((bool, Bn)), - } - impl ::core::marker::StructuralPartialEq for Phase {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Phase { - #[inline] - fn eq(&self, other: &Phase) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &Phase) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Phase::Unsigned(ref __self_0), &Phase::Unsigned(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - _ => false, - } - } else { - true - } - } - } - } - impl ::core::marker::StructuralEq for Phase {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Phase { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq<(bool, Bn)>; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Phase { - #[inline] - fn clone(&self) -> Phase { - match (&*self,) { - (&Phase::Off,) => Phase::Off, - (&Phase::Signed,) => Phase::Signed, - (&Phase::Unsigned(ref __self_0),) => { - Phase::Unsigned(::core::clone::Clone::clone(&(*__self_0))) - } - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for Phase {} - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Phase - where - Bn: _parity_scale_codec::Encode, - (bool, Bn): _parity_scale_codec::Encode, - { - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( - &self, - __codec_dest_edqy: &mut __CodecOutputEdqy, - ) { - match *self { - Phase::Off => { - __codec_dest_edqy.push_byte(0usize as u8); - } - Phase::Signed => { - __codec_dest_edqy.push_byte(1usize as u8); - } - Phase::Unsigned(ref aa) => { - __codec_dest_edqy.push_byte(2usize as u8); - __codec_dest_edqy.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for Phase - where - Bn: _parity_scale_codec::Encode, - (bool, Bn): _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Phase - where - Bn: _parity_scale_codec::Decode, - (bool, Bn): _parity_scale_codec::Decode, - { - fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( - __codec_input_edqy: &mut __CodecInputEdqy, - ) -> core::result::Result { - match __codec_input_edqy.read_byte()? { - __codec_x_edqy if __codec_x_edqy == 0usize as u8 => Ok(Phase::Off), - __codec_x_edqy if __codec_x_edqy == 1usize as u8 => Ok(Phase::Signed), - __codec_x_edqy if __codec_x_edqy == 2usize as u8 => Ok(Phase::Unsigned({ - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => return Err("Error decoding field Phase :: Unsigned.0".into()), - Ok(__codec_res_edqy) => __codec_res_edqy, - } - })), - _ => Err("No such variant in enum Phase".into()), - } - } - } - }; - impl core::fmt::Debug for Phase - where - Bn: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::Off => fmt.debug_tuple("Phase::Off").finish(), - Self::Signed => fmt.debug_tuple("Phase::Signed").finish(), - Self::Unsigned(ref a0) => fmt.debug_tuple("Phase::Unsigned").field(a0).finish(), - _ => Ok(()), - } - } - } - impl Default for Phase { - fn default() -> Self { - Phase::Off - } - } - impl Phase { - /// Weather the phase is signed or not. - pub fn is_signed(&self) -> bool { - match self { - Phase::Signed => true, - _ => false, - } - } - /// Weather the phase is unsigned or not. - pub fn is_unsigned(&self) -> bool { - match self { - Phase::Unsigned(_) => true, - _ => false, - } - } - /// Weather the phase is unsigned and open or not, with specific start. - pub fn is_unsigned_open_at(&self, at: Bn) -> bool { - match self { - Phase::Unsigned((true, real)) if *real == at => true, - _ => false, - } - } - /// Weather the phase is unsigned and open or not. - pub fn is_unsigned_open(&self) -> bool { - match self { - Phase::Unsigned((true, _)) => true, - _ => false, - } - } - /// Weather the phase is off or not. - pub fn is_off(&self) -> bool { - match self { - Phase::Off => true, - _ => false, - } - } - } - /// The type of `Computation` that provided this election data. - pub enum ElectionCompute { - /// Election was computed on-chain. - OnChain, - /// Election was computed with a signed submission. - Signed, - /// Election was computed with an unsigned submission. - Unsigned, - } - impl ::core::marker::StructuralPartialEq for ElectionCompute {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for ElectionCompute { - #[inline] - fn eq(&self, other: &ElectionCompute) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - _ => true, - } - } else { - false - } - } - } - } - impl ::core::marker::StructuralEq for ElectionCompute {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for ElectionCompute { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - {} - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for ElectionCompute { - #[inline] - fn clone(&self) -> ElectionCompute { - { - *self - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for ElectionCompute {} - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for ElectionCompute { - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( - &self, - __codec_dest_edqy: &mut __CodecOutputEdqy, - ) { - match *self { - ElectionCompute::OnChain => { - __codec_dest_edqy.push_byte(0usize as u8); - } - ElectionCompute::Signed => { - __codec_dest_edqy.push_byte(1usize as u8); - } - ElectionCompute::Unsigned => { - __codec_dest_edqy.push_byte(2usize as u8); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for ElectionCompute {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for ElectionCompute { - fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( - __codec_input_edqy: &mut __CodecInputEdqy, - ) -> core::result::Result { - match __codec_input_edqy.read_byte()? { - __codec_x_edqy if __codec_x_edqy == 0usize as u8 => { - Ok(ElectionCompute::OnChain) - } - __codec_x_edqy if __codec_x_edqy == 1usize as u8 => Ok(ElectionCompute::Signed), - __codec_x_edqy if __codec_x_edqy == 2usize as u8 => { - Ok(ElectionCompute::Unsigned) - } - _ => Err("No such variant in enum ElectionCompute".into()), - } - } - } - }; - impl core::fmt::Debug for ElectionCompute { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::OnChain => fmt.debug_tuple("ElectionCompute::OnChain").finish(), - Self::Signed => fmt.debug_tuple("ElectionCompute::Signed").finish(), - Self::Unsigned => fmt.debug_tuple("ElectionCompute::Unsigned").finish(), - _ => Ok(()), - } - } - } - impl Default for ElectionCompute { - fn default() -> Self { - ElectionCompute::OnChain - } - } - /// A raw, unchecked solution. - /// - /// This is what will get submitted to the chain. - /// - /// Such a solution should never become effective in anyway before being checked by the - /// [`Module::feasibility_check`]. - pub struct RawSolution { - /// Compact election edges. - compact: C, - /// The _claimed_ score of the solution. - score: ElectionScore, - } - impl ::core::marker::StructuralPartialEq for RawSolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for RawSolution { - #[inline] - fn eq(&self, other: &RawSolution) -> bool { - match *other { - RawSolution { - compact: ref __self_1_0, - score: ref __self_1_1, - } => match *self { - RawSolution { - compact: ref __self_0_0, - score: ref __self_0_1, - } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), - }, - } - } - #[inline] - fn ne(&self, other: &RawSolution) -> bool { - match *other { - RawSolution { - compact: ref __self_1_0, - score: ref __self_1_1, - } => match *self { - RawSolution { - compact: ref __self_0_0, - score: ref __self_0_1, - } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), - }, - } - } - } - impl ::core::marker::StructuralEq for RawSolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for RawSolution { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for RawSolution { - #[inline] - fn clone(&self) -> RawSolution { - match *self { - RawSolution { - compact: ref __self_0_0, - score: ref __self_0_1, - } => RawSolution { - compact: ::core::clone::Clone::clone(&(*__self_0_0)), - score: ::core::clone::Clone::clone(&(*__self_0_1)), - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for RawSolution - where - C: _parity_scale_codec::Encode, - C: _parity_scale_codec::Encode, - { - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( - &self, - __codec_dest_edqy: &mut __CodecOutputEdqy, - ) { - __codec_dest_edqy.push(&self.compact); - __codec_dest_edqy.push(&self.score); - } - } - impl _parity_scale_codec::EncodeLike for RawSolution - where - C: _parity_scale_codec::Encode, - C: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for RawSolution - where - C: _parity_scale_codec::Decode, - C: _parity_scale_codec::Decode, - { - fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( - __codec_input_edqy: &mut __CodecInputEdqy, - ) -> core::result::Result { - Ok(RawSolution { - compact: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => return Err("Error decoding field RawSolution.compact".into()), - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - score: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => return Err("Error decoding field RawSolution.score".into()), - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - }) - } - } - }; - impl core::fmt::Debug for RawSolution - where - C: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("RawSolution") - .field("compact", &self.compact) - .field("score", &self.score) - .finish() - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for RawSolution { - #[inline] - fn default() -> RawSolution { - RawSolution { - compact: ::core::default::Default::default(), - score: ::core::default::Default::default(), - } - } - } - /// A raw, unchecked signed submission. - /// - /// This is just a wrapper around [`RawSolution`] and some additional info. - pub struct SignedSubmission { - /// Who submitted this solution. - who: A, - /// The deposit reserved for storing this solution. - deposit: B, - /// The reward that should be given to this solution, if chosen the as the final one. - reward: B, - /// The raw solution itself. - solution: RawSolution, - } - impl ::core::marker::StructuralPartialEq for SignedSubmission {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl< - A: ::core::cmp::PartialEq, - B: ::core::cmp::PartialEq + HasCompact, - C: ::core::cmp::PartialEq, - > ::core::cmp::PartialEq for SignedSubmission - { - #[inline] - fn eq(&self, other: &SignedSubmission) -> bool { - match *other { - SignedSubmission { - who: ref __self_1_0, - deposit: ref __self_1_1, - reward: ref __self_1_2, - solution: ref __self_1_3, - } => match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - && (*__self_0_3) == (*__self_1_3) - } - }, - } - } - #[inline] - fn ne(&self, other: &SignedSubmission) -> bool { - match *other { - SignedSubmission { - who: ref __self_1_0, - deposit: ref __self_1_1, - reward: ref __self_1_2, - solution: ref __self_1_3, - } => match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) - || (*__self_0_2) != (*__self_1_2) - || (*__self_0_3) != (*__self_1_3) - } - }, - } - } - } - impl ::core::marker::StructuralEq for SignedSubmission {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq - for SignedSubmission - { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq>; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl< - A: ::core::clone::Clone, - B: ::core::clone::Clone + HasCompact, - C: ::core::clone::Clone, - > ::core::clone::Clone for SignedSubmission - { - #[inline] - fn clone(&self) -> SignedSubmission { - match *self { - SignedSubmission { - who: ref __self_0_0, - deposit: ref __self_0_1, - reward: ref __self_0_2, - solution: ref __self_0_3, - } => SignedSubmission { - who: ::core::clone::Clone::clone(&(*__self_0_0)), - deposit: ::core::clone::Clone::clone(&(*__self_0_1)), - reward: ::core::clone::Clone::clone(&(*__self_0_2)), - solution: ::core::clone::Clone::clone(&(*__self_0_3)), - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for SignedSubmission - where - A: _parity_scale_codec::Encode, - A: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - { - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( - &self, - __codec_dest_edqy: &mut __CodecOutputEdqy, - ) { - __codec_dest_edqy.push(&self.who); - __codec_dest_edqy.push(&self.deposit); - __codec_dest_edqy.push(&self.reward); - __codec_dest_edqy.push(&self.solution); - } - } - impl _parity_scale_codec::EncodeLike for SignedSubmission - where - A: _parity_scale_codec::Encode, - A: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - B: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - RawSolution: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for SignedSubmission - where - A: _parity_scale_codec::Decode, - A: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - B: _parity_scale_codec::Decode, - RawSolution: _parity_scale_codec::Decode, - RawSolution: _parity_scale_codec::Decode, - { - fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( - __codec_input_edqy: &mut __CodecInputEdqy, - ) -> core::result::Result { - Ok(SignedSubmission { - who: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err("Error decoding field SignedSubmission.who".into()) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - deposit: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err("Error decoding field SignedSubmission.deposit".into()) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - reward: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err("Error decoding field SignedSubmission.reward".into()) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - solution: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err("Error decoding field SignedSubmission.solution".into()) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - }) - } - } - }; - impl core::fmt::Debug for SignedSubmission - where - A: core::fmt::Debug, - B: core::fmt::Debug, - C: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("SignedSubmission") - .field("who", &self.who) - .field("deposit", &self.deposit) - .field("reward", &self.reward) - .field("solution", &self.solution) - .finish() - } - } - /// A checked solution, ready to be enacted. - pub struct ReadySolution { - /// The final supports of the solution. - /// - /// This is target-major vector, storing each winners, total backing, and each individual - /// backer. - supports: Supports, - /// The score of the solution. - /// - /// This is needed to potentially challenge the solution. - score: ElectionScore, - /// How this election was computed. - compute: ElectionCompute, - } - impl ::core::marker::StructuralPartialEq for ReadySolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for ReadySolution { - #[inline] - fn eq(&self, other: &ReadySolution) -> bool { - match *other { - ReadySolution { - supports: ref __self_1_0, - score: ref __self_1_1, - compute: ref __self_1_2, - } => match *self { - ReadySolution { - supports: ref __self_0_0, - score: ref __self_0_1, - compute: ref __self_0_2, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - } - }, - } - } - #[inline] - fn ne(&self, other: &ReadySolution) -> bool { - match *other { - ReadySolution { - supports: ref __self_1_0, - score: ref __self_1_1, - compute: ref __self_1_2, - } => match *self { - ReadySolution { - supports: ref __self_0_0, - score: ref __self_0_1, - compute: ref __self_0_2, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) - || (*__self_0_2) != (*__self_1_2) - } - }, - } - } - } - impl ::core::marker::StructuralEq for ReadySolution {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for ReadySolution { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for ReadySolution { - #[inline] - fn clone(&self) -> ReadySolution { - match *self { - ReadySolution { - supports: ref __self_0_0, - score: ref __self_0_1, - compute: ref __self_0_2, - } => ReadySolution { - supports: ::core::clone::Clone::clone(&(*__self_0_0)), - score: ::core::clone::Clone::clone(&(*__self_0_1)), - compute: ::core::clone::Clone::clone(&(*__self_0_2)), - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for ReadySolution - where - Supports: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - { - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( - &self, - __codec_dest_edqy: &mut __CodecOutputEdqy, - ) { - __codec_dest_edqy.push(&self.supports); - __codec_dest_edqy.push(&self.score); - __codec_dest_edqy.push(&self.compute); - } - } - impl _parity_scale_codec::EncodeLike for ReadySolution - where - Supports: _parity_scale_codec::Encode, - Supports: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for ReadySolution - where - Supports: _parity_scale_codec::Decode, - Supports: _parity_scale_codec::Decode, - { - fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( - __codec_input_edqy: &mut __CodecInputEdqy, - ) -> core::result::Result { - Ok(ReadySolution { - supports: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err("Error decoding field ReadySolution.supports".into()) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - score: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => return Err("Error decoding field ReadySolution.score".into()), - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - compute: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err("Error decoding field ReadySolution.compute".into()) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - }) - } - } - }; - impl core::fmt::Debug for ReadySolution - where - A: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("ReadySolution") - .field("supports", &self.supports) - .field("score", &self.score) - .field("compute", &self.compute) - .finish() - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for ReadySolution { - #[inline] - fn default() -> ReadySolution { - ReadySolution { - supports: ::core::default::Default::default(), - score: ::core::default::Default::default(), - compute: ::core::default::Default::default(), - } - } - } - /// Witness data about the size of the election. - /// - /// This is needed for proper weight calculation. - pub struct WitnessData { - /// Number of all voters. - /// - /// This must match the on-chain snapshot. - #[codec(compact)] - voters: u32, - /// Number of all targets. - /// - /// This must match the on-chain snapshot. - #[codec(compact)] - targets: u32, - } - impl ::core::marker::StructuralPartialEq for WitnessData {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for WitnessData { - #[inline] - fn eq(&self, other: &WitnessData) -> bool { - match *other { - WitnessData { - voters: ref __self_1_0, - targets: ref __self_1_1, - } => match *self { - WitnessData { - voters: ref __self_0_0, - targets: ref __self_0_1, - } => (*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1), - }, - } - } - #[inline] - fn ne(&self, other: &WitnessData) -> bool { - match *other { - WitnessData { - voters: ref __self_1_0, - targets: ref __self_1_1, - } => match *self { - WitnessData { - voters: ref __self_0_0, - targets: ref __self_0_1, - } => (*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1), - }, - } - } - } - impl ::core::marker::StructuralEq for WitnessData {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for WitnessData { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for WitnessData { - #[inline] - fn clone(&self) -> WitnessData { - { - let _: ::core::clone::AssertParamIsClone; - let _: ::core::clone::AssertParamIsClone; - *self - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for WitnessData {} - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for WitnessData { - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( - &self, - __codec_dest_edqy: &mut __CodecOutputEdqy, - ) { - { - __codec_dest_edqy . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . voters ) ) ; - } - { - __codec_dest_edqy . push ( & < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: EncodeAsRef < '_ , u32 > > :: from ( & self . targets ) ) ; - } - } - } - impl _parity_scale_codec::EncodeLike for WitnessData {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for WitnessData { - fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( - __codec_input_edqy: &mut __CodecInputEdqy, - ) -> core::result::Result { - Ok(WitnessData { - voters: { - let __codec_res_edqy = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( __codec_input_edqy ) ; - match __codec_res_edqy { - Err(_) => return Err("Error decoding field WitnessData.voters".into()), - Ok(__codec_res_edqy) => __codec_res_edqy.into(), - } - }, - targets: { - let __codec_res_edqy = < < u32 as _parity_scale_codec :: HasCompact > :: Type as _parity_scale_codec :: Decode > :: decode ( __codec_input_edqy ) ; - match __codec_res_edqy { - Err(_) => return Err("Error decoding field WitnessData.targets".into()), - Ok(__codec_res_edqy) => __codec_res_edqy.into(), - } - }, - }) - } - } - }; - impl core::fmt::Debug for WitnessData { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("WitnessData") - .field("voters", &self.voters) - .field("targets", &self.targets) - .finish() - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for WitnessData { - #[inline] - fn default() -> WitnessData { - WitnessData { - voters: ::core::default::Default::default(), - targets: ::core::default::Default::default(), - } - } - } - /// A snapshot of all the data that is needed for en entire round. They are provided by - /// [`ElectionDataProvider`] at the beginning of the signed phase and are kept around until the - /// round is finished. - /// - /// These are stored together because they are often times accessed together. - pub struct RoundSnapshot { - /// All of the voters. - pub voters: Vec<(A, VoteWeight, Vec)>, - /// All of the targets. - pub targets: Vec, - /// Desired number of winners to be elected for this round. - pub desired_targets: u32, - } - impl ::core::marker::StructuralPartialEq for RoundSnapshot {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for RoundSnapshot { - #[inline] - fn eq(&self, other: &RoundSnapshot) -> bool { - match *other { - RoundSnapshot { - voters: ref __self_1_0, - targets: ref __self_1_1, - desired_targets: ref __self_1_2, - } => match *self { - RoundSnapshot { - voters: ref __self_0_0, - targets: ref __self_0_1, - desired_targets: ref __self_0_2, - } => { - (*__self_0_0) == (*__self_1_0) - && (*__self_0_1) == (*__self_1_1) - && (*__self_0_2) == (*__self_1_2) - } - }, - } - } - #[inline] - fn ne(&self, other: &RoundSnapshot) -> bool { - match *other { - RoundSnapshot { - voters: ref __self_1_0, - targets: ref __self_1_1, - desired_targets: ref __self_1_2, - } => match *self { - RoundSnapshot { - voters: ref __self_0_0, - targets: ref __self_0_1, - desired_targets: ref __self_0_2, - } => { - (*__self_0_0) != (*__self_1_0) - || (*__self_0_1) != (*__self_1_1) - || (*__self_0_2) != (*__self_1_2) - } - }, - } - } - } - impl ::core::marker::StructuralEq for RoundSnapshot {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for RoundSnapshot { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq)>>; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for RoundSnapshot { - #[inline] - fn clone(&self) -> RoundSnapshot { - match *self { - RoundSnapshot { - voters: ref __self_0_0, - targets: ref __self_0_1, - desired_targets: ref __self_0_2, - } => RoundSnapshot { - voters: ::core::clone::Clone::clone(&(*__self_0_0)), - targets: ::core::clone::Clone::clone(&(*__self_0_1)), - desired_targets: ::core::clone::Clone::clone(&(*__self_0_2)), - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for RoundSnapshot - where - Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Encode, - Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Encode, - Vec: _parity_scale_codec::Encode, - Vec: _parity_scale_codec::Encode, - { - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( - &self, - __codec_dest_edqy: &mut __CodecOutputEdqy, - ) { - __codec_dest_edqy.push(&self.voters); - __codec_dest_edqy.push(&self.targets); - __codec_dest_edqy.push(&self.desired_targets); - } - } - impl _parity_scale_codec::EncodeLike for RoundSnapshot - where - Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Encode, - Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Encode, - Vec: _parity_scale_codec::Encode, - Vec: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for RoundSnapshot - where - Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Decode, - Vec<(A, VoteWeight, Vec)>: _parity_scale_codec::Decode, - Vec: _parity_scale_codec::Decode, - Vec: _parity_scale_codec::Decode, - { - fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( - __codec_input_edqy: &mut __CodecInputEdqy, - ) -> core::result::Result { - Ok(RoundSnapshot { - voters: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err("Error decoding field RoundSnapshot.voters".into()) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - targets: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err("Error decoding field RoundSnapshot.targets".into()) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - desired_targets: { - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err( - "Error decoding field RoundSnapshot.desired_targets".into() - ) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - }, - }) - } - } - }; - impl core::fmt::Debug for RoundSnapshot - where - A: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_struct("RoundSnapshot") - .field("voters", &self.voters) - .field("targets", &self.targets) - .field("desired_targets", &self.desired_targets) - .finish() - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::default::Default for RoundSnapshot { - #[inline] - fn default() -> RoundSnapshot { - RoundSnapshot { - voters: ::core::default::Default::default(), - targets: ::core::default::Default::default(), - desired_targets: ::core::default::Default::default(), - } - } - } - /// The crate errors. - /// - /// Note that this is different from the [`PalletError`]. - pub enum Error { - /// A feasibility error. - Feasibility(FeasibilityError), - /// An error in the on-chain fallback. - OnChainFallback(crate::onchain::Error), - /// An internal error in the NPoS elections crate. - NposElections(sp_npos_elections::Error), - /// Snapshot data was unavailable unexpectedly. - SnapshotUnAvailable, - /// Submitting a transaction to the pool failed. - /// - /// This can only happen in the unsigned phase. - PoolSubmissionFailed, - } - impl core::fmt::Debug for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::Feasibility(ref a0) => { - fmt.debug_tuple("Error::Feasibility").field(a0).finish() - } - Self::OnChainFallback(ref a0) => { - fmt.debug_tuple("Error::OnChainFallback").field(a0).finish() - } - Self::NposElections(ref a0) => { - fmt.debug_tuple("Error::NposElections").field(a0).finish() - } - Self::SnapshotUnAvailable => fmt.debug_tuple("Error::SnapshotUnAvailable").finish(), - Self::PoolSubmissionFailed => { - fmt.debug_tuple("Error::PoolSubmissionFailed").finish() - } - _ => Ok(()), - } - } - } - impl ::core::marker::StructuralEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Error { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - impl ::core::marker::StructuralPartialEq for Error {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Error { - #[inline] - fn eq(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - ( - &Error::OnChainFallback(ref __self_0), - &Error::OnChainFallback(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - ( - &Error::NposElections(ref __self_0), - &Error::NposElections(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &Error) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - (&Error::Feasibility(ref __self_0), &Error::Feasibility(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - ( - &Error::OnChainFallback(ref __self_0), - &Error::OnChainFallback(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - ( - &Error::NposElections(ref __self_0), - &Error::NposElections(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - _ => false, - } - } else { - true - } - } - } - } - impl From for Error { - fn from(e: crate::onchain::Error) -> Self { - Error::OnChainFallback(e) - } - } - impl From for Error { - fn from(e: sp_npos_elections::Error) -> Self { - Error::NposElections(e) - } - } - impl From for Error { - fn from(e: FeasibilityError) -> Self { - Error::Feasibility(e) - } - } - /// Errors that can happen in the feasibility check. - pub enum FeasibilityError { - /// Wrong number of winners presented. - WrongWinnerCount, - /// The snapshot is not available. - /// - /// This must be an internal error of the chain. - SnapshotUnavailable, - /// Internal error from the election crate. - NposElection(sp_npos_elections::Error), - /// A vote is invalid. - InvalidVote, - /// A voter is invalid. - InvalidVoter, - /// A winner is invalid. - InvalidWinner, - /// The given score was invalid. - InvalidScore, - } - impl core::fmt::Debug for FeasibilityError { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::WrongWinnerCount => fmt - .debug_tuple("FeasibilityError::WrongWinnerCount") - .finish(), - Self::SnapshotUnavailable => fmt - .debug_tuple("FeasibilityError::SnapshotUnavailable") - .finish(), - Self::NposElection(ref a0) => fmt - .debug_tuple("FeasibilityError::NposElection") - .field(a0) - .finish(), - Self::InvalidVote => fmt.debug_tuple("FeasibilityError::InvalidVote").finish(), - Self::InvalidVoter => fmt.debug_tuple("FeasibilityError::InvalidVoter").finish(), - Self::InvalidWinner => fmt.debug_tuple("FeasibilityError::InvalidWinner").finish(), - Self::InvalidScore => fmt.debug_tuple("FeasibilityError::InvalidScore").finish(), - _ => Ok(()), - } - } - } - impl ::core::marker::StructuralEq for FeasibilityError {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for FeasibilityError { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - } - } - } - impl ::core::marker::StructuralPartialEq for FeasibilityError {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for FeasibilityError { - #[inline] - fn eq(&self, other: &FeasibilityError) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &FeasibilityError::NposElection(ref __self_0), - &FeasibilityError::NposElection(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - _ => true, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &FeasibilityError) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &FeasibilityError::NposElection(ref __self_0), - &FeasibilityError::NposElection(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - _ => false, - } - } else { - true - } - } - } - } - impl From for FeasibilityError { - fn from(e: sp_npos_elections::Error) -> Self { - FeasibilityError::NposElection(e) - } - } - pub trait WeightInfo {} - pub trait Config: frame_system::Config + SendTransactionTypes> - where - ExtendedBalance: From>>, - { - /// Event type. - type Event: From> + Into<::Event>; - /// Currency type. - type Currency: ReservableCurrency + Currency; - /// Duration of the signed phase. - type SignedPhase: Get; - /// Duration of the unsigned phase. - type UnsignedPhase: Get; - /// Maximum number of singed submissions that can be queued. - type MaxSignedSubmissions: Get; - type SignedRewardBase: Get>; - type SignedRewardFactor: Get; - type SignedRewardMax: Get>>; - type SignedDepositBase: Get>; - type SignedDepositByte: Get>; - type SignedDepositWeight: Get>; - /// The minimum amount of improvement to the solution score that defines a solution as "better". - type SolutionImprovementThreshold: Get; - /// Maximum number of iteration of balancing that will be executed in the embedded miner of the - /// pallet. - type UnsignedMaxIterations: Get; - /// The priority of the unsigned transaction submitted in the unsigned-phase - type UnsignedPriority: Get; - /// Handler for the slashed deposits. - type SlashHandler: OnUnbalanced>; - /// Handler for the rewards. - type RewardHandler: OnUnbalanced>; - /// Something that will provide the election data. - type ElectionDataProvider: ElectionDataProvider; - /// The weight of the pallet. - type WeightInfo; - } - use self::sp_api_hidden_includes_decl_storage::hidden_include::{ - IterableStorageDoubleMap as _, IterableStorageMap as _, StorageDoubleMap as _, - StorageMap as _, StoragePrefixedMap as _, StorageValue as _, - }; - #[doc(hidden)] - mod sp_api_hidden_includes_decl_storage { - pub extern crate frame_support as hidden_include; - } - trait Store { - type Round; - type CurrentPhase; - type SignedSubmissions; - type QueuedSolution; - type Snapshot; - } - impl Store for Module - where - ExtendedBalance: From>>, - { - type Round = Round; - type CurrentPhase = CurrentPhase; - type SignedSubmissions = SignedSubmissions; - type QueuedSolution = QueuedSolution; - type Snapshot = Snapshot; - } - impl Module - where - ExtendedBalance: From>>, - { - /// Internal counter for the number of rounds. - /// - /// This is useful for de-duplication of transactions submitted to the pool, and general - /// diagnostics of the module. - /// - /// This is merely incremented once per every time that signed phase starts. - pub fn round() -> u32 { - < Round < > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < u32 > > :: get ( ) - } - /// Current phase. - pub fn current_phase() -> Phase { - < CurrentPhase < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Phase < T :: BlockNumber > > > :: get ( ) - } - /// Sorted (worse -> best) list of unchecked, signed solutions. - pub fn signed_submissions( - ) -> Vec, CompactOf>> { - < SignedSubmissions < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > > > :: get ( ) - } - /// Current best solution, signed or unsigned. - pub fn queued_solution() -> Option> { - < QueuedSolution < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < ReadySolution < T :: AccountId > > > :: get ( ) - } - /// Snapshot data of the round. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub fn snapshot() -> Option> { - < Snapshot < T > as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: storage :: StorageValue < RoundSnapshot < T :: AccountId > > > :: get ( ) - } - } - #[doc(hidden)] - pub struct __GetByteStructRound( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_Round: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructRound - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_Round - .get_or_init(|| { - let def_val: u32 = 0; - ::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructRound where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructRound where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructCurrentPhase( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_CurrentPhase: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructCurrentPhase - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_CurrentPhase - .get_or_init(|| { - let def_val: Phase = Phase::Off; - as Encode>::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructCurrentPhase where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructCurrentPhase where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructSignedSubmissions( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_SignedSubmissions: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructSignedSubmissions - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_SignedSubmissions . get_or_init ( | | { let def_val : Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > = Default :: default ( ) ; < Vec < SignedSubmission < T :: AccountId , BalanceOf < T > , CompactOf < T > > > as Encode > :: encode ( & def_val ) } ) . clone ( ) - } - } - unsafe impl Send for __GetByteStructSignedSubmissions where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructSignedSubmissions where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructQueuedSolution( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_QueuedSolution: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructQueuedSolution - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_QueuedSolution - .get_or_init(|| { - let def_val: Option> = Default::default(); - > as Encode>::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructQueuedSolution where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructQueuedSolution where - ExtendedBalance: From>> - { - } - #[doc(hidden)] - pub struct __GetByteStructSnapshot( - pub self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T), - >, - ); - #[cfg(feature = "std")] - #[allow(non_upper_case_globals)] - static __CACHE_GET_BYTE_STRUCT_Snapshot: - self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell< - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec, - > = self::sp_api_hidden_includes_decl_storage::hidden_include::once_cell::sync::OnceCell::new(); - #[cfg(feature = "std")] - impl self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::DefaultByte - for __GetByteStructSnapshot - where - ExtendedBalance: From>>, - { - fn default_byte( - &self, - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::vec::Vec { - use self::sp_api_hidden_includes_decl_storage::hidden_include::codec::Encode; - __CACHE_GET_BYTE_STRUCT_Snapshot - .get_or_init(|| { - let def_val: Option> = Default::default(); - > as Encode>::encode(&def_val) - }) - .clone() - } - } - unsafe impl Send for __GetByteStructSnapshot where - ExtendedBalance: From>> - { - } - unsafe impl Sync for __GetByteStructSnapshot where - ExtendedBalance: From>> - { - } - impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - pub fn storage_metadata( - ) -> self::sp_api_hidden_includes_decl_storage::hidden_include::metadata::StorageMetadata { - self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageMetadata { prefix : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "TwoPhaseElectionProvider" ) , entries : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Round" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "u32" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructRound :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Internal counter for the number of rounds." , "" , " This is useful for de-duplication of transactions submitted to the pool, and general" , " diagnostics of the module." , "" , " This is merely incremented once per every time that signed phase starts." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "CurrentPhase" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Phase" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructCurrentPhase :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current phase." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "SignedSubmissions" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Default , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Vec, CompactOf>>" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSignedSubmissions :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Sorted (worse -> best) list of unchecked, signed solutions." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "QueuedSolution" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "ReadySolution" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructQueuedSolution :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Current best solution, signed or unsigned." ] ) , } , self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryMetadata { name : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "Snapshot" ) , modifier : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryModifier :: Optional , ty : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: StorageEntryType :: Plain ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( "RoundSnapshot" ) ) , default : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DefaultByteGetter ( & __GetByteStructSnapshot :: < T > ( self :: sp_api_hidden_includes_decl_storage :: hidden_include :: sp_std :: marker :: PhantomData ) ) ) , documentation : self :: sp_api_hidden_includes_decl_storage :: hidden_include :: metadata :: DecodeDifferent :: Encode ( & [ " Snapshot data of the round." , "" , " This is created at the beginning of the signed phase and cleared upon calling `elect`." ] ) , } ] [ .. ] ) , } - } - } - /// Hidden instance generated to be internally used when module is used without - /// instance. - #[doc(hidden)] - pub struct __InherentHiddenInstance; - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for __InherentHiddenInstance { - #[inline] - fn clone(&self) -> __InherentHiddenInstance { - match *self { - __InherentHiddenInstance => __InherentHiddenInstance, - } - } - } - impl ::core::marker::StructuralEq for __InherentHiddenInstance {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for __InherentHiddenInstance { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - {} - } - } - impl ::core::marker::StructuralPartialEq for __InherentHiddenInstance {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for __InherentHiddenInstance { - #[inline] - fn eq(&self, other: &__InherentHiddenInstance) -> bool { - match *other { - __InherentHiddenInstance => match *self { - __InherentHiddenInstance => true, - }, - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for __InherentHiddenInstance { - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( - &self, - __codec_dest_edqy: &mut __CodecOutputEdqy, - ) { - } - } - impl _parity_scale_codec::EncodeLike for __InherentHiddenInstance {} - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for __InherentHiddenInstance { - fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( - __codec_input_edqy: &mut __CodecInputEdqy, - ) -> core::result::Result { - Ok(__InherentHiddenInstance) - } - } - }; - impl core::fmt::Debug for __InherentHiddenInstance { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_tuple("__InherentHiddenInstance").finish() - } - } - impl self::sp_api_hidden_includes_decl_storage::hidden_include::traits::Instance - for __InherentHiddenInstance - { - const PREFIX: &'static str = "TwoPhaseElectionProvider"; - } - /// Internal counter for the number of rounds. - /// - /// This is useful for de-duplication of transactions submitted to the pool, and general - /// diagnostics of the module. - /// - /// This is merely incremented once per every time that signed phase starts. - pub struct Round( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData<()>, - ); - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - u32, - > for Round - { - type Query = u32; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"Round" - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - v.unwrap_or_else(|| 0) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - Some(v) - } - } - /// Current phase. - pub struct CurrentPhase( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Phase, - > for CurrentPhase - where - ExtendedBalance: From>>, - { - type Query = Phase; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"CurrentPhase" - } - fn from_optional_value_to_query(v: Option>) -> Self::Query { - v.unwrap_or_else(|| Phase::Off) - } - fn from_query_to_optional_value(v: Self::Query) -> Option> { - Some(v) - } - } - /// Sorted (worse -> best) list of unchecked, signed solutions. - pub struct SignedSubmissions( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - Vec, CompactOf>>, - > for SignedSubmissions - where - ExtendedBalance: From>>, - { - type Query = Vec, CompactOf>>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"SignedSubmissions" - } - fn from_optional_value_to_query( - v: Option, CompactOf>>>, - ) -> Self::Query { - v.unwrap_or_else(|| Default::default()) - } - fn from_query_to_optional_value( - v: Self::Query, - ) -> Option, CompactOf>>> { - Some(v) - } - } - /// Current best solution, signed or unsigned. - pub struct QueuedSolution( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - ReadySolution, - > for QueuedSolution - where - ExtendedBalance: From>>, - { - type Query = Option>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"QueuedSolution" - } - fn from_optional_value_to_query(v: Option>) -> Self::Query { - v.or_else(|| Default::default()) - } - fn from_query_to_optional_value(v: Self::Query) -> Option> { - v - } - } - /// Snapshot data of the round. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub struct Snapshot( - self::sp_api_hidden_includes_decl_storage::hidden_include::sp_std::marker::PhantomData< - (T,), - >, - ) - where - ExtendedBalance: From>>; - impl - self::sp_api_hidden_includes_decl_storage::hidden_include::storage::generator::StorageValue< - RoundSnapshot, - > for Snapshot - where - ExtendedBalance: From>>, - { - type Query = Option>; - fn module_prefix() -> &'static [u8] { - < __InherentHiddenInstance as self :: sp_api_hidden_includes_decl_storage :: hidden_include :: traits :: Instance > :: PREFIX . as_bytes ( ) - } - fn storage_prefix() -> &'static [u8] { - b"Snapshot" - } - fn from_optional_value_to_query(v: Option>) -> Self::Query { - v.or_else(|| Default::default()) - } - fn from_query_to_optional_value(v: Self::Query) -> Option> { - v - } - } - /// [`RawEvent`] specialized for the configuration [`Config`] - /// - /// [`RawEvent`]: enum.RawEvent.html - /// [`Config`]: trait.Config.html - pub type Event = RawEvent<::AccountId>; - /// Events for this module. - /// - pub enum RawEvent { - /// A solution was stored with the given compute. - /// - /// If the solution is signed, this means that it hasn't yet been processed. If the solution - /// is unsigned, this means that it has also been processed. - SolutionStored(ElectionCompute), - /// The election has been finalized, with `Some` of the given computation, or else if the - /// election failed, `None`. - ElectionFinalized(Option), - /// An account has been rewarded for their signed submission being finalized. - Rewarded(AccountId), - /// An account has been slashed for submitting an invalid signed submission. - Slashed(AccountId), - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for RawEvent { - #[inline] - fn clone(&self) -> RawEvent { - match (&*self,) { - (&RawEvent::SolutionStored(ref __self_0),) => { - RawEvent::SolutionStored(::core::clone::Clone::clone(&(*__self_0))) - } - (&RawEvent::ElectionFinalized(ref __self_0),) => { - RawEvent::ElectionFinalized(::core::clone::Clone::clone(&(*__self_0))) - } - (&RawEvent::Rewarded(ref __self_0),) => { - RawEvent::Rewarded(::core::clone::Clone::clone(&(*__self_0))) - } - (&RawEvent::Slashed(ref __self_0),) => { - RawEvent::Slashed(::core::clone::Clone::clone(&(*__self_0))) - } - } - } - } - impl ::core::marker::StructuralPartialEq for RawEvent {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for RawEvent { - #[inline] - fn eq(&self, other: &RawEvent) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &RawEvent::SolutionStored(ref __self_0), - &RawEvent::SolutionStored(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - ( - &RawEvent::ElectionFinalized(ref __self_0), - &RawEvent::ElectionFinalized(ref __arg_1_0), - ) => (*__self_0) == (*__arg_1_0), - (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { - (*__self_0) == (*__arg_1_0) - } - _ => unsafe { ::core::intrinsics::unreachable() }, - } - } else { - false - } - } - } - #[inline] - fn ne(&self, other: &RawEvent) -> bool { - { - let __self_vi = unsafe { ::core::intrinsics::discriminant_value(&*self) }; - let __arg_1_vi = unsafe { ::core::intrinsics::discriminant_value(&*other) }; - if true && __self_vi == __arg_1_vi { - match (&*self, &*other) { - ( - &RawEvent::SolutionStored(ref __self_0), - &RawEvent::SolutionStored(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - ( - &RawEvent::ElectionFinalized(ref __self_0), - &RawEvent::ElectionFinalized(ref __arg_1_0), - ) => (*__self_0) != (*__arg_1_0), - (&RawEvent::Rewarded(ref __self_0), &RawEvent::Rewarded(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - (&RawEvent::Slashed(ref __self_0), &RawEvent::Slashed(ref __arg_1_0)) => { - (*__self_0) != (*__arg_1_0) - } - _ => unsafe { ::core::intrinsics::unreachable() }, - } - } else { - true - } - } - } - } - impl ::core::marker::StructuralEq for RawEvent {} - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for RawEvent { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq>; - let _: ::core::cmp::AssertParamIsEq; - let _: ::core::cmp::AssertParamIsEq; - } - } - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for RawEvent - where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - { - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( - &self, - __codec_dest_edqy: &mut __CodecOutputEdqy, - ) { - match *self { - RawEvent::SolutionStored(ref aa) => { - __codec_dest_edqy.push_byte(0usize as u8); - __codec_dest_edqy.push(aa); - } - RawEvent::ElectionFinalized(ref aa) => { - __codec_dest_edqy.push_byte(1usize as u8); - __codec_dest_edqy.push(aa); - } - RawEvent::Rewarded(ref aa) => { - __codec_dest_edqy.push_byte(2usize as u8); - __codec_dest_edqy.push(aa); - } - RawEvent::Slashed(ref aa) => { - __codec_dest_edqy.push_byte(3usize as u8); - __codec_dest_edqy.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for RawEvent - where - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - AccountId: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for RawEvent - where - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - AccountId: _parity_scale_codec::Decode, - { - fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( - __codec_input_edqy: &mut __CodecInputEdqy, - ) -> core::result::Result { - match __codec_input_edqy.read_byte()? { - __codec_x_edqy if __codec_x_edqy == 0usize as u8 => { - Ok(RawEvent::SolutionStored({ - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err( - "Error decoding field RawEvent :: SolutionStored.0".into() - ) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - })) - } - __codec_x_edqy if __codec_x_edqy == 1usize as u8 => { - Ok(RawEvent::ElectionFinalized({ - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err( - "Error decoding field RawEvent :: ElectionFinalized.0" - .into(), - ) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - })) - } - __codec_x_edqy if __codec_x_edqy == 2usize as u8 => Ok(RawEvent::Rewarded({ - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err("Error decoding field RawEvent :: Rewarded.0".into()) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - })), - __codec_x_edqy if __codec_x_edqy == 3usize as u8 => Ok(RawEvent::Slashed({ - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err("Error decoding field RawEvent :: Slashed.0".into()) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - })), - _ => Err("No such variant in enum RawEvent".into()), - } - } - } - }; - impl core::fmt::Debug for RawEvent - where - AccountId: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - match self { - Self::SolutionStored(ref a0) => fmt - .debug_tuple("RawEvent::SolutionStored") - .field(a0) - .finish(), - Self::ElectionFinalized(ref a0) => fmt - .debug_tuple("RawEvent::ElectionFinalized") - .field(a0) - .finish(), - Self::Rewarded(ref a0) => fmt.debug_tuple("RawEvent::Rewarded").field(a0).finish(), - Self::Slashed(ref a0) => fmt.debug_tuple("RawEvent::Slashed").field(a0).finish(), - _ => Ok(()), - } - } - } - impl From> for () { - fn from(_: RawEvent) -> () { - () - } - } - impl RawEvent { - #[allow(dead_code)] - #[doc(hidden)] - pub fn metadata() -> &'static [::frame_support::event::EventMetadata] { - &[ - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("SolutionStored"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&[ - "ElectionCompute", - ]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" A solution was stored with the given compute.", - r"", - r" If the solution is signed, this means that it hasn't yet been processed. If the solution", - r" is unsigned, this means that it has also been processed.", - ]), - }, - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("ElectionFinalized"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&[ - "Option", - ]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" The election has been finalized, with `Some` of the given computation, or else if the", - r" election failed, `None`.", - ]), - }, - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("Rewarded"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" An account has been rewarded for their signed submission being finalized.", - ]), - }, - ::frame_support::event::EventMetadata { - name: ::frame_support::event::DecodeDifferent::Encode("Slashed"), - arguments: ::frame_support::event::DecodeDifferent::Encode(&["AccountId"]), - documentation: ::frame_support::event::DecodeDifferent::Encode(&[ - r" An account has been slashed for submitting an invalid signed submission.", - ]), - }, - ] - } - } - pub enum PalletError - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - __Ignore( - ::frame_support::sp_std::marker::PhantomData<(T,)>, - ::frame_support::Never, - ), - /// Submission was too early. - EarlySubmission, - /// Submission was too weak, score-wise. - WeakSubmission, - /// The queue was full, and the solution was not better than any of the existing ones. - QueueFull, - /// The origin failed to pay the deposit. - CannotPayDeposit, - } - impl ::frame_support::sp_std::fmt::Debug for PalletError - where - ExtendedBalance: From>>, - { - fn fmt( - &self, - f: &mut ::frame_support::sp_std::fmt::Formatter<'_>, - ) -> ::frame_support::sp_std::fmt::Result { - f.write_str(self.as_str()) - } - } - impl PalletError - where - ExtendedBalance: From>>, - { - fn as_u8(&self) -> u8 { - match self { - PalletError::__Ignore(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"`__Ignore` can never be constructed",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - PalletError::EarlySubmission => 0, - PalletError::WeakSubmission => 0 + 1, - PalletError::QueueFull => 0 + 1 + 1, - PalletError::CannotPayDeposit => 0 + 1 + 1 + 1, - } - } - fn as_str(&self) -> &'static str { - match self { - Self::__Ignore(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"`__Ignore` can never be constructed",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - PalletError::EarlySubmission => "EarlySubmission", - PalletError::WeakSubmission => "WeakSubmission", - PalletError::QueueFull => "QueueFull", - PalletError::CannotPayDeposit => "CannotPayDeposit", - } - } - } - impl From> for &'static str - where - ExtendedBalance: From>>, - { - fn from(err: PalletError) -> &'static str { - err.as_str() - } - } - impl From> for ::frame_support::sp_runtime::DispatchError - where - ExtendedBalance: From>>, - { - fn from(err: PalletError) -> Self { - let index = ::index::>() - .expect("Every active module has an index in the runtime; qed") as u8; - ::frame_support::sp_runtime::DispatchError::Module { - index, - error: err.as_u8(), - message: Some(err.as_str()), - } - } - } - impl ::frame_support::error::ModuleErrorMetadata for PalletError - where - ExtendedBalance: From>>, - { - fn metadata() -> &'static [::frame_support::error::ErrorMetadata] { - &[ - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("EarlySubmission"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[ - r" Submission was too early.", - ]), - }, - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("WeakSubmission"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[ - r" Submission was too weak, score-wise.", - ]), - }, - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("QueueFull"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[ - r" The queue was full, and the solution was not better than any of the existing ones.", - ]), - }, - ::frame_support::error::ErrorMetadata { - name: ::frame_support::error::DecodeDifferent::Encode("CannotPayDeposit"), - documentation: ::frame_support::error::DecodeDifferent::Encode(&[ - r" The origin failed to pay the deposit.", - ]), - }, - ] - } - } - pub struct Module(::frame_support::sp_std::marker::PhantomData<(T,)>) - where - ExtendedBalance: From>>; - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::clone::Clone for Module - where - ExtendedBalance: From>>, - { - #[inline] - fn clone(&self) -> Module { - match *self { - Module(ref __self_0_0) => Module(::core::clone::Clone::clone(&(*__self_0_0))), - } - } - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::marker::Copy for Module where - ExtendedBalance: From>> - { - } - impl ::core::marker::StructuralPartialEq for Module where - ExtendedBalance: From>> - { - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::PartialEq for Module - where - ExtendedBalance: From>>, - { - #[inline] - fn eq(&self, other: &Module) -> bool { - match *other { - Module(ref __self_1_0) => match *self { - Module(ref __self_0_0) => (*__self_0_0) == (*__self_1_0), - }, - } - } - #[inline] - fn ne(&self, other: &Module) -> bool { - match *other { - Module(ref __self_1_0) => match *self { - Module(ref __self_0_0) => (*__self_0_0) != (*__self_1_0), - }, - } - } - } - impl ::core::marker::StructuralEq for Module where - ExtendedBalance: From>> - { - } - #[automatically_derived] - #[allow(unused_qualifications)] - impl ::core::cmp::Eq for Module - where - ExtendedBalance: From>>, - { - #[inline] - #[doc(hidden)] - fn assert_receiver_is_total_eq(&self) -> () { - { - let _: ::core::cmp::AssertParamIsEq< - ::frame_support::sp_std::marker::PhantomData<(T,)>, - >; - } - } - } - impl core::fmt::Debug for Module - where - ExtendedBalance: From>>, - T: core::fmt::Debug, - { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - fmt.debug_tuple("Module").field(&self.0).finish() - } - } - impl - ::frame_support::traits::OnInitialize<::BlockNumber> for Module - where - ExtendedBalance: From>>, - { - fn on_initialize(now: T::BlockNumber) -> Weight { - let __within_span__ = { - use ::tracing::__macro_support::Callsite as _; - static CALLSITE: ::tracing::__macro_support::MacroCallsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "on_initialize", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(469u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - MacroCallsite::new(&META) - }; - let mut interest = ::tracing::subscriber::Interest::never(); - if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL - && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() - && { - interest = CALLSITE.interest(); - !interest.is_never() - } - && CALLSITE.is_enabled(interest) - { - let meta = CALLSITE.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - let span = CALLSITE.disabled_span(); - {}; - span - } - }; - let __tracing_guard__ = __within_span__.enter(); - { - let next_election = T::ElectionDataProvider::next_election_prediction(now); - let next_election = next_election.max(now); - let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); - let unsigned_deadline = T::UnsignedPhase::get(); - let remaining = next_election - now; - match Self::current_phase() { - Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { - >::put(Phase::Signed); - Round::mutate(|r| *r += 1); - Self::start_signed_phase(); - { - let lvl = ::log::Level::Info; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::__private_api_log( - ::core::fmt::Arguments::new_v1( - &["\u{1f3e6} Starting signed phase at #", " , round "], - &match (&now, &Self::round()) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - ), - ::core::fmt::ArgumentV1::new( - arg1, - ::core::fmt::Display::fmt, - ), - ], - }, - ), - lvl, - &( - crate::LOG_TARGET, - "frame_election_providers::two_phase", - "frame/election-providers/src/two_phase/mod.rs", - 493u32, - ), - ); - } - }; - } - Phase::Signed if remaining <= unsigned_deadline && remaining > 0.into() => { - let found_solution = Self::finalize_signed_phase(); - >::put(Phase::Unsigned((!found_solution, now))); - { - let lvl = ::log::Level::Info; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::__private_api_log( - ::core::fmt::Arguments::new_v1( - &["\u{1f3e6} Starting unsigned phase at #"], - &match (&now,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - ), - lvl, - &( - crate::LOG_TARGET, - "frame_election_providers::two_phase", - "frame/election-providers/src/two_phase/mod.rs", - 502u32, - ), - ); - } - }; - } - _ => {} - } - Default::default() - } - } - } - impl ::frame_support::traits::OnRuntimeUpgrade for Module - where - ExtendedBalance: From>>, - { - fn on_runtime_upgrade() -> ::frame_support::dispatch::Weight { - let __within_span__ = { - use ::tracing::__macro_support::Callsite as _; - static CALLSITE: ::tracing::__macro_support::MacroCallsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "on_runtime_upgrade", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(469u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - MacroCallsite::new(&META) - }; - let mut interest = ::tracing::subscriber::Interest::never(); - if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL - && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() - && { - interest = CALLSITE.interest(); - !interest.is_never() - } && CALLSITE.is_enabled(interest) - { - let meta = CALLSITE.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - let span = CALLSITE.disabled_span(); - {}; - span - } - }; - let __tracing_guard__ = __within_span__.enter(); - frame_support::traits::PalletVersion { - major: 2u16, - minor: 0u8, - patch: 0u8, - } - .put_into_storage::<::PalletInfo, Self>(); - <::DbWeight as ::frame_support::traits::Get<_>>::get() - .writes(1) - } - } - impl - ::frame_support::traits::OnFinalize<::BlockNumber> for Module - where - ExtendedBalance: From>>, - { - } - impl - ::frame_support::traits::OffchainWorker<::BlockNumber> for Module - where - ExtendedBalance: From>>, - { - fn offchain_worker(n: T::BlockNumber) { - if Self::set_check_offchain_execution_status(n).is_ok() - && Self::current_phase().is_unsigned_open_at(n) - { - let _ = Self::mine_and_submit().map_err(|e| { - let lvl = ::log::Level::Error; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::__private_api_log( - ::core::fmt::Arguments::new_v1( - &["\u{1f3e6} error while submitting transaction in OCW: "], - &match (&e,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - ), - lvl, - &( - crate::LOG_TARGET, - "frame_election_providers::two_phase", - "frame/election-providers/src/two_phase/mod.rs", - 519u32, - ), - ); - } - }); - } - } - } - impl Module - where - ExtendedBalance: From>>, - { - /// Deposits an event using `frame_system::Module::deposit_event`. - fn deposit_event(event: impl Into<::Event>) { - >::deposit_event(event.into()) - } - } - #[cfg(feature = "std")] - impl ::frame_support::traits::IntegrityTest for Module where - ExtendedBalance: From>> - { - } - /// Can also be called using [`Call`]. - /// - /// [`Call`]: enum.Call.html - impl Module - where - ExtendedBalance: From>>, - { - /// Submit a solution for the signed phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// The solution is potentially queued, based on the claimed score and processed at the end - /// of the signed phase. - /// - /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution - /// might be rewarded, slashed, or get all or a part of the deposit back. - /// - /// NOTE: Calling this function will bypass origin filters. - fn submit( - origin: T::Origin, - solution: RawSolution>, - ) -> DispatchResultWithPostInfo { - let __within_span__ = { - use ::tracing::__macro_support::Callsite as _; - static CALLSITE: ::tracing::__macro_support::MacroCallsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "submit", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(469u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - MacroCallsite::new(&META) - }; - let mut interest = ::tracing::subscriber::Interest::never(); - if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL - && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() - && { - interest = CALLSITE.interest(); - !interest.is_never() - } - && CALLSITE.is_enabled(interest) - { - let meta = CALLSITE.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - let span = CALLSITE.disabled_span(); - {}; - span - } - }; - let __tracing_guard__ = __within_span__.enter(); - let who = ensure_signed(origin)?; - { - if !Self::current_phase().is_signed() { - { - return Err(PalletError::::EarlySubmission.into()); - }; - } - }; - let mut signed_submissions = Self::signed_submissions(); - let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution); - { - if !maybe_index.is_some() { - { - return Err("QueueFull".into()); - }; - } - }; - let index = maybe_index.expect("Option checked to be `Some`; qed."); - let deposit = signed_submissions[index].deposit; - T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; - if true { - if !(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()) { - { - :: std :: rt :: begin_panic ( "assertion failed: signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()" ) - } - }; - }; - >::put(signed_submissions); - Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Signed)); - Ok(None.into()) - } - #[allow(unreachable_code)] - /// Submit a solution for the unsigned phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. - /// Moreover, this unsigned solution is only validated when submitted to the pool from the - /// local process. Effectively, this means that only active validators can submit this - /// transaction when authoring a block. - /// - /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will - /// panic if the solution submitted by the validator is invalid, effectively putting their - /// authoring reward at risk. - /// - /// No deposit or reward is associated with this. - /// - /// NOTE: Calling this function will bypass origin filters. - fn submit_unsigned( - origin: T::Origin, - solution: RawSolution>, - ) -> ::frame_support::dispatch::DispatchResult { - let __within_span__ = { - use ::tracing::__macro_support::Callsite as _; - static CALLSITE: ::tracing::__macro_support::MacroCallsite = { - use ::tracing::__macro_support::MacroCallsite; - static META: ::tracing::Metadata<'static> = { - ::tracing_core::metadata::Metadata::new( - "submit_unsigned", - "frame_election_providers::two_phase", - ::tracing::Level::TRACE, - Some("frame/election-providers/src/two_phase/mod.rs"), - Some(469u32), - Some("frame_election_providers::two_phase"), - ::tracing_core::field::FieldSet::new( - &[], - ::tracing_core::callsite::Identifier(&CALLSITE), - ), - ::tracing::metadata::Kind::SPAN, - ) - }; - MacroCallsite::new(&META) - }; - let mut interest = ::tracing::subscriber::Interest::never(); - if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL - && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current() - && { - interest = CALLSITE.interest(); - !interest.is_never() - } - && CALLSITE.is_enabled(interest) - { - let meta = CALLSITE.metadata(); - ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) }) - } else { - let span = CALLSITE.disabled_span(); - {}; - span - } - }; - let __tracing_guard__ = __within_span__.enter(); - { - ensure_none(origin)?; - let _ = Self::unsigned_pre_dispatch_checks(&solution)?; - let ready = Self::feasibility_check(solution, ElectionCompute::Unsigned).expect( - "Invalid unsigned submission must produce invalid block and deprive \ - validator from their authoring reward.", - ); - >::put(ready); - Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); - } - Ok(()) - } - } - /// Dispatchable calls. - /// - /// Each variant of this enum maps to a dispatchable function from the associated module. - pub enum Call - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[codec(skip)] - __PhantomItem( - ::frame_support::sp_std::marker::PhantomData<(T,)>, - ::frame_support::Never, - ), - #[allow(non_camel_case_types)] - /// Submit a solution for the signed phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// The solution is potentially queued, based on the claimed score and processed at the end - /// of the signed phase. - /// - /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution - /// might be rewarded, slashed, or get all or a part of the deposit back. - submit(RawSolution>), - #[allow(non_camel_case_types)] - /// Submit a solution for the unsigned phase. - /// - /// The dispatch origin fo this call must be __signed__. - /// - /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. - /// Moreover, this unsigned solution is only validated when submitted to the pool from the - /// local process. Effectively, this means that only active validators can submit this - /// transaction when authoring a block. - /// - /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will - /// panic if the solution submitted by the validator is invalid, effectively putting their - /// authoring reward at risk. - /// - /// No deposit or reward is associated with this. - submit_unsigned(RawSolution>), - } - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Encode for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - { - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( - &self, - __codec_dest_edqy: &mut __CodecOutputEdqy, - ) { - match *self { - Call::submit(ref aa) => { - __codec_dest_edqy.push_byte(0usize as u8); - __codec_dest_edqy.push(aa); - } - Call::submit_unsigned(ref aa) => { - __codec_dest_edqy.push_byte(1usize as u8); - __codec_dest_edqy.push(aa); - } - _ => (), - } - } - } - impl _parity_scale_codec::EncodeLike for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - RawSolution>: _parity_scale_codec::Encode, - { - } - }; - const _: () = { - #[allow(unknown_lints)] - #[allow(rust_2018_idioms)] - extern crate codec as _parity_scale_codec; - impl _parity_scale_codec::Decode for Call - where - ExtendedBalance: From>>, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - RawSolution>: _parity_scale_codec::Decode, - { - fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( - __codec_input_edqy: &mut __CodecInputEdqy, - ) -> core::result::Result { - match __codec_input_edqy.read_byte()? { - __codec_x_edqy if __codec_x_edqy == 0usize as u8 => Ok(Call::submit({ - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => return Err("Error decoding field Call :: submit.0".into()), - Ok(__codec_res_edqy) => __codec_res_edqy, - } - })), - __codec_x_edqy if __codec_x_edqy == 1usize as u8 => { - Ok(Call::submit_unsigned({ - let __codec_res_edqy = - _parity_scale_codec::Decode::decode(__codec_input_edqy); - match __codec_res_edqy { - Err(_) => { - return Err( - "Error decoding field Call :: submit_unsigned.0".into() - ) - } - Ok(__codec_res_edqy) => __codec_res_edqy, - } - })) - } - _ => Err("No such variant in enum Call".into()), - } - } - } - }; - impl ::frame_support::dispatch::GetDispatchInfo for Call - where - ExtendedBalance: From>>, - { - fn get_dispatch_info(&self) -> ::frame_support::dispatch::DispatchInfo { - match *self { - Call::submit(ref solution) => { - let base_weight = T::WeightInfo::submit(); - let weight = >, - )>>::weigh_data(&base_weight, (solution,)); - let class = - >, - )>>::classify_dispatch(&base_weight, (solution,)); - let pays_fee = >, - )>>::pays_fee(&base_weight, (solution,)); - ::frame_support::dispatch::DispatchInfo { - weight, - class, - pays_fee, - } - } - Call::submit_unsigned(ref solution) => { - let base_weight = T::WeightInfo::submit_unsigned(); - let weight = >, - )>>::weigh_data(&base_weight, (solution,)); - let class = - >, - )>>::classify_dispatch(&base_weight, (solution,)); - let pays_fee = >, - )>>::pays_fee(&base_weight, (solution,)); - ::frame_support::dispatch::DispatchInfo { - weight, - class, - pays_fee, - } - } - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"__PhantomItem should never be used.",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - } - } - } - impl ::frame_support::dispatch::GetCallName for Call - where - ExtendedBalance: From>>, - { - fn get_call_name(&self) -> &'static str { - match *self { - Call::submit(ref solution) => { - let _ = (solution); - "submit" - } - Call::submit_unsigned(ref solution) => { - let _ = (solution); - "submit_unsigned" - } - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"__PhantomItem should never be used.",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - } - } - fn get_call_names() -> &'static [&'static str] { - &["submit", "submit_unsigned"] - } - } - pub use ::frame_support::traits::GetPalletVersion as _; - impl ::frame_support::traits::GetPalletVersion for Module - where - ExtendedBalance: From>>, - { - fn current_version() -> ::frame_support::traits::PalletVersion { - frame_support::traits::PalletVersion { - major: 2u16, - minor: 0u8, - patch: 0u8, - } - } - fn storage_version() -> Option<::frame_support::traits::PalletVersion> { - let key = ::frame_support::traits::PalletVersion::storage_key::< - ::PalletInfo, - Self, - >() - .expect("Every active pallet has a name in the runtime; qed"); - ::frame_support::storage::unhashed::get(&key) - } - } - impl ::frame_support::traits::OnGenesis for Module - where - ExtendedBalance: From>>, - { - fn on_genesis() { - frame_support::traits::PalletVersion { - major: 2u16, - minor: 0u8, - patch: 0u8, - } - .put_into_storage::<::PalletInfo, Self>(); - } - } - impl ::frame_support::dispatch::Clone for Call - where - ExtendedBalance: From>>, - { - fn clone(&self) -> Self { - match *self { - Call::submit(ref solution) => Call::submit((*solution).clone()), - Call::submit_unsigned(ref solution) => Call::submit_unsigned((*solution).clone()), - _ => ::std::rt::begin_panic("internal error: entered unreachable code"), - } - } - } - impl ::frame_support::dispatch::PartialEq for Call - where - ExtendedBalance: From>>, - { - fn eq(&self, _other: &Self) -> bool { - match *self { - Call::submit(ref solution) => { - let self_params = (solution,); - if let Call::submit(ref solution) = *_other { - self_params == (solution,) - } else { - match *_other { - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic("internal error: entered unreachable code") - } - _ => false, - } - } - } - Call::submit_unsigned(ref solution) => { - let self_params = (solution,); - if let Call::submit_unsigned(ref solution) = *_other { - self_params == (solution,) - } else { - match *_other { - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic("internal error: entered unreachable code") - } - _ => false, - } - } - } - _ => ::std::rt::begin_panic("internal error: entered unreachable code"), - } - } - } - impl ::frame_support::dispatch::Eq for Call where - ExtendedBalance: From>> - { - } - impl ::frame_support::dispatch::fmt::Debug for Call - where - ExtendedBalance: From>>, - { - fn fmt( - &self, - _f: &mut ::frame_support::dispatch::fmt::Formatter, - ) -> ::frame_support::dispatch::result::Result<(), ::frame_support::dispatch::fmt::Error> { - match *self { - Call::submit(ref solution) => _f.write_fmt(::core::fmt::Arguments::new_v1( - &["", ""], - &match (&"submit", &(solution.clone(),)) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), - ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), - ], - }, - )), - Call::submit_unsigned(ref solution) => { - _f.write_fmt(::core::fmt::Arguments::new_v1( - &["", ""], - &match (&"submit_unsigned", &(solution.clone(),)) { - (arg0, arg1) => [ - ::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Display::fmt), - ::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt), - ], - }, - )) - } - _ => ::std::rt::begin_panic("internal error: entered unreachable code"), - } - } - } - impl ::frame_support::traits::UnfilteredDispatchable for Call - where - ExtendedBalance: From>>, - { - type Origin = T::Origin; - fn dispatch_bypass_filter( - self, - _origin: Self::Origin, - ) -> ::frame_support::dispatch::DispatchResultWithPostInfo { - match self { - Call::submit(solution) => >::submit(_origin, solution) - .map(Into::into) - .map_err(Into::into), - Call::submit_unsigned(solution) => >::submit_unsigned(_origin, solution) - .map(Into::into) - .map_err(Into::into), - Call::__PhantomItem(_, _) => { - ::std::rt::begin_panic_fmt(&::core::fmt::Arguments::new_v1( - &["internal error: entered unreachable code: "], - &match (&"__PhantomItem should never be used.",) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Display::fmt, - )], - }, - )) - } - } - } - } - impl ::frame_support::dispatch::Callable for Module - where - ExtendedBalance: From>>, - { - type Call = Call; - } - impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[allow(dead_code)] - pub fn call_functions() -> &'static [::frame_support::dispatch::FunctionMetadata] { - &[ - ::frame_support::dispatch::FunctionMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("submit"), - arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - ::frame_support::dispatch::FunctionArgumentMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), - ty: ::frame_support::dispatch::DecodeDifferent::Encode( - "RawSolution>", - ), - }, - ]), - documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - r" Submit a solution for the signed phase.", - r"", - r" The dispatch origin fo this call must be __signed__.", - r"", - r" The solution is potentially queued, based on the claimed score and processed at the end", - r" of the signed phase.", - r"", - r" A deposit is reserved and recorded for the solution. Based on the outcome, the solution", - r" might be rewarded, slashed, or get all or a part of the deposit back.", - ]), - }, - ::frame_support::dispatch::FunctionMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("submit_unsigned"), - arguments: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - ::frame_support::dispatch::FunctionArgumentMetadata { - name: ::frame_support::dispatch::DecodeDifferent::Encode("solution"), - ty: ::frame_support::dispatch::DecodeDifferent::Encode( - "RawSolution>", - ), - }, - ]), - documentation: ::frame_support::dispatch::DecodeDifferent::Encode(&[ - r" Submit a solution for the unsigned phase.", - r"", - r" The dispatch origin fo this call must be __signed__.", - r"", - r" This submission is checked on the fly, thus it is likely yo be more limited and smaller.", - r" Moreover, this unsigned solution is only validated when submitted to the pool from the", - r" local process. Effectively, this means that only active validators can submit this", - r" transaction when authoring a block.", - r"", - r" To prevent any incorrect solution (and thus wasted time/weight), this transaction will", - r" panic if the solution submitted by the validator is invalid, effectively putting their", - r" authoring reward at risk.", - r"", - r" No deposit or reward is associated with this.", - ]), - }, - ] - } - } - impl Module - where - ExtendedBalance: From>>, - { - #[doc(hidden)] - #[allow(dead_code)] - pub fn module_constants_metadata( - ) -> &'static [::frame_support::dispatch::ModuleConstantMetadata] { - &[] - } - } - impl ::frame_support::dispatch::ModuleErrorMetadata for Module - where - ExtendedBalance: From>>, - { - fn metadata() -> &'static [::frame_support::dispatch::ErrorMetadata] { - as ::frame_support::dispatch::ModuleErrorMetadata>::metadata() - } - } - impl Module - where - ExtendedBalance: From>>, - { - /// Checks the feasibility of a solution. - /// - /// This checks the solution for the following: - /// - /// 0. **all** of the used indices must be correct. - /// 1. present correct number of winners. - /// 2. any assignment is checked to match with `SnapshotVoters`. - /// 3. for each assignment, the check of `ElectionDataProvider` is also examined. - /// 4. the claimed score is valid. - fn feasibility_check( - solution: RawSolution>, - compute: ElectionCompute, - ) -> Result, FeasibilityError> { - let RawSolution { compact, score } = solution; - let winners = compact.unique_targets(); - { - if !(winners.len() as u32 == Self::desired_targets()) { - { - return Err(FeasibilityError::WrongWinnerCount.into()); - }; - } - }; - let snapshot_voters = - Self::snapshot_voters().ok_or(FeasibilityError::SnapshotUnavailable)?; - let snapshot_targets = - Self::snapshot_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - let voter_at = |i: crate::two_phase::CompactVoterIndexOf| -> Option { - as crate::TryInto>::try_into(i) - .ok() - .and_then(|i| snapshot_voters.get(i).map(|(x, _, _)| x).cloned()) - }; - let target_at = |i: crate::two_phase::CompactTargetIndexOf| -> Option { - as crate::TryInto>::try_into(i) - .ok() - .and_then(|i| snapshot_targets.get(i).cloned()) - }; - let winners = winners - .into_iter() - .map(|i| target_at(i).ok_or(FeasibilityError::InvalidWinner)) - .collect::, FeasibilityError>>()?; - let assignments = compact - .into_assignment(voter_at, target_at) - .map_err::(Into::into)?; - let _ = assignments - .iter() - .map(|Assignment { who, distribution }| { - snapshot_voters.iter().find(|(v, _, _)| v == who).map_or( - Err(FeasibilityError::InvalidVoter), - |(_, _, t)| { - if distribution.iter().map(|(x, _)| x).all(|x| t.contains(x)) - && T::ElectionDataProvider::feasibility_check_assignment::< - CompactAccuracyOf, - >(who, distribution) - { - Ok(()) - } else { - Err(FeasibilityError::InvalidVote) - } - }, - ) - }) - .collect::>()?; - let stake_of = |who: &T::AccountId| -> crate::VoteWeight { - snapshot_voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - }; - let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) - .map_err::(Into::into)?; - let supports = sp_npos_elections::to_supports(&winners, &staked_assignments) - .map_err::(Into::into)?; - let known_score = supports.evaluate(); - { - if !(known_score == score) { - { - return Err(FeasibilityError::InvalidScore.into()); - }; - } - }; - Ok(ReadySolution { - supports, - compute, - score, - }) - } - /// On-chain fallback of election. - fn onchain_fallback() -> Result, Error> { - let RoundSnapshot { - desired_targets, - voters, - targets, - } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; - >::elect::( - desired_targets, - targets, - voters, - ) - .map_err(Into::into) - } - } - impl ElectionProvider for Module - where - ExtendedBalance: From>>, - { - const NEEDS_ELECT_DATA: bool = false; - type Error = Error; - fn elect( - _to_elect: usize, - _targets: Vec, - _voters: Vec<(T::AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>, - { - Self::queued_solution() - .map_or_else( - || { - Self::onchain_fallback() - .map(|r| (r, ElectionCompute::OnChain)) - .map_err(Into::into) - }, - |ReadySolution { - supports, compute, .. - }| Ok((supports, compute)), - ) - .map(|(supports, compute)| { - >::put(Phase::Off); - >::kill(); - Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); - { - let lvl = ::log::Level::Info; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::__private_api_log( - ::core::fmt::Arguments::new_v1( - &["\u{1f3e6} Finalized election round with compute ", "."], - &match (&compute,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - ), - lvl, - &( - crate::LOG_TARGET, - "frame_election_providers::two_phase", - "frame/election-providers/src/two_phase/mod.rs", - 733u32, - ), - ); - } - }; - supports - }) - .map_err(|err| { - Self::deposit_event(RawEvent::ElectionFinalized(None)); - { - let lvl = ::log::Level::Error; - if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() { - ::log::__private_api_log( - ::core::fmt::Arguments::new_v1( - &["\u{1f3e6} Failed to finalize election round. Error = "], - &match (&err,) { - (arg0,) => [::core::fmt::ArgumentV1::new( - arg0, - ::core::fmt::Debug::fmt, - )], - }, - ), - lvl, - &( - crate::LOG_TARGET, - "frame_election_providers::two_phase", - "frame/election-providers/src/two_phase/mod.rs", - 738u32, - ), - ); - } - }; - err - }) - } - fn ongoing() -> bool { - match Self::current_phase() { - Phase::Signed | Phase::Unsigned(_) => true, - _ => false, - } - } - } -} -const LOG_TARGET: &'static str = "election-provider"; -#[doc(hidden)] -pub use sp_npos_elections::VoteWeight; -#[doc(hidden)] -pub use sp_runtime::traits::UniqueSaturatedInto; -#[doc(hidden)] -pub use sp_std::convert::TryInto; diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs index fbd20a9287aed..adf308038879b 100644 --- a/frame/election-providers/src/lib.rs +++ b/frame/election-providers/src/lib.rs @@ -19,10 +19,10 @@ //! //! Two main election providers are implemented in this crate. //! -//! 1. [`onchain`]: A `struct` that perform the election onchain (i.e. in the fly). This type is +//! 1. [onchain]: A `struct` that perform the election onchain (i.e. in the fly). This type is //! likely to be expensive for most chains and damage the block time. Only use when you are sure //! that the inputs are bounded and small enough. -//! 2. [`two_phase`]: An individual `pallet` that performs the election in two phases, signed and +//! 2. [two_phase]: An individual `pallet` that performs the election in two phases, signed and //! unsigned. Needless to say, the pallet needs to be included in the final runtime. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index 037e346918998..b3e75d55b5f7c 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -24,9 +24,9 @@ pub use frame_benchmarking::{account, benchmarks, whitelist_account, whitelisted use frame_support::assert_ok; use frame_system::RawOrigin; use rand::{seq::SliceRandom, thread_rng}; -use sp_npos_elections::{ExtendedBalance}; +use sp_npos_elections::ExtendedBalance; use sp_runtime::InnerOf; -use std::convert::TryInto; +use sp_std::convert::TryInto; const SEED: u32 = 0; @@ -42,7 +42,7 @@ fn solution_with_size( ) -> RawSolution> where ExtendedBalance: From>>, - > as std::convert::TryFrom>::Error: std::fmt::Debug, + > as sp_std::convert::TryFrom>::Error: sp_std::fmt::Debug, { assert!(witness.targets >= winners_count, "must have enough targets"); assert!( @@ -146,8 +146,7 @@ where benchmarks! { where_clause { where ExtendedBalance: From>>, - // TODO: do I really need this? - > as std::convert::TryFrom>::Error: std::fmt::Debug, + > as sp_std::convert::TryFrom>::Error: sp_std::fmt::Debug, } _{} @@ -212,8 +211,6 @@ benchmarks! { // number of desired targets. Must be a subset of `t` component. let d in 30 .. 60; - println!("running v {}, t {}, a {}, d {}", v, t, a, d); - let witness = WitnessData { voters: v, targets: t }; let raw_solution = solution_with_size::(witness, a, d); diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index b27f72f29ff6c..d05c2841ecbfd 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -18,7 +18,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, PerU16, }; -use std::{cell::RefCell, sync::Arc}; +use std::sync::Arc; pub use frame_support::{assert_noop, assert_ok}; @@ -149,51 +149,12 @@ impl pallet_balances::Config for Runtime { type WeightInfo = (); } -use paste::paste; -// TODO: no need for this anymore. -macro_rules! parameter_types_thread_local { - ( - $( - static $name:ident : $type:ty = $default:expr; - )* - ) => { - parameter_types_thread_local! { - @THREAD_LOCAL($( - $name, $type, $default, - )*) - } - - parameter_types_thread_local! { - @GETTER_STRUCT($( - $name, $type, - )*) - } - }; - (@THREAD_LOCAL($($name:ident, $type:ty, $default:expr,)*)) => { - thread_local! { - $( - static $name: RefCell<$type> = RefCell::new($default); - )* - } - }; - (@GETTER_STRUCT($($name:ident, $type:ty,)*)) => { - $( - paste! { - pub struct [<$name:camel>]; - impl Get<$type> for [<$name:camel>] { - fn get() -> $type { $name.with(|v| v.borrow().clone() )} - } - } - )* - } -} - -parameter_types_thread_local! { - static SIGNED_PHASE: u64 = 10; - static UNSIGNED_PHASE: u64 = 5; - static MAX_SIGNED_SUBMISSIONS: u32 = 5; - static TARGETS: Vec = vec![10, 20, 30, 40]; - static VOTERS: Vec<(AccountId, VoteWeight, Vec)> = vec![ +parameter_types! { + pub static SignedPhase: u64 = 10; + pub static UnsignedPhase: u64 = 5; + pub static MaxSignedSubmissions: u32 = 5; + pub static Targets: Vec = vec![10, 20, 30, 40]; + pub static Voters: Vec<(AccountId, VoteWeight, Vec)> = vec![ (1, 10, vec![10, 20]), (2, 10, vec![30, 40]), (3, 10, vec![40]), @@ -204,17 +165,20 @@ parameter_types_thread_local! { (30, 30, vec![30]), (40, 40, vec![40]), ]; - static DESIRED_TARGETS: u32 = 2; - static SIGNED_DEPOSIT_BASE: Balance = 5; - static SIGNED_REWARD_BASE: Balance = 7; - static MAX_UNSIGNED_ITERATIONS: u32 = 5; - static UNSIGNED_PRIORITY: u64 = 100; - static SOLUTION_IMPROVEMENT_THRESHOLD: Perbill = Perbill::zero(); - static MINER_MAX_WEIGHT: Weight = 128; + pub static DesiredTargets: u32 = 2; + pub static SignedDepositBase: Balance = 5; + pub static SignedDepositByte: Balance = 0; + pub static SignedDepositWeight: Balance = 0; + pub static SignedRewardBase: Balance = 7; + pub static SignedRewardFactor: Perbill = Perbill::zero(); + pub static SignedRewardMax: Balance = 10; + pub static MinerMaxIterations: u32 = 5; + pub static UnsignedPriority: u64 = 100; + pub static SolutionImprovementThreshold: Perbill = Perbill::zero(); + pub static MinerMaxWeight: Weight = 128; + pub static EpochLength: u64 = 30; } - - impl crate::two_phase::Config for Runtime { type Event = (); type Currency = Balances; @@ -222,15 +186,15 @@ impl crate::two_phase::Config for Runtime { type UnsignedPhase = UnsignedPhase; type MaxSignedSubmissions = MaxSignedSubmissions; type SignedRewardBase = SignedRewardBase; - type SignedRewardFactor = (); - type SignedRewardMax = (); + type SignedRewardFactor = SignedRewardFactor; + type SignedRewardMax = SignedRewardMax; type SignedDepositBase = SignedDepositBase; type SignedDepositByte = (); type SignedDepositWeight = (); type SolutionImprovementThreshold = SolutionImprovementThreshold; type SlashHandler = (); type RewardHandler = (); - type MinerMaxIterations = MaxUnsignedIterations; + type MinerMaxIterations = MinerMaxIterations; type MinerMaxWeight = MinerMaxWeight; type UnsignedPriority = UnsignedPriority; type ElectionDataProvider = StakingMock; @@ -247,14 +211,9 @@ where pub type Extrinsic = sp_runtime::testing::TestXt; +#[derive(Default)] pub struct ExtBuilder {} -impl Default for ExtBuilder { - fn default() -> Self { - Self {} - } -} - pub struct StakingMock; impl ElectionDataProvider for StakingMock { type CompactSolution = TestCompact; @@ -272,25 +231,42 @@ impl ElectionDataProvider for StakingMock { true } fn next_election_prediction(now: u64) -> u64 { - now + 20 - now % 20 + now + EpochLength::get() - now % EpochLength::get() } } impl ExtBuilder { pub fn max_signed_submission(self, count: u32) -> Self { - MAX_SIGNED_SUBMISSIONS.with(|v| *v.borrow_mut() = count); + ::set(count); self } pub fn unsigned_priority(self, p: u64) -> Self { - UNSIGNED_PRIORITY.with(|v| *v.borrow_mut() = p); + ::set(p); self } pub fn solution_improvement_threshold(self, p: Perbill) -> Self { - SOLUTION_IMPROVEMENT_THRESHOLD.with(|v| *v.borrow_mut() = p); + ::set(p); + self + } + pub fn signed_deposit(self, base: u64, byte: u64, weight: u64) -> Self { + ::set(base); + ::set(byte); + ::set(weight); + self + } + pub fn phases(self, signed: u64, unsigned: u64) -> Self { + ::set(signed); + ::set(unsigned); + self + } + pub fn reward(self, base: u64, factor: Perbill, max: u64) -> Self { + ::set(base); + ::set(factor); + ::set(max); self } pub fn desired_targets(self, t: u32) -> Self { - DESIRED_TARGETS.with(|v| *v.borrow_mut() = t); + ::set(t); self } pub fn add_voter(self, who: AccountId, stake: Balance, targets: Vec) -> Self { @@ -315,6 +291,7 @@ impl ExtBuilder { sp_io::TestExternalities::from(storage) } + pub fn build_offchainify( self, iters: u32, @@ -332,6 +309,7 @@ impl ExtBuilder { (ext, pool_state) } + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { self.build().execute_with(test) } diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 26f3185e02c8d..f744324e27614 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -17,14 +17,15 @@ //! # Two phase election provider pallet. //! -//! As the name suggests, this election-provider has two distinct phases (see [`Phase`]), signed and -//! unsigned. +//! As the name suggests, this election-provider has two distinct phases (see +//! [Phase](two_phase::Phase)), signed and unsigned. //! //! ## Phases //! //! The timeline of pallet is as follows. At each block, //! [`ElectionDataProvider::next_election_prediction`] is used to estimate the time remaining to the -//! next call to `elect`. Based on this, a phase is chosen. The timeline is as follows. +//! next call to [`ElectionProvider::elect`]. Based on this, a phase is chosen. The timeline is as +//! follows. //! //! ```ignore //! elect() @@ -32,23 +33,29 @@ //! +-------------------------------------------------------------------+ //! Phase::Off + Phase::Signed + Phase::Unsigned + //! -//! Note that the unsigned phase starts `T::UnsignedPhase` blocks before the -//! `next_election_prediction`, but only ends when a call to `ElectionProvider::elect` happens. -//! //! ``` +//! +//! Note that the unsigned phase starts [Config::UnsignedPhase](two_phase::Config::UnsignedPhase) +//! blocks before the `next_election_prediction`, but only ends when a call to +//! `ElectionProvider::elect` happens. +//! +//! Each of the phases can be disabled by essentially setting their length to zero. If both phases +//! have length zero, then the pallet essentially runs only the on-chain backup. +//! //! ### Signed Phase //! -//! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A -//! deposit is reserved, based on the size of the solution, for the cost of keeping this solution -//! on-chain for a number of blocks. A maximum of [`Config::MaxSignedSubmissions`] solutions are -//! stored. The queue is always sorted based on score (worse to best). +//! In the signed phase, solutions (of type [RawSolution](struct.RawSolution.html)) are submitted +//! and queued on chain. A deposit is reserved, based on the size of the solution, for the cost of +//! keeping this solution on-chain for a number of blocks, and the potential weight of the solution +//! upon being checked. A maximum of [`Config::MaxSignedSubmissions`] solutions are stored. The +//! queue is always sorted based on score (worse to best). //! //! Upon arrival of a new solution: //! //! 1. If the queue is not full, it is stored in the appropriate index. //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the -//! worse solution is discarded (TODO: must return the bond here) and the new solution is stored -//! in the correct index. +//! worse solution is discarded, the bond of the outgoing solution is returned, and the new +//! solution is stored in the correct index. //! 3. If the queue is full and the solution is not an improvement compared to any of the queued //! ones, it is instantly rejected and no additional bond is reserved. //! @@ -58,8 +65,8 @@ //! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed //! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure //! the score claimed by this score was correct, among other checks. At each step, if the current -//! best solution passes the feasibility check, it is considered to be the best one. The sender -//! of the origin is rewarded, and the rest of the queued solutions get their deposit back, without +//! best solution passes the feasibility check, it is considered to be the best one. The sender of +//! the origin is rewarded, and the rest of the queued solutions get their deposit back, without //! being checked. //! //! The following example covers all of the cases at the end of the signed phase: @@ -79,32 +86,53 @@ //! +-------------------------------+ //! ``` //! -//! TODO: what if length of some phase is zero? -//! //! Note that both of the bottom solutions end up being discarded and get their deposit back, //! despite one of them being invalid. //! //! ## Unsigned Phase //! -//! If signed phase ends with a good solution, then the unsigned phase will be `active` -//! ([`Phase::Unsigned(true)`]), else the unsigned phase will be `passive`. +//! The unsigned phase will always follow the signed phase, with the specified duration. In this +//! phase, only validator nodes can submit solutions. A validator node who has offchain workers +//! enabled will start to mine a solution in this phase and submits it back to the chain as an +//! unsigned transaction, thus the name _unsigned_ phase. //! -//! TODO +//! Validators will only submit solutions if the one that they have computed is sufficiently better +//! than the best queued one (see [SolutionImprovementThreshold]) and will limit the weigh of the +//! solution to [MinerMaxWeight]. //! //! ### Fallback //! -//! If we reach the end of both phases (i.e. call to `ElectionProvider::elect` happens) and no good +//! If we reach the end of both phases (i.e. call to [ElectionProvider::elect] happens) and no good //! solution is queued, then we fallback to an on-chain election. The on-chain election is slow, and //! contains to balancing or reduction post-processing. //! -//! ## Correct Submission +//! ## Feasible Solution (correct solution) //! -//! TODO +//! All submissions must undergo a feasibility check. A feasible solution is as follows: +//! +//! 0. **all** of the used indices must be correct. +//! 1. present correct number of winners. +//! 2. any assignment is checked to match with [Snapshot::voters]. +//! 3. for each assignment, the check of `ElectionDataProvider` is also examined. +//! 4. the claimed score is valid. //! //! ## Accuracy //! -//! TODO +//! Solutions are encoded using indices of the [Snapshot]. The accuracy used for these indices +//! heavily influences the size of the solution. These indices are configured by an upstream user of +//! this pallet, through `CompactSolution` type of the `ElectionDataProvider`. +//! +//! ## Future Plans //! +//! **Challenge Phase**. We plan adding a third phase to the pallet, called the challenge phase. +//! This is phase in which no further solutions are processed, and the current best solution might +//! be challenged by anyone (signed or unsigned). The main plan here is to enforce the solution to +//! be PJR. Checking PJR on-chain is quite expensive, yet proving that a solution is **not** PJR is +//! rather cheap. If a queued solution is challenged: +//! +//! 1. We must surely slash whoever submitted that solution (might be a challenge for unsigned +//! solutions). +//! 2. It is probably fine to fallback to the on-chain election, as we expect this to happen rarely. use crate::onchain::OnChainSequentialPhragmen; use codec::{Decode, Encode, HasCompact}; @@ -127,8 +155,7 @@ use sp_runtime::{ }; use sp_std::prelude::*; -// TODO: make this only test. -#[cfg(any(feature = "runtime-benchmarks", test))] +#[cfg(feature = "runtime-benchmarks")] mod benchmarking; #[cfg(test)] mod mock; @@ -373,6 +400,8 @@ impl From for FeasibilityError { } pub trait WeightInfo { + fn open_signed_phase() -> Weight; + fn open_unsigned_phase() -> Weight; fn feasibility_check(v: u32, t: u32, a: u32, d: u32) -> Weight; fn submit(v: u32, t: u32, a: u32, d: u32) -> Weight; fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight; @@ -389,6 +418,12 @@ impl WeightInfo for () { fn submit_unsigned(_: u32, _: u32, _: u32, _: u32) -> Weight { Default::default() } + fn open_signed_phase() -> Weight { + Default::default() + } + fn open_unsigned_phase() -> Weight { + Default::default() + } } pub trait Config: frame_system::Config + SendTransactionTypes> @@ -408,7 +443,6 @@ where /// Maximum number of singed submissions that can be queued. type MaxSignedSubmissions: Get; - // TODO: these need input from the research team type SignedRewardBase: Get>; type SignedRewardFactor: Get; type SignedRewardMax: Get>>; @@ -518,27 +552,24 @@ decl_module! { let remaining = next_election - now; match Self::current_phase() { Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { - // check only for the signed phase. + // signed phae can only start after Off. >::put(Phase::Signed); Round::mutate(|r| *r +=1); Self::start_signed_phase(); log!(info, "Starting signed phase at #{:?} , round {}.", now, Self::round()); + T::WeightInfo::open_signed_phase() }, - Phase::Signed if remaining <= unsigned_deadline && remaining > 0u32.into() => { - // check the unsigned phase. - // TODO: this is probably very bad as it is.. we should only assume we don't - // want OCW solutions if the solutions is checked to be PJR as well. Probably a - // good middle ground for now is to always let the unsigned phase be open. - let found_solution = Self::finalize_signed_phase(); - >::put(Phase::Unsigned((!found_solution, now))); + Phase::Signed | Phase::Off if remaining <= unsigned_deadline && remaining > 0u32.into() => { + // unsigned phase can start after Off or Signed. + let _ = Self::finalize_signed_phase(); + >::put(Phase::Unsigned((true, now))); log!(info, "Starting unsigned phase at #{:?}.", now); + T::WeightInfo::open_unsigned_phase() }, _ => { - // Nothing. We wait in the unsigned phase until we receive the call to `elect`. + Zero::zero() } } - - Default::default() } fn offchain_worker(n: T::BlockNumber) { @@ -572,7 +603,7 @@ decl_module! { // ensure round is correct. ensure!(Self::round() == solution.round, PalletError::::InvalidRound); - // TODO: this is the only case where having separate snapshot would have been better + // NOTE: this is the only case where having separate snapshot would have been better // because could do just decode_len. But we can create abstractions to do this. // build witness. @@ -587,8 +618,8 @@ decl_module! { let index = maybe_index.expect("Option checked to be `Some`; qed."); // collect deposit. Thereafter, the function cannot fail. - // TODO: ensure this index is correct. - let deposit = signed_submissions[index].deposit; + // Defensive -- index is valid. + let deposit = signed_submissions.get(index).map(|s| s.deposit).unwrap_or_default(); T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; // store the new signed submission. @@ -655,7 +686,7 @@ where /// /// 0. **all** of the used indices must be correct. /// 1. present correct number of winners. - /// 2. any assignment is checked to match with `SnapshotVoters`. + /// 2. any assignment is checked to match with [Snapshot::voters]. /// 3. for each assignment, the check of `ElectionDataProvider` is also examined. /// 4. the claimed score is valid. fn feasibility_check( @@ -665,8 +696,6 @@ where let RawSolution { compact, score, .. } = solution; // winners are not directly encoded in the solution. - // TODO: dupe winner - // TODO: dupe in compact. let winners = compact.unique_targets(); // read the entire snapshot. NOTE: could be optimized. @@ -678,7 +707,7 @@ where ensure!( winners.len() as u32 == desired_targets, - FeasibilityError::WrongWinnerCount + FeasibilityError::WrongWinnerCount, ); // ----- Start building. First, we need some closures. @@ -742,11 +771,25 @@ where /// On-chain fallback of election. fn onchain_fallback() -> Result, Error> { + // If the length of singed phase is zero, the signed phase never starts and thus snapshot is + // never created. + let get_snapshot_backup = || { + let targets = T::ElectionDataProvider::targets(); + let voters = T::ElectionDataProvider::voters(); + let desired_targets = T::ElectionDataProvider::desired_targets(); + + RoundSnapshot { + voters, + targets, + desired_targets, + } + }; + let RoundSnapshot { desired_targets, voters, targets, - } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; + } = Self::snapshot().unwrap_or_else(get_snapshot_backup); >::elect::( desired_targets as usize, targets, @@ -774,6 +817,7 @@ where Self::queued_solution() .map_or_else( || { + Self::onchain_fallback() .map(|r| (r, ElectionCompute::OnChain)) .map_err(Into::into) @@ -811,7 +855,7 @@ mod tests { #[test] fn phase_rotation_works() { ExtBuilder::default().build_and_execute(|| { - // 0 ------- 5 -------------- 15 ------- 20 + // 0 ------- 15 -------------- 25 ------- 30 ------- ------- 45 ------- 55 ------- 60 // | | // Signed Unsigned @@ -824,54 +868,65 @@ mod tests { assert!(TwoPhase::snapshot().is_none()); assert_eq!(TwoPhase::round(), 0); - roll_to(5); + roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Signed); assert!(TwoPhase::snapshot().is_some()); assert_eq!(TwoPhase::round(), 1); - roll_to(14); + roll_to(24); assert_eq!(TwoPhase::current_phase(), Phase::Signed); assert!(TwoPhase::snapshot().is_some()); assert_eq!(TwoPhase::round(), 1); - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(25); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); assert!(TwoPhase::snapshot().is_some()); - roll_to(19); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(29); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); assert!(TwoPhase::snapshot().is_some()); - roll_to(20); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(30); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); assert!(TwoPhase::snapshot().is_some()); // we close when upstream tells us to elect. - roll_to(21); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(32); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); assert!(TwoPhase::snapshot().is_some()); TwoPhase::elect::(2, Default::default(), Default::default()) .unwrap(); - assert_eq!(TwoPhase::current_phase(), Phase::Off); + + assert!(TwoPhase::current_phase().is_off()); assert!(TwoPhase::snapshot().is_none()); assert_eq!(TwoPhase::round(), 1); + + roll_to(44); + assert!(TwoPhase::current_phase().is_off()); + + roll_to(45); + assert!(TwoPhase::current_phase().is_signed()); + + roll_to(55); + assert!(TwoPhase::current_phase().is_unsigned_open_at(55)); }) } #[test] fn onchain_backup_works() { ExtBuilder::default().build_and_execute(|| { - roll_to(5); + roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Signed); - roll_to(20); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(25); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); // zilch solutions thus far. let supports = TwoPhase::elect::(2, Default::default(), Default::default()) .unwrap(); + assert_eq!( supports, vec![ @@ -893,4 +948,75 @@ mod tests { ) }) } + + #[test] + fn signed_phase_void() { + ExtBuilder::default().phases(0, 10).build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_off()); + + roll_to(19); + assert!(TwoPhase::current_phase().is_off()); + + roll_to(20); + dbg!(TwoPhase::current_phase()); + assert!(TwoPhase::current_phase().is_unsigned_open_at(20)); + + roll_to(30); + assert!(TwoPhase::current_phase().is_unsigned_open_at(20)); + + let _ = + TwoPhase::elect::(2, Default::default(), Default::default()) + .unwrap(); + + assert!(TwoPhase::current_phase().is_off()); + }); + } + + #[test] + fn unsigned_phase_void() { + ExtBuilder::default().phases(10, 0).build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_off()); + + roll_to(19); + assert!(TwoPhase::current_phase().is_off()); + + roll_to(20); + assert!(TwoPhase::current_phase().is_signed()); + + roll_to(30); + assert!(TwoPhase::current_phase().is_signed()); + + let _ = + TwoPhase::elect::(2, Default::default(), Default::default()) + .unwrap(); + + assert!(TwoPhase::current_phase().is_off()); + }); + } + + #[test] + fn both_phases_void() { + ExtBuilder::default().phases(0, 0).build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_off()); + + roll_to(19); + assert!(TwoPhase::current_phase().is_off()); + + roll_to(20); + assert!(TwoPhase::current_phase().is_off()); + + roll_to(30); + assert!(TwoPhase::current_phase().is_off()); + + // this module is now only capable of doing on-chain backup. + let _ = + TwoPhase::elect::(2, Default::default(), Default::default()) + .unwrap(); + + assert!(TwoPhase::current_phase().is_off()); + }); + } } diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index cf3c52118d37f..c7d097a2785f6 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -101,9 +101,15 @@ where } /// Find a proper position in the queue for the signed queue, whilst maintaining the order of - /// solution quality. + /// solution quality. If insertion was successful, `Some(index)` is returned where index is the + /// index of the newly inserted item. /// /// The length of the queue will always be kept less than or equal to `T::MaxSignedSubmissions`. + /// + /// If a solution is removed, their bond is unreserved. + /// + /// Invariant: The returned index is always a valid index in `queue` and can safely be used to + /// inspect the newly inserted element. pub fn insert_submission( who: &T::AccountId, queue: &mut Vec, CompactOf>>, @@ -146,8 +152,15 @@ where // It is either 0 (in which case `0 <= queue.len()`) or one of the queue indices // + 1. The biggest queue index is `queue.len() - 1`, thus `at <= queue.len()`. queue.insert(at, submission); + // if length has exceeded the limit, eject the weakest, return shifted index. if queue.len() as u32 > T::MaxSignedSubmissions::get() { - queue.remove(0); + Self::remove_weakest(queue); + // Invariant: at > 0 + // Proof by contradiction: Assume at is 0 and this will underflow. Then the + // previous length of the queue must have been `T::MaxSignedSubmissions` so + // that `queue.len() + 1` (for the newly inserted one) is more than + // `T::MaxSignedSubmissions`. But this would have been detected by the first + // if branch; qed. Some(at - 1) } else { Some(at) @@ -159,6 +172,18 @@ where outcome } + /// Removes the weakest element of the queue, namely the first one, should the length of the + /// queue be enough. noop if the queue is empty. Bond of the removed solution is returned. + pub fn remove_weakest( + queue: &mut Vec, CompactOf>>, + ) { + if queue.len() > 0 { + let SignedSubmission { who, deposit, .. } = queue.remove(0); + let _remainder = T::Currency::unreserve(&who, deposit); + debug_assert!(_remainder.is_zero()); + } + } + /// Collect sufficient deposit to store this solution this chain. /// /// The deposit is composed of 3 main elements: @@ -184,8 +209,13 @@ where /// The reward for this solution, if successfully chosen as the best one at the end of the /// signed phase. pub fn reward_for(solution: &RawSolution>) -> BalanceOf { - T::SignedRewardBase::get() - + T::SignedRewardFactor::get() * solution.score[0].saturated_into::>() + let raw_reward = T::SignedRewardBase::get() + + T::SignedRewardFactor::get() * solution.score[0].saturated_into::>(); + + match T::SignedRewardMax::get() { + Some(cap) => raw_reward.min(cap), + None => raw_reward, + } } } @@ -213,8 +243,8 @@ mod tests { #[test] fn should_pay_deposit() { ExtBuilder::default().build_and_execute(|| { - roll_to(5); - assert_eq!(TwoPhase::current_phase(), Phase::Signed); + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); let solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); @@ -229,8 +259,8 @@ mod tests { #[test] fn good_solution_is_rewarded() { ExtBuilder::default().build_and_execute(|| { - roll_to(5); - assert_eq!(TwoPhase::current_phase(), Phase::Signed); + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); let solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); @@ -243,11 +273,50 @@ mod tests { }) } + #[test] + fn reward_is_capped() { + ExtBuilder::default() + .reward(5, Perbill::from_percent(25), 10) + .build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); + + let solution = raw_solution(); + assert_eq!(solution.score[0], 40); + assert_eq!(balances(&99), (100, 0)); + + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!(balances(&99), (95, 5)); + + assert!(TwoPhase::finalize_signed_phase()); + // expected reward is 5 + 10 + assert_eq!(balances(&99), (100 + 10, 0)); + }); + + ExtBuilder::default() + .reward(5, Perbill::from_percent(25), 20) + .build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); + + let solution = raw_solution(); + assert_eq!(solution.score[0], 40); + assert_eq!(balances(&99), (100, 0)); + + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!(balances(&99), (95, 5)); + + assert!(TwoPhase::finalize_signed_phase()); + // expected reward is 5 + 10 + assert_eq!(balances(&99), (100 + 15, 0)); + }); + } + #[test] fn bad_solution_is_slashed() { ExtBuilder::default().build_and_execute(|| { - roll_to(5); - assert_eq!(TwoPhase::current_phase(), Phase::Signed); + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); let mut solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); @@ -268,8 +337,8 @@ mod tests { #[test] fn suppressed_solution_gets_bond_back() { ExtBuilder::default().build_and_execute(|| { - roll_to(5); - assert_eq!(TwoPhase::current_phase(), Phase::Signed); + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); let mut solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); @@ -295,45 +364,38 @@ mod tests { } #[test] - fn queue_is_always_sorted() { + fn cannot_submit_worse_with_full_queue() { ExtBuilder::default().build_and_execute(|| { - roll_to(5); - assert_eq!(TwoPhase::current_phase(), Phase::Signed); + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); - let solution = RawSolution { - score: [5, 0, 0], - ..Default::default() - }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + for s in 0..MaxSignedSubmissions::get() { + // score is always getting better + let solution = RawSolution { + score: [(5 + s).into(), 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + } - // then a worse one. + // weaker. let solution = RawSolution { score: [4, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); - // then a better one. - let solution = RawSolution { - score: [6, 0, 0], - ..Default::default() - }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); - - assert_eq!( - TwoPhase::signed_submissions() - .iter() - .map(|x| x.solution.score[0]) - .collect::>(), - vec![4, 5, 6] + assert_noop!( + TwoPhase::submit(Origin::signed(99), solution), + PalletError::::QueueFull, ); }) } #[test] - fn cannot_submit_worse_with_full_queue() { + fn weakest_is_removed_if_better_provided() { ExtBuilder::default().build_and_execute(|| { - roll_to(5); + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); for s in 0..MaxSignedSubmissions::get() { // score is always getting better @@ -344,25 +406,39 @@ mod tests { assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); } - // weaker. + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![5, 6, 7, 8, 9] + ); + + // better. let solution = RawSolution { - score: [4, 0, 0], + score: [20, 0, 0], ..Default::default() }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); - assert_noop!( - TwoPhase::submit(Origin::signed(99), solution), - PalletError::::QueueFull, + // the one with score 5 was rejected, the new one inserted. + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![6, 7, 8, 9, 20] ); }) } #[test] - fn weakest_is_removed_if_better_provided() { + fn weakest_is_removed_if_better_provided_wont_remove_self() { ExtBuilder::default().build_and_execute(|| { - roll_to(5); + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); - for s in 0..MaxSignedSubmissions::get() { + for s in 1..MaxSignedSubmissions::get() { // score is always getting better let solution = RawSolution { score: [(5 + s).into(), 0, 0], @@ -371,17 +447,23 @@ mod tests { assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); } + let solution = RawSolution { + score: [4, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_eq!( TwoPhase::signed_submissions() .into_iter() .map(|s| s.solution.score[0]) .collect::>(), - vec![5, 6, 7, 8, 9] + vec![4, 6, 7, 8, 9] ); // better. let solution = RawSolution { - score: [20, 0, 0], + score: [5, 0, 0], ..Default::default() }; assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); @@ -392,17 +474,51 @@ mod tests { .into_iter() .map(|s| s.solution.score[0]) .collect::>(), - vec![6, 7, 8, 9, 20] + vec![5, 6, 7, 8, 9] ); }) } + #[test] + fn early_ejected_solution_gets_bond_back() { + ExtBuilder::default() + .signed_deposit(2, 0, 0) + .build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); + + for s in 0..MaxSignedSubmissions::get() { + // score is always getting better + let solution = RawSolution { + score: [(5 + s).into(), 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + } + + assert_eq!(balances(&99).1, 2 * 5); + assert_eq!(balances(&999).1, 0); + + // better. + let solution = RawSolution { + score: [20, 0, 0], + ..Default::default() + }; + assert_ok!(TwoPhase::submit(Origin::signed(999), solution)); + + // got one bond back. + assert_eq!(balances(&99).1, 2 * 4); + assert_eq!(balances(&999).1, 2); + }) + } + #[test] fn equally_good_is_not_accepted() { ExtBuilder::default() .max_signed_submission(3) .build_and_execute(|| { - roll_to(5); + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); for i in 0..MaxSignedSubmissions::get() { let solution = RawSolution { @@ -437,10 +553,12 @@ mod tests { .max_signed_submission(3) .build_and_execute(|| { let scores = || TwoPhase::signed_submissions() - .into_iter() - .map(|s| s.solution.score[0]) - .collect::>(); - roll_to(5); + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(); + + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); let solution = RawSolution { score: [5, 0, 0], @@ -500,8 +618,8 @@ mod tests { // - bad_solution_is_slashed // - suppressed_solution_gets_bond_back ExtBuilder::default().build_and_execute(|| { - roll_to(5); - assert_eq!(TwoPhase::current_phase(), Phase::Signed); + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); assert_eq!(balances(&99), (100, 0)); assert_eq!(balances(&999), (100, 0)); diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 36789c96ce504..7c65034d0cde2 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -28,9 +28,9 @@ use sp_runtime::{ InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, }, - SaturatedConversion, + DispatchError, SaturatedConversion, }; -use sp_std::cmp::Ordering; +use sp_std::{cmp::Ordering, convert::TryInto}; /// Storage key used to store the persistent offchain worker status. pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; @@ -358,18 +358,23 @@ where } } - if let Err(_why) = Self::unsigned_pre_dispatch_checks(solution) { - return InvalidTransaction::Custom(99).into(); // TODO - } + + let _ = Self::unsigned_pre_dispatch_checks(solution) + .map_err(dispatch_error_to_invalid) + .map(Into::into)?; ValidTransaction::with_tag_prefix("OffchainElection") // The higher the score[0], the better a solution is. .priority( T::UnsignedPriority::get().saturating_add(solution.score[0].saturated_into()), ) - // TODO: need some provides to de-duplicate: use Round. - // TODO: we can do this better. - .longevity(DEFAULT_LONGEVITY) + // used to deduplicate unsigned solutions: each validator should produce one + // solution per round at most, and solutions are not propagate. + .and_provides(solution.round) + // transaction should stay in the pool for the duration of the unsigned phase. + .longevity(TryInto::::try_into( + T::UnsignedPhase::get()).unwrap_or(DEFAULT_LONGEVITY) + ) // We don't propagate this. This can never the validated at a remote node. .propagate(false) .build() @@ -381,14 +386,24 @@ where fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { if let Call::submit_unsigned(solution, _) = call { Self::unsigned_pre_dispatch_checks(solution) - // TODO error number - .map_err(|_| InvalidTransaction::Custom(99).into()) + .map_err(dispatch_error_to_invalid) + .map_err(Into::into) } else { Err(InvalidTransaction::Call.into()) } } } +/// convert a DispatchError to a custom InvalidTransaction with the inner code being the error +/// number. +fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { + let error_number = match error { + DispatchError::Module { error, .. } => error, + _ => 0, + }; + InvalidTransaction::Custom(error_number) +} + // #[cfg(test)] // mod test { // #![allow(unused_variables)] @@ -539,7 +554,7 @@ where #[cfg(test)] mod tests { use super::{mock::*, *}; - use frame_support::traits::OffchainWorker; + use frame_support::{dispatch::Dispatchable, traits::OffchainWorker}; use sp_runtime::PerU16; #[test] @@ -564,7 +579,7 @@ mod tests { ); // signed - roll_to(5); + roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Signed); matches!( ::validate_unsigned(TransactionSource::Local, &call) @@ -577,8 +592,8 @@ mod tests { ); // unsigned - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); assert!(::validate_unsigned( TransactionSource::Local, @@ -592,8 +607,8 @@ mod tests { #[test] fn validate_unsigned_retracts_low_score() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); let solution = RawSolution:: { score: [5, 0, 0], @@ -634,8 +649,8 @@ mod tests { ExtBuilder::default() .unsigned_priority(20) .build_and_execute(|| { - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); let solution = RawSolution:: { score: [5, 0, 0], @@ -663,9 +678,8 @@ mod tests { )] fn invalid_solution_panics() { ExtBuilder::default().build_and_execute(|| { - use frame_support::dispatch::Dispatchable; - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); // This is in itself an invalid BS solution.. let solution = RawSolution:: { @@ -681,8 +695,8 @@ mod tests { #[test] fn miner_works() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); // ensure we have snapshots in place. assert!(TwoPhase::snapshot().is_some()); @@ -701,7 +715,7 @@ mod tests { #[test] fn miner_trims_weight() { - + // set a proper max weight and mock weighInfo, test weight being trimmed. } #[test] @@ -718,8 +732,8 @@ mod tests { .solution_improvement_threshold(Perbill::from_percent(50)) .build_and_execute(|| { - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); assert_eq!(TwoPhase::snapshot().unwrap().desired_targets, 1); // an initial solution @@ -790,32 +804,32 @@ mod tests { fn ocw_check_prevent_duplicate() { let (mut ext, _) = ExtBuilder::default().build_offchainify(0); ext.execute_with(|| { - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); // first execution -- okay. - assert!(TwoPhase::set_check_offchain_execution_status(15).is_ok()); + assert!(TwoPhase::set_check_offchain_execution_status(25).is_ok()); // next block: rejected. - assert!(TwoPhase::set_check_offchain_execution_status(16).is_err()); + assert!(TwoPhase::set_check_offchain_execution_status(26).is_err()); // allowed after `OFFCHAIN_REPEAT` assert!( - TwoPhase::set_check_offchain_execution_status((16 + OFFCHAIN_REPEAT).into()) + TwoPhase::set_check_offchain_execution_status((26 + OFFCHAIN_REPEAT).into()) .is_ok() ); // a fork like situation: re-execute last 3. assert!(TwoPhase::set_check_offchain_execution_status( - (16 + OFFCHAIN_REPEAT - 3).into() + (26 + OFFCHAIN_REPEAT - 3).into() ) .is_err()); assert!(TwoPhase::set_check_offchain_execution_status( - (16 + OFFCHAIN_REPEAT - 2).into() + (26 + OFFCHAIN_REPEAT - 2).into() ) .is_err()); assert!(TwoPhase::set_check_offchain_execution_status( - (16 + OFFCHAIN_REPEAT - 1).into() + (26 + OFFCHAIN_REPEAT - 1).into() ) .is_err()); }) @@ -825,21 +839,23 @@ mod tests { fn ocw_only_runs_when_signed_open_now() { let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); ext.execute_with(|| { - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); + roll_to(25); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); + // we must clear the offchain storage to ensure the offchain execution check doesn't get // in the way. let mut storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); - TwoPhase::offchain_worker(14); + TwoPhase::offchain_worker(24); assert!(pool.read().transactions.len().is_zero()); storage.clear(); - TwoPhase::offchain_worker(16); + TwoPhase::offchain_worker(26); assert!(pool.read().transactions.len().is_zero()); storage.clear(); - TwoPhase::offchain_worker(15); + // submits! + TwoPhase::offchain_worker(25); assert!(!pool.read().transactions.len().is_zero()); }) } @@ -848,9 +864,9 @@ mod tests { fn ocw_can_submit_to_pool() { let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); ext.execute_with(|| { - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 15))); - TwoPhase::offchain_worker(15); + roll_to(25); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); + TwoPhase::offchain_worker(25); let encoded = pool.read().transactions[0].clone(); let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 1d133c1b613bc..01fab9a29cd5a 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -28,19 +28,24 @@ use frame_system::{RawOrigin, Module as System, Config as SystemConfig}; use frame_benchmarking::{benchmarks, account}; use frame_support::traits::{Currency, OnInitialize}; -use sp_runtime::{Perbill, traits::{Convert, StaticLookup, Saturating, UniqueSaturatedInto}}; -use sp_staking::offence::{ReportOffence, Offence, OffenceDetails}; +use sp_runtime::{ + traits::{Convert, Saturating, StaticLookup, UniqueSaturatedInto}, + Perbill, +}; +use sp_staking::offence::{Offence, OffenceDetails, ReportOffence}; -use pallet_balances::{Config as BalancesConfig}; use pallet_babe::BabeEquivocationOffence; +use pallet_balances::Config as BalancesConfig; use pallet_grandpa::{GrandpaEquivocationOffence, GrandpaTimeSlot}; use pallet_im_online::{Config as ImOnlineConfig, Module as ImOnline, UnresponsivenessOffence}; use pallet_offences::{Config as OffencesConfig, Module as Offences}; -use pallet_session::historical::{Config as HistoricalConfig, IdentificationTuple}; -use pallet_session::{Config as SessionConfig, SessionManager}; +use pallet_session::{ + historical::{Config as HistoricalConfig, IdentificationTuple}, + Config as SessionConfig, SessionManager, +}; use pallet_staking::{ - Module as Staking, Config as StakingConfig, RewardDestination, ValidatorPrefs, - Exposure, IndividualExposure, ElectionStatus, MAX_NOMINATIONS, Event as StakingEvent + Config as StakingConfig, Event as StakingEvent, Exposure, IndividualExposure, + Module as Staking, RewardDestination, ValidatorPrefs, MAX_NOMINATIONS, }; const SEED: u32 = 0; @@ -359,7 +364,7 @@ benchmarks! { let o = 10; let n = 100; - Staking::::put_election_status(ElectionStatus::Closed); + // Staking::::put_election_status(ElectionStatus::Closed); let mut deferred_offences = vec![]; let offenders = make_offenders::(o, n)?.0; From a7c48410224d842fe4b522e5059046448d4cf121 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 9 Dec 2020 14:05:38 +0000 Subject: [PATCH 21/62] Some Staking stuff left to do. --- Cargo.lock | 1 - bin/node/runtime/src/lib.rs | 4 +- client/executor/src/integration_tests/mod.rs | 2 - frame/babe/src/lib.rs | 10 +- frame/election-providers/Cargo.toml | 7 +- .../src/two_phase/benchmarking.rs | 116 +++++++++++--- frame/election-providers/src/two_phase/mod.rs | 56 ++++--- .../src/two_phase/signed.rs | 150 +++++++++++++----- .../src/two_phase/unsigned.rs | 1 - frame/session/src/lib.rs | 29 ++-- frame/staking/Cargo.toml | 2 +- frame/staking/src/lib.rs | 49 +++++- frame/staking/src/mock.rs | 18 ++- frame/staking/src/tests.rs | 66 +++++++- primitives/election-providers/src/lib.rs | 2 +- 15 files changed, 392 insertions(+), 121 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 872b326ba294d..625fedca784a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1576,7 +1576,6 @@ dependencies = [ "parking_lot 0.10.2", "paste 1.0.3", "rand 0.7.3", - "rand_chacha 0.2.2", "serde", "sp-arithmetic", "sp-core", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 060429ae0ec89..9f9ecbd831202 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -471,8 +471,8 @@ impl pallet_staking::Config for Runtime { } parameter_types! { - pub const SignedPhase: u32 = 50; - pub const UnsignedPhase: u32 = 50; + pub const SignedPhase: u32 = 25; + pub const UnsignedPhase: u32 = 25; pub const MaxSignedSubmissions: u32 = 10; pub const SignedRewardBase: Balance = 1 * DOLLARS; pub const SignedDepositBase: Balance = 1 * DOLLARS; diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index d41784f5aa067..afb4a9740e829 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -763,7 +763,6 @@ fn spawning_runtime_instance_nested_should_work(wasm_method: WasmExecutionMethod #[test_case(WasmExecutionMethod::Interpreted)] #[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))] fn panic_in_spawned_instance_panics_on_joining_its_result(wasm_method: WasmExecutionMethod) { - let mut ext = TestExternalities::default(); let mut ext = ext.ext(); @@ -774,6 +773,5 @@ fn panic_in_spawned_instance_panics_on_joining_its_result(wasm_method: WasmExecu &mut ext, ).unwrap_err(); - dbg!(&error_result); assert!(format!("{}", error_result).contains("Spawned task")); } diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index a61f1244cbebd..9c229c297e498 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -407,12 +407,12 @@ impl Module { /// In other word, this is only accurate if no slots are missed. Given missed slots, the slot /// number will grow while the block number will not. Hence, the result can be interpreted as an /// upper bound. - // -------------- IMPORTANT NOTE -------------- - // This implementation is linked to how [`should_epoch_change`] is working. This might need to - // be updated accordingly, if the underlying mechanics of slot and epochs change. + // -------------- IMPORTANT NOTE -------------- This implementation is linked to how + // [`should_epoch_change`] is working. This might need to be updated accordingly, if the + // underlying mechanics of slot and epochs change. // - // WEIGHT NOTE: This function is tied to the weight of `EstimateNextSessionRotation`. If you update - // this function, you must also update the corresponding weight. + // WEIGHT NOTE: This function is tied to the weight of `EstimateNextSessionRotation`. If you + // update this function, you must also update the corresponding weight. pub fn next_expected_epoch_change(now: T::BlockNumber) -> Option { let next_slot = Self::current_epoch_start().saturating_add(T::EpochDuration::get()); next_slot diff --git a/frame/election-providers/Cargo.toml b/frame/election-providers/Cargo.toml index ebe0be8eb3094..a8f24be771cae 100644 --- a/frame/election-providers/Cargo.toml +++ b/frame/election-providers/Cargo.toml @@ -29,8 +29,7 @@ sp-election-providers = { version = "2.0.0", default-features = false, path = ". # Optional imports for benchmarking frame-benchmarking = { version = "2.0.0", default-features = false, path = "../benchmarking", optional = true } -rand_chacha = { version = "0.2", default-features = false, optional = true } -rand = { version = "0.7.3", optional = true } +rand = { version = "0.7.3", default-features = false, optional = true, features = ["alloc", "small_rng"] } [dev-dependencies] sp-io = { version = "2.0.0", path = "../../primitives/io" } @@ -42,9 +41,6 @@ substrate-test-utils = { version = "2.0.0", path = "../../test-utils" } parking_lot = "0.10.2" sp-tracing = { version = "2.0.0", path = "../../primitives/tracing" } -frame-benchmarking = { version = "2.0.0", path = "../benchmarking" } -rand_chacha = { version = "0.2" } -rand = "0.7.3" [features] default = ["std"] @@ -64,6 +60,5 @@ std = [ ] runtime-benchmarks = [ "frame-benchmarking", - "rand_chacha", "rand", ] diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index b3e75d55b5f7c..34e2b782d657b 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -21,14 +21,18 @@ use super::*; use crate::two_phase::{Module as TwoPhase}; pub use frame_benchmarking::{account, benchmarks, whitelist_account, whitelisted_caller}; -use frame_support::assert_ok; +use frame_support::{assert_ok, traits::OnInitialize}; use frame_system::RawOrigin; -use rand::{seq::SliceRandom, thread_rng}; +use rand::{prelude::SliceRandom, rngs::SmallRng, SeedableRng}; use sp_npos_elections::ExtendedBalance; use sp_runtime::InnerOf; use sp_std::convert::TryInto; const SEED: u32 = 0; +// const DEFAULT_VOTERS: u32 = 1000; +// const DEFAULT_TARGETS: u32 = 500; +// const DEFAULT_DESIRED: u32 = 200; +// const DEFAULT_ACTIVE_VOTERS: u32 = 500; /// Creates a **valid** solution with exactly the given size. /// @@ -58,7 +62,7 @@ where .map(|i| account("Targets", i, SEED)) .collect(); - let mut rng = thread_rng(); + let mut rng = SmallRng::seed_from_u64(999u64); // decide who are the winners. let winners = targets @@ -150,29 +154,84 @@ benchmarks! { } _{} + on_initialize_nothing { + assert!(>::current_phase().is_off()); + }: { + >::on_initialize(1u32.into()); + } verify { + assert!(>::current_phase().is_off()); + } + + on_initialize_open_signed_phase { + assert!(>::snapshot().is_none()); + assert!(>::current_phase().is_off()); + let next_election = T::ElectionDataProvider::next_election_prediction(1u32.into()); + + let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); + let unsigned_deadline = T::UnsignedPhase::get(); + }: { + >::on_initialize(next_election - signed_deadline + 1u32.into()); + } verify { + assert!(>::snapshot().is_some()); + assert!(>::current_phase().is_signed()); + } + + finalize_signed_phase_accept_solution { + let receiver = account("receiver", 0, SEED); + T::Currency::make_free_balance_be(&receiver, 100u32.into()); + let ready: ReadySolution = Default::default(); + let deposit: BalanceOf = 10u32.into(); + let reward: BalanceOf = 20u32.into(); + + assert_ok!(T::Currency::reserve(&receiver, deposit)); + assert_eq!(T::Currency::free_balance(&receiver), 90u32.into()); + }: { + >::finalize_signed_phase_accept_solution(ready, &receiver, deposit, reward) + } verify { + assert_eq!(T::Currency::free_balance(&receiver), 120u32.into()); + assert_eq!(T::Currency::reserved_balance(&receiver), 0u32.into()); + } + + finalize_signed_phase_reject_solution { + let receiver = account("receiver", 0, SEED); + let deposit: BalanceOf = 10u32.into(); + T::Currency::make_free_balance_be(&receiver, 100u32.into()); + assert_ok!(T::Currency::reserve(&receiver, deposit)); + + assert_eq!(T::Currency::free_balance(&receiver), 90u32.into()); + assert_eq!(T::Currency::reserved_balance(&receiver), 10u32.into()); + }: { + >::finalize_signed_phase_reject_solution(&receiver, deposit) + } verify { + assert_eq!(T::Currency::free_balance(&receiver), 90u32.into()); + assert_eq!(T::Currency::reserved_balance(&receiver), 0u32.into()); + } + submit { - // number of votes in snapshot. - let v in 2000 .. 3000; - // number of targets in snapshot. - let t in 500 .. 800; - // number of assignments, i.e. compact.len(). This means the active nominators, thus must be - // a subset of `v` component. - let a in 500 .. 1500; - // number of desired targets. Must be a subset of `t` component. - let d in 200 .. 400; + let c in 1 .. (T::MaxSignedSubmissions::get() - 1); - let witness = WitnessData { voters: v, targets: t }; - let raw_solution = solution_with_size::(witness, a, d); + // the solution will be worse than all of them meaning the score need to be checked against all. + let solution = RawSolution { score: [(1000_0000u128 - 1).into(), 0, 0], ..Default::default() }; - assert!(>::signed_submissions().len() == 0); >::put(Phase::Signed); + ::put(1); + + for i in 0..c { + >::mutate(|queue| { + let solution = RawSolution { score: [(1000_0000 + i).into(), 0, 0], ..Default::default() }; + let signed_submission = SignedSubmission { solution, ..Default::default() }; + // note: this is quite tricky: we know that the queue will stay sorted here. The + // last will be best. + queue.push(signed_submission); + }) + } let caller = frame_benchmarking::whitelisted_caller(); T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance() * 10u32.into()); - }: _(RawOrigin::Signed(caller), raw_solution) + }: _(RawOrigin::Signed(caller), solution, c) verify { - assert!(>::signed_submissions().len() == 1); + assert!(>::signed_submissions().len() as u32 == c + 1); } submit_unsigned { @@ -196,9 +255,6 @@ benchmarks! { assert!(>::queued_solution().is_some()); } - open_signed_phase {}: {} verify {} - close_signed_phase {}: {} verify {} - // This is checking a valid solution. The worse case is indeed a valid solution. feasibility_check { // number of voters in snapshot. @@ -239,5 +295,25 @@ mod test { ExtBuilder::default().build_and_execute(|| { assert_ok!(test_benchmark_submit::()); }); + + ExtBuilder::default().build_and_execute(|| { + assert_ok!(test_benchmark_on_initialize_open_signed_phase::()); + }); + + ExtBuilder::default().build_and_execute(|| { + assert_ok!(test_benchmark_on_initialize_nothing::()); + }); + + ExtBuilder::default().build_and_execute(|| { + assert_ok!(test_benchmark_finalize_signed_phase_accept_solution::< + Runtime, + >()); + }); + + ExtBuilder::default().build_and_execute(|| { + assert_ok!(test_benchmark_finalize_signed_phase_reject_solution::< + Runtime, + >()); + }); } } diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index f744324e27614..1ff9bed7dd434 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -155,7 +155,7 @@ use sp_runtime::{ }; use sp_std::prelude::*; -#[cfg(feature = "runtime-benchmarks")] +#[cfg(any(feature = "runtime-benchmarks", test))] mod benchmarking; #[cfg(test)] mod mock; @@ -275,7 +275,7 @@ impl Default for RawSolution { /// A raw, unchecked signed submission. /// /// This is just a wrapper around [`RawSolution`] and some additional info. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] pub struct SignedSubmission { /// Who submitted this solution. who: A, @@ -400,28 +400,35 @@ impl From for FeasibilityError { } pub trait WeightInfo { - fn open_signed_phase() -> Weight; - fn open_unsigned_phase() -> Weight; + fn on_initialize_open_signed_phase() -> Weight; + fn on_initialize_open_unsigned_phase() -> Weight; + fn finalize_signed_phase_accept_solution() -> Weight; + fn finalize_signed_phase_reject_solution() -> Weight; fn feasibility_check(v: u32, t: u32, a: u32, d: u32) -> Weight; - fn submit(v: u32, t: u32, a: u32, d: u32) -> Weight; + fn submit(c: u32) -> Weight; fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight; } - impl WeightInfo for () { fn feasibility_check(_: u32, _: u32, _: u32, _: u32) -> Weight { Default::default() } - fn submit(_: u32, _: u32, _: u32, _: u32) -> Weight { + fn submit(_: u32) -> Weight { Default::default() } fn submit_unsigned(_: u32, _: u32, _: u32, _: u32) -> Weight { Default::default() } - fn open_signed_phase() -> Weight { + fn on_initialize_open_signed_phase() -> Weight { + Default::default() + } + fn on_initialize_open_unsigned_phase() -> Weight { Default::default() } - fn open_unsigned_phase() -> Weight { + fn finalize_signed_phase_accept_solution() -> Weight { + Default::default() + } + fn finalize_signed_phase_reject_solution() -> Weight { Default::default() } } @@ -549,22 +556,26 @@ decl_module! { let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); let unsigned_deadline = T::UnsignedPhase::get(); + sp_std::if_std! { + dbg!(now, next_election, signed_deadline, unsigned_deadline); + } let remaining = next_election - now; match Self::current_phase() { Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { - // signed phae can only start after Off. + // signed phase can only start after Off. >::put(Phase::Signed); Round::mutate(|r| *r +=1); Self::start_signed_phase(); log!(info, "Starting signed phase at #{:?} , round {}.", now, Self::round()); - T::WeightInfo::open_signed_phase() + T::WeightInfo::on_initialize_open_signed_phase() }, Phase::Signed | Phase::Off if remaining <= unsigned_deadline && remaining > 0u32.into() => { // unsigned phase can start after Off or Signed. let _ = Self::finalize_signed_phase(); + // for now always start the unsigned phase. >::put(Phase::Unsigned((true, now))); log!(info, "Starting unsigned phase at #{:?}.", now); - T::WeightInfo::open_unsigned_phase() + T::WeightInfo::on_initialize_open_unsigned_phase() }, _ => { Zero::zero() @@ -593,10 +604,17 @@ decl_module! { /// /// A deposit is reserved and recorded for the solution. Based on the outcome, the solution /// might be rewarded, slashed, or get all or a part of the deposit back. - #[weight = T::WeightInfo::submit(0, 0, 0, 0)] - fn submit(origin, solution: RawSolution>) -> DispatchResultWithPostInfo { + /// + /// # + /// Queue size must be provided as witness data. + /// # + #[weight = T::WeightInfo::submit(*witness_data)] + fn submit(origin, solution: RawSolution>, witness_data: u32) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; + // ensure witness data is correct. + ensure!(witness_data == >::decode_len().unwrap_or_default() as u32, PalletError::::InvalidWitness); + // ensure solution is timely. ensure!(Self::current_phase().is_signed(), PalletError::::EarlySubmission); @@ -606,7 +624,7 @@ decl_module! { // NOTE: this is the only case where having separate snapshot would have been better // because could do just decode_len. But we can create abstractions to do this. - // build witness. + // build witness. Note: this is not needed for weight calc, thus not input. // defensive-only: if phase is signed, snapshot will exist. let RoundSnapshot { voters, targets, .. } = Self::snapshot().unwrap_or_default(); let witness = WitnessData { voters: voters.len() as u32, targets: targets.len() as u32 }; @@ -658,6 +676,7 @@ decl_module! { let _ = Self::unsigned_pre_dispatch_checks(&solution)?; // ensure witness was correct. + // TODO: probably split these again.. let RoundSnapshot { voters, targets, .. } = Self::snapshot().unwrap_or_default(); ensure!(voters.len() as u32 == witness.voters, PalletError::::InvalidWitness); ensure!(targets.len() as u32 == witness.targets, PalletError::::InvalidWitness); @@ -855,9 +874,9 @@ mod tests { #[test] fn phase_rotation_works() { ExtBuilder::default().build_and_execute(|| { - // 0 ------- 15 -------------- 25 ------- 30 ------- ------- 45 ------- 55 ------- 60 - // | | - // Signed Unsigned + // 0 ------- 15 ------- 25 ------- 30 ------- ------- 45 ------- 55 ------- 60 + // | | | | + // Signed Unsigned Signed Unsigned assert_eq!(System::block_number(), 0); assert_eq!(TwoPhase::current_phase(), Phase::Off); @@ -959,7 +978,6 @@ mod tests { assert!(TwoPhase::current_phase().is_off()); roll_to(20); - dbg!(TwoPhase::current_phase()); assert!(TwoPhase::current_phase().is_unsigned_open_at(20)); roll_to(30); diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index c7d097a2785f6..9cb2e073e5e99 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -56,6 +56,7 @@ where pub fn finalize_signed_phase() -> bool { let mut all_submission: Vec> = >::take(); let mut found_solution = false; + let mut weight = T::DbWeight::get().reads(1); while let Some(best) = all_submission.pop() { let SignedSubmission { @@ -64,27 +65,40 @@ where deposit, reward, } = best; + let active_voters = solution.compact.voters_count() as u32; match Self::feasibility_check(solution, ElectionCompute::Signed) { Ok(ready_solution) => { - // write this ready solution. - >::put(ready_solution); - - // unreserve deposit. - let _remaining = T::Currency::unreserve(&who, deposit); - debug_assert!(_remaining.is_zero()); + Self::finalize_signed_phase_accept_solution( + ready_solution, + &who, + deposit, + reward, + ); + found_solution = true; - // Reward. - let positive_imbalance = T::Currency::deposit_creating(&who, reward); - T::RewardHandler::on_unbalanced(positive_imbalance); + let feasibility_weight = { + // TODO: might be easier to just store the weight in `SignedSubmission`? + let RoundSnapshot { + voters, + targets, + desired_targets, + } = Self::snapshot().unwrap_or_default(); + let v = voters.len() as u32; + let t = targets.len() as u32; + let a = active_voters; + let w = desired_targets; + T::WeightInfo::feasibility_check(v, t, a, w) + }; - found_solution = true; + weight = weight.saturating_add(feasibility_weight); + weight = weight + .saturating_add(T::WeightInfo::finalize_signed_phase_accept_solution()); break; } Err(_) => { - let (negative_imbalance, _remaining) = - T::Currency::slash_reserved(&who, deposit); - debug_assert!(_remaining.is_zero()); - T::SlashHandler::on_unbalanced(negative_imbalance); + Self::finalize_signed_phase_reject_solution(&who, deposit); + weight = weight + .saturating_add(T::WeightInfo::finalize_signed_phase_reject_solution()); } } } @@ -94,12 +108,47 @@ where all_submission.into_iter().for_each(|not_processed| { let SignedSubmission { who, deposit, .. } = not_processed; let _remaining = T::Currency::unreserve(&who, deposit); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); debug_assert!(_remaining.is_zero()); }); found_solution } + /// Helper function for the case where a solution is accepted in the signed phase. + /// + /// Extracted to facilitate with weight calculation. + /// + /// Infallible + pub fn finalize_signed_phase_accept_solution( + ready_solution: ReadySolution, + who: &T::AccountId, + deposit: BalanceOf, + reward: BalanceOf, + ) { + // write this ready solution. + >::put(ready_solution); + + // unreserve deposit. + let _remaining = T::Currency::unreserve(who, deposit); + debug_assert!(_remaining.is_zero()); + + // Reward. + let positive_imbalance = T::Currency::deposit_creating(who, reward); + T::RewardHandler::on_unbalanced(positive_imbalance); + } + + /// Helper function for the case where a solution is accepted in the rejected phase. + /// + /// Extracted to facilitate with weight calculation. + /// + /// Infallible + pub fn finalize_signed_phase_reject_solution(who: &T::AccountId, deposit: BalanceOf) { + let (negative_imbalance, _remaining) = T::Currency::slash_reserved(who, deposit); + debug_assert!(_remaining.is_zero()); + T::SlashHandler::on_unbalanced(negative_imbalance); + } + /// Find a proper position in the queue for the signed queue, whilst maintaining the order of /// solution quality. If insertion was successful, `Some(index)` is returned where index is the /// index of the newly inserted item. @@ -222,6 +271,18 @@ where #[cfg(test)] mod tests { use super::{mock::*, *}; + use frame_support::dispatch::DispatchResultWithPostInfo; + + fn submit_with_witness( + origin: Origin, + solution: RawSolution>, + ) -> DispatchResultWithPostInfo { + TwoPhase::submit( + origin, + solution, + TwoPhase::signed_submissions().len() as u32, + ) + } #[test] fn cannot_submit_too_early() { @@ -234,12 +295,15 @@ mod tests { let solution = raw_solution(); assert_noop!( - TwoPhase::submit(Origin::signed(10), solution), + submit_with_witness(Origin::signed(10), solution), PalletError::::EarlySubmission, ); }) } + #[test] + fn wrong_witness_fails() {} + #[test] fn should_pay_deposit() { ExtBuilder::default().build_and_execute(|| { @@ -249,7 +313,7 @@ mod tests { let solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(balances(&99), (95, 5)); assert_eq!(TwoPhase::signed_submissions().first().unwrap().deposit, 5); @@ -265,7 +329,7 @@ mod tests { let solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(balances(&99), (95, 5)); assert!(TwoPhase::finalize_signed_phase()); @@ -285,7 +349,7 @@ mod tests { assert_eq!(solution.score[0], 40); assert_eq!(balances(&99), (100, 0)); - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(balances(&99), (95, 5)); assert!(TwoPhase::finalize_signed_phase()); @@ -303,7 +367,7 @@ mod tests { assert_eq!(solution.score[0], 40); assert_eq!(balances(&99), (100, 0)); - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(balances(&99), (95, 5)); assert!(TwoPhase::finalize_signed_phase()); @@ -324,7 +388,7 @@ mod tests { // make the solution invalid. solution.score[0] += 1; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(balances(&99), (95, 5)); // no good solution was stored. @@ -345,11 +409,11 @@ mod tests { assert_eq!(balances(&999), (100, 0)); // submit as correct. - assert_ok!(TwoPhase::submit(Origin::signed(99), solution.clone())); + assert_ok!(submit_with_witness(Origin::signed(99), solution.clone())); // make the solution invalid and weaker. solution.score[0] -= 1; - assert_ok!(TwoPhase::submit(Origin::signed(999), solution)); + assert_ok!(submit_with_witness(Origin::signed(999), solution)); assert_eq!(balances(&99), (95, 5)); assert_eq!(balances(&999), (95, 5)); @@ -375,7 +439,7 @@ mod tests { score: [(5 + s).into(), 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); } // weaker. @@ -385,7 +449,7 @@ mod tests { }; assert_noop!( - TwoPhase::submit(Origin::signed(99), solution), + submit_with_witness(Origin::signed(99), solution), PalletError::::QueueFull, ); }) @@ -403,7 +467,7 @@ mod tests { score: [(5 + s).into(), 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); } assert_eq!( @@ -419,7 +483,7 @@ mod tests { score: [20, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); // the one with score 5 was rejected, the new one inserted. assert_eq!( @@ -444,14 +508,14 @@ mod tests { score: [(5 + s).into(), 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); } let solution = RawSolution { score: [4, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!( TwoPhase::signed_submissions() @@ -466,7 +530,7 @@ mod tests { score: [5, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); // the one with score 5 was rejected, the new one inserted. assert_eq!( @@ -493,7 +557,7 @@ mod tests { score: [(5 + s).into(), 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); } assert_eq!(balances(&99).1, 2 * 5); @@ -504,7 +568,7 @@ mod tests { score: [20, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(999), solution)); + assert_ok!(submit_with_witness(Origin::signed(999), solution)); // got one bond back. assert_eq!(balances(&99).1, 2 * 4); @@ -525,7 +589,7 @@ mod tests { score: [(5 + i).into(), 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); } assert_eq!( TwoPhase::signed_submissions() @@ -541,7 +605,7 @@ mod tests { ..Default::default() }; assert_noop!( - TwoPhase::submit(Origin::signed(99), solution), + submit_with_witness(Origin::signed(99), solution), PalletError::::QueueFull, ); }) @@ -564,49 +628,49 @@ mod tests { score: [5, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(scores(), vec![5]); let solution = RawSolution { score: [8, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(scores(), vec![5, 8]); let solution = RawSolution { score: [3, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(scores(), vec![3, 5, 8]); let solution = RawSolution { score: [6, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(scores(), vec![5, 6, 8]); let solution = RawSolution { score: [6, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(scores(), vec![6, 6, 8]); let solution = RawSolution { score: [10, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(scores(), vec![6, 8, 10]); let solution = RawSolution { score: [12, 0, 0], ..Default::default() }; - assert_ok!(TwoPhase::submit(Origin::signed(99), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(scores(), vec![8, 10, 12]); }) } @@ -627,15 +691,15 @@ mod tests { let mut solution = raw_solution(); // submit a correct one. - assert_ok!(TwoPhase::submit(Origin::signed(99), solution.clone())); + assert_ok!(submit_with_witness(Origin::signed(99), solution.clone())); // make the solution invalidly better and submit. This ought to be slashed. solution.score[0] += 1; - assert_ok!(TwoPhase::submit(Origin::signed(999), solution.clone())); + assert_ok!(submit_with_witness(Origin::signed(999), solution.clone())); // make the solution invalidly worse and submit. This ought to be suppressed and returned. solution.score[0] -= 1; - assert_ok!(TwoPhase::submit(Origin::signed(9999), solution)); + assert_ok!(submit_with_witness(Origin::signed(9999), solution)); assert_eq!( TwoPhase::signed_submissions() diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 7c65034d0cde2..cc2e1e04c4bf5 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -704,7 +704,6 @@ mod tests { // mine seq_phragmen solution with 2 iters. let (solution, witness) = TwoPhase::mine_solution(2).unwrap(); - dbg!(&solution); // ensure this solution is valid. assert!(TwoPhase::queued_solution().is_none()); diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 40ae5bed83e49..4500ea93a48bb 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -152,21 +152,30 @@ impl< } impl< - BlockNumber: Rem + Sub + Zero + PartialOrd + Saturating + Clone, - Period: Get, - Offset: Get, -> EstimateNextSessionRotation for PeriodicSessions { + BlockNumber: Rem + + Sub + + Zero + + PartialOrd + + Saturating + + Clone + + From // TODO: remove these + + sp_std::fmt::Debug, + Period: Get, + Offset: Get, + > EstimateNextSessionRotation for PeriodicSessions +{ fn estimate_next_session_rotation(now: BlockNumber) -> Option { let offset = Offset::get(); let period = Period::get(); Some(if now > offset { - let block_after_last_session = (now.clone() - offset) % period.clone(); + let block_after_last_session = (now.clone() - offset.clone()) % period.clone(); if block_after_last_session > Zero::zero() { now.saturating_add( period.saturating_sub(block_after_last_session) ) } else { - Zero::zero() + // TODO: fix this in master. + now + period + offset } } else { offset @@ -174,10 +183,10 @@ impl< } fn weight(_now: BlockNumber) -> Weight { - // Weight note: `estimate_next_session_rotation` has no storage reads and trivial computational overhead. - // There should be no risk to the chain having this weight value be zero for now. - // However, this value of zero was not properly calculated, and so it would be reasonable - // to come back here and properly calculate the weight of this function. + // Weight note: `estimate_next_session_rotation` has no storage reads and trivial + // computational overhead. There should be no risk to the chain having this weight value be + // zero for now. However, this value of zero was not properly calculated, and so it would be + // reasonable to come back here and properly calculate the weight of this function. 0 } } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 44fafa723a1fb..7ade07dfc4fa3 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -39,7 +39,7 @@ sp-storage = { version = "2.0.0", path = "../../primitives/storage" } sp-tracing = { version = "2.0.0", path = "../../primitives/tracing" } pallet-balances = { version = "2.0.0", path = "../balances" } pallet-timestamp = { version = "2.0.0", path = "../timestamp" } -frame-election-providers = { version = "2.0.0", default-features = false, path = "../election-providers" } +frame-election-providers = { version = "2.0.0", path = "../election-providers" } pallet-staking-reward-curve = { version = "2.0.0", path = "../staking/reward-curve" } substrate-test-utils = { version = "2.0.0", path = "../../test-utils" } frame-benchmarking = { version = "2.0.0", path = "../benchmarking" } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 43ace46fa344d..25e6a00c82529 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -696,6 +696,8 @@ pub trait SessionInterface: frame_system::Config { fn validators() -> Vec; /// Prune historical session tries up to but not including the given index. fn prune_historical_up_to(up_to: SessionIndex); + /// The current session index. + fn current_index() -> SessionIndex; } impl SessionInterface<::AccountId> for T @@ -720,6 +722,10 @@ where >::validators() } + fn current_index() -> SessionIndex { + >::current_index() + } + fn prune_historical_up_to(up_to: SessionIndex) { >::prune_up_to(up_to); } @@ -1993,7 +1999,7 @@ impl Module { } } - /// Plan a new session potentially trigger a new era. + /// Plan a new session, potentially trigger a new era. fn new_session(session_index: SessionIndex) -> Option> { if let Some(current_era) = Self::current_era() { // Initial era has been set. @@ -2127,6 +2133,7 @@ impl Module { *s = Some(s.map(|s| s + 1).unwrap_or(0)); s.unwrap() }); + println!("❌ ErasStartSessionIndex::insert({}, {});", current_era, start_session_index); ErasStartSessionIndex::insert(¤t_era, &start_session_index); // Clean old era information. @@ -2421,10 +2428,6 @@ impl ElectionDataProvider for Module Self::validator_count() } - fn next_election_prediction(now: T::BlockNumber) -> T::BlockNumber { - T::NextNewSession::estimate_next_new_session(now).unwrap_or_default() - } - fn voters() -> Vec<(T::AccountId, VoteWeight, Vec)> { Self::get_npos_voters() } @@ -2433,6 +2436,42 @@ impl ElectionDataProvider for Module Self::get_npos_targets() } + fn next_election_prediction(now: T::BlockNumber) -> T::BlockNumber { + let current_era = Self::current_era().unwrap_or(0); + // Note: this happens after the on_initialize of the session module, therefore, this is the + // updated session index in the border cases. + let session_index = T::SessionInterface::current_index(); + let current_era_start_session_index = + Self::eras_start_session_index(current_era).unwrap_or(0); + let era_length = session_index + .saturating_sub(current_era_start_session_index) + .min(T::SessionsPerEra::get()); + // TODO: this is probably an ugly hack here and can be re-done. + // TODO: cases to consider: session length = 1, session length > 1, + let session_length = T::NextNewSession::estimate_next_new_session(1u32.into()) + .unwrap_or(0u32.into()) + .max(1u32.into()); + + let this_session_end = T::NextNewSession::estimate_next_new_session(now) + .unwrap_or_default(); + let sessions_left: T::BlockNumber = T::SessionsPerEra::get() + .saturating_sub(era_length) + .saturating_sub(1) // one session is computed in this_session_end. + .into(); + + dbg!( + now, + session_index, + current_era_start_session_index, + era_length, + T::NextNewSession::estimate_next_new_session(now).unwrap(), + this_session_end, + sessions_left, + session_length, + ); + this_session_end.saturating_add(sessions_left.saturating_mul(session_length)) + } + fn feasibility_check_assignment( _who: &T::AccountId, _distribution: &[(T::AccountId, P)], diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 999c92e6d3bcd..f2abf29a81a53 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -695,6 +695,18 @@ pub(crate) fn add_slash(who: &AccountId) { ); } +pub(crate) fn run_to_block(n: BlockNumber) { + Staking::on_finalize(System::block_number()); + for b in System::block_number() + 1..=n { + System::set_block_number(b); + Session::on_initialize(b); + Staking::on_initialize(b); + if b != n { + Staking::on_finalize(System::block_number()); + } + } +} + // // winners will be chosen by simply their unweighted total backing stake. Nominator stake is // // distributed evenly. // pub(crate) fn horrible_npos_solution( @@ -914,10 +926,10 @@ macro_rules! assert_session_era { $session, ); assert_eq!( - Staking::active_era().unwrap().index, + Staking::current_era().unwrap(), $era, - "wrong active era {} != {}", - Staking::active_era().unwrap().index, + "wrong current era {} != {}", + Staking::current_era().unwrap(), $era, ); }; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index d9f6598f12ed3..20f5f8bc13e8f 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4421,8 +4421,6 @@ fn test_payout_stakers() { bond_nominator(1000 + i, 100 + i, balance + i as Balance, vec![11]); } - dbg!("HERE"); - mock::start_era(1); Staking::reward_by_ids(vec![(11, 1)]); // Compute total payout now for whole duration as other parameter won't change @@ -4710,3 +4708,67 @@ fn payout_to_any_account_works() { assert!(Balances::free_balance(42) > 0); }) } + +mod election_provider { + use super::*; + + #[test] + fn estimate_next_election_works() { + ExtBuilder::default() + .session_per_era(5) + .session_length(5) + .build() + .execute_with(|| { + // TODO: prediction for the first session is incorrect. correct is 20 because of + // first session having zero length + assert_session_era!(0, 0); + assert_eq!( + Staking::next_election_prediction(System::block_number()), + 25 + ); + + run_to_block(4); + assert_session_era!(0, 0); + assert_eq!( + Staking::next_election_prediction(System::block_number()), + 25 + ); + + run_to_block(19); + assert_session_era!(3, 0); + assert_eq!( + Staking::next_election_prediction(System::block_number()), + 25 + ); + + run_to_block(20); + assert_session_era!(4, 1); + assert_eq!( + Staking::next_election_prediction(System::block_number()), + 45 + ); + + run_to_block(21); + assert_session_era!(4, 1); + assert_eq!( + Staking::next_election_prediction(System::block_number()), + 45 + ); + + // run_to_block(25); + // assert_eq!(System::block_number(), 25); + // assert_session_era!(5, 1); + // assert_eq!( + // Staking::next_election_prediction(System::block_number()), + // 45 + // ); + + run_to_block(32); + assert_session_era!(6, 1); + assert_eq!( + Staking::next_election_prediction(System::block_number()), + 45 + ); + }) + } +} diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index ab14fc67d40ba..446f6e8fce488 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -91,7 +91,7 @@ pub trait ElectionDataProvider { /// Something that can compute the result of an election and pass it back to the caller. pub trait ElectionProvider { /// Indicate weather this election provider needs data when calling [`elect`] or not. If - /// `false`, then the call site can ignore all parameters of [`elect`] + /// `false`, then the call site can ignore all parameters of [`elect`]. const NEEDS_ELECT_DATA: bool; /// The error type that is returned by the provider. From 492289773b4564ce5c8869aade7f75f28652d6e4 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 15 Dec 2020 10:36:20 +0000 Subject: [PATCH 22/62] Split the snapshot; type for CompactSolution and MaxNominations --- Cargo.lock | 1 + bin/node/runtime/Cargo.toml | 2 + bin/node/runtime/src/lib.rs | 76 +++++---- .../src/two_phase/benchmarking.rs | 6 +- .../src/two_phase/macros.rs | 42 ++--- .../election-providers/src/two_phase/mock.rs | 5 +- frame/election-providers/src/two_phase/mod.rs | 148 ++++++++++++------ .../src/two_phase/signed.rs | 54 ++++--- .../src/two_phase/unsigned.rs | 18 +-- frame/staking/src/benchmarking.rs | 20 +-- frame/staking/src/lib.rs | 70 +++------ frame/staking/src/mock.rs | 2 + frame/staking/src/tests.rs | 127 +++++++-------- primitives/election-providers/src/lib.rs | 10 +- primitives/npos-elections/src/lib.rs | 7 + 15 files changed, 314 insertions(+), 274 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a83142f31ade..49509afa17257 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4006,6 +4006,7 @@ dependencies = [ "sp-inherents", "sp-io", "sp-keyring", + "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-session", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 09c95f49fea2a..a2eef4594564e 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -35,6 +35,7 @@ sp-keyring = { version = "2.0.0", optional = true, path = "../../../primitives/k sp-session = { version = "2.0.0", default-features = false, path = "../../../primitives/session" } sp-transaction-pool = { version = "2.0.0", default-features = false, path = "../../../primitives/transaction-pool" } sp-version = { version = "2.0.0", default-features = false, path = "../../../primitives/version" } +sp-npos-elections = { version = "2.0.0", default-features = false, path = "../../../primitives/npos-elections" } # frame dependencies frame-executive = { version = "2.0.0", default-features = false, path = "../../../frame/executive" } @@ -111,6 +112,7 @@ std = [ "pallet-im-online/std", "pallet-indices/std", "sp-inherents/std", + "sp-npos-elections/std", "pallet-membership/std", "pallet-mmr/std", "pallet-multisig/std", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index f122e50189d9f..1600af453d8bf 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -22,54 +22,56 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit = "256"] - -use sp_std::prelude::*; +use codec::{Decode, Encode}; use frame_support::{ - construct_runtime, parameter_types, debug, RuntimeDebug, - weights::{ - Weight, IdentityFee, - constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, DispatchClass, - }, + construct_runtime, debug, parameter_types, traits::{ - Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness, LockIdentifier, - U128CurrencyToVote, + Currency, Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, OnUnbalanced, + Randomness, U128CurrencyToVote, }, + weights::{ + constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, + DispatchClass, IdentityFee, Weight, + }, + RuntimeDebug, }; use frame_system::{ - EnsureRoot, EnsureOneOf, - limits::{BlockWeights, BlockLength} + limits::{BlockLength, BlockWeights}, + EnsureOneOf, EnsureRoot, +}; +pub use node_primitives::{AccountId, Signature}; +use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment}; +use pallet_grandpa::{ + fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, }; -use frame_support::traits::InstanceFilter; -use codec::{Encode, Decode}; +use pallet_im_online::sr25519::AuthorityId as ImOnlineId; +use pallet_session::historical as pallet_session_historical; +pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment}; +use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; +use sp_api::impl_runtime_apis; +use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_core::{ crypto::KeyTypeId, u32_trait::{_1, _2, _3, _4, _5}, OpaqueMetadata, }; -pub use node_primitives::{AccountId, Signature}; -use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment}; -use sp_api::impl_runtime_apis; +use sp_inherents::{CheckInherentsResult, InherentData}; +use sp_npos_elections::CompactSolution; use sp_runtime::{ - Permill, Perbill, Perquintill, Percent, ApplyExtrinsicResult, - impl_opaque_keys, generic, create_runtime_str, ModuleId, FixedPointNumber, -}; -use sp_runtime::curve::PiecewiseLinear; -use sp_runtime::transaction_validity::{TransactionValidity, TransactionSource, TransactionPriority}; -use sp_runtime::traits::{ - self, BlakeTwo256, Block as BlockT, StaticLookup, SaturatedConversion, - ConvertInto, OpaqueKeys, NumberFor, + create_runtime_str, + curve::PiecewiseLinear, + generic, impl_opaque_keys, + traits::{ + self, BlakeTwo256, Block as BlockT, ConvertInto, NumberFor, OpaqueKeys, + SaturatedConversion, StaticLookup, + }, + transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, FixedPointNumber, ModuleId, Perbill, Percent, Permill, Perquintill, }; -use sp_version::RuntimeVersion; +use sp_std::prelude::*; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; -use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; -use pallet_grandpa::fg_primitives; -use pallet_im_online::sr25519::AuthorityId as ImOnlineId; -use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; -use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; -pub use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment, CurrencyAdapter}; -use pallet_session::{historical as pallet_session_historical}; -use sp_inherents::{InherentData, CheckInherentsResult}; +use sp_version::RuntimeVersion; use static_assertions::const_assert; use frame_election_providers::two_phase as pallet_two_phase_election_provider; @@ -451,7 +453,13 @@ pallet_staking_reward_curve::build! { ); } +sp_npos_elections::generate_solution_type!( + #[compact] + pub struct CompactU16Solution::(16) +); + parameter_types! { + pub const MaxNominations: u32 = CompactU16Solution::LIMIT as u32; pub const SessionsPerEra: sp_staking::SessionIndex = 6; pub const BondingDuration: pallet_staking::EraIndex = 24 * 28; pub const SlashDeferDuration: pallet_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. @@ -472,6 +480,7 @@ impl pallet_staking::Config for Runtime { type UnixTime = Timestamp; type CurrencyToVote = U128CurrencyToVote; type RewardRemainder = Treasury; + type MaxNominations = MaxNominations; type Event = Event; type Slash = Treasury; // send the slashed funds to the treasury. type Reward = (); // rewards are minted from the void @@ -520,6 +529,7 @@ impl pallet_two_phase_election_provider::Config for Runtime { type MinerMaxWeight = (); type UnsignedPriority = (); type ElectionDataProvider = Staking; + type CompactSolution = CompactU16Solution; type WeightInfo = (); } diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index 91567734ef354..ec2ea0737f7b3 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -106,8 +106,12 @@ where assert_eq!(all_voters.len() as u32, witness.voters); assert_eq!(winners.len() as u32, winners_count); + SnapshotMetadata::put(RoundSnapshotMetadata { + voters_len: all_voters.len() as u32, + targets_len: targets.len() as u32, + }); + DesiredTargets::put(winners_count); >::put(RoundSnapshot { - desired_targets: winners_count, voters: all_voters.clone(), targets: targets.clone(), }); diff --git a/frame/election-providers/src/two_phase/macros.rs b/frame/election-providers/src/two_phase/macros.rs index 83146a7263075..6bd7de658e6ae 100644 --- a/frame/election-providers/src/two_phase/macros.rs +++ b/frame/election-providers/src/two_phase/macros.rs @@ -55,14 +55,14 @@ macro_rules! target_index_fn { macro_rules! voter_at_fn { ($snap:ident, $acc:ty, $t:ident) => { |i: $crate::two_phase::CompactVoterIndexOf<$t>| -> Option<$acc> { - <$crate::two_phase::CompactVoterIndexOf<$t> as $crate::TryInto>::try_into(i) - .ok() - .and_then(|i| $snap - .get(i) - .map(|(x, _, _)| x) - .cloned() - ) - } + <$crate::two_phase::CompactVoterIndexOf<$t> as $crate::TryInto>::try_into(i) + .ok() + .and_then(|i| $snap + .get(i) + .map(|(x, _, _)| x) + .cloned() + ) + } }; } @@ -70,13 +70,13 @@ macro_rules! voter_at_fn { macro_rules! target_at_fn { ($snap:ident, $acc:ty, $t:ident) => { |i: $crate::two_phase::CompactTargetIndexOf<$t>| -> Option<$acc> { - <$crate::two_phase::CompactTargetIndexOf<$t> as $crate::TryInto>::try_into(i) - .ok() - .and_then(|i| $snap - .get(i) - .cloned() - ) - }; + <$crate::two_phase::CompactTargetIndexOf<$t> as $crate::TryInto>::try_into(i) + .ok() + .and_then(|i| $snap + .get(i) + .cloned() + ) + }; }; } @@ -85,11 +85,11 @@ macro_rules! target_at_fn { macro_rules! stake_of_fn { ($voters:ident, $acc:ty) => { |who: &$acc| -> $crate::VoteWeight { - $voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - } + $voters + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + } }; } diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 6d113a67dcea7..a416de23d803a 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -56,8 +56,8 @@ pub fn raw_solution() -> RawSolution> { let RoundSnapshot { voters, targets, - desired_targets, } = TwoPhase::snapshot().unwrap(); + let desired_targets = TwoPhase::desired_targets().unwrap(); // closures let voter_index = crate::voter_index_fn!(voters, AccountId, Runtime); @@ -195,6 +195,7 @@ impl crate::two_phase::Config for Runtime { type UnsignedPriority = UnsignedPriority; type ElectionDataProvider = StakingMock; type WeightInfo = (); + type CompactSolution = TestCompact; } impl frame_system::offchain::SendTransactionTypes for Runtime @@ -212,8 +213,6 @@ pub struct ExtBuilder {} pub struct StakingMock; impl ElectionDataProvider for StakingMock { - type CompactSolution = TestCompact; - fn targets() -> Vec { Targets::get() } diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 1ff9bed7dd434..b2094b610abf7 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -165,12 +165,8 @@ pub(crate) mod macros; pub mod signed; pub mod unsigned; -/// The compact solution type used by this crate. This is provided from the [`ElectionDataProvider`] -/// implementer. -pub type CompactOf = <::ElectionDataProvider as ElectionDataProvider< - ::AccountId, - ::BlockNumber, ->>::CompactSolution; +/// The compact solution type used by this crate. +pub type CompactOf = ::CompactSolution; /// The voter index. Derived from [`CompactOf`]. pub type CompactVoterIndexOf = as CompactSolution>::Voter; @@ -331,8 +327,21 @@ pub struct RoundSnapshot { pub voters: Vec<(A, VoteWeight, Vec)>, /// All of the targets. pub targets: Vec, - /// Desired number of winners to be elected for this round. - pub desired_targets: u32, +} + +/// Some metadata related to snapshot. +/// +/// In this pallet, there are cases where we want to read the whole snapshot (voters, targets, +/// desired), and cases that we are interested in just the length of these values. The former favors +/// the snapshot to be stored in one struct (as it is now) while the latter prefers them to be +/// separate to enable the use of `decode_len`. This approach is a middle ground, storing the +/// snapshot as one struct, whilst storing the lengths separately. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] +pub struct RoundSnapshotMetadata { + /// The length of voters. + voters_len: u32, + /// The length of targets. + targets_len: u32, } /// The crate errors. @@ -400,8 +409,8 @@ impl From for FeasibilityError { } pub trait WeightInfo { + fn on_initialize_nothing() -> Weight; fn on_initialize_open_signed_phase() -> Weight; - fn on_initialize_open_unsigned_phase() -> Weight; fn finalize_signed_phase_accept_solution() -> Weight; fn finalize_signed_phase_reject_solution() -> Weight; fn feasibility_check(v: u32, t: u32, a: u32, d: u32) -> Weight; @@ -419,10 +428,10 @@ impl WeightInfo for () { fn submit_unsigned(_: u32, _: u32, _: u32, _: u32) -> Weight { Default::default() } - fn on_initialize_open_signed_phase() -> Weight { + fn on_initialize_nothing() -> Weight { Default::default() } - fn on_initialize_open_unsigned_phase() -> Weight { + fn on_initialize_open_signed_phase() -> Weight { Default::default() } fn finalize_signed_phase_accept_solution() -> Weight { @@ -477,6 +486,15 @@ where /// Something that will provide the election data. type ElectionDataProvider: ElectionDataProvider; + /// The compact solution type + type CompactSolution: codec::Codec + + Default + + PartialEq + + Eq + + Clone + + sp_std::fmt::Debug + + CompactSolution; + /// The weight of the pallet. type WeightInfo: WeightInfo; } @@ -488,8 +506,8 @@ decl_storage! { /// This is useful for de-duplication of transactions submitted to the pool, and general /// diagnostics of the module. /// - /// This is merely incremented once per every time that signed phase starts. - pub Round get(fn round): u32 = 0; + /// This is merely incremented once per every time that an upstream `elect` is called. + pub Round get(fn round): u32 = 1; /// Current phase. pub CurrentPhase get(fn current_phase): Phase = Phase::Off; @@ -503,6 +521,16 @@ decl_storage! { /// /// This is created at the beginning of the signed phase and cleared upon calling `elect`. pub Snapshot get(fn snapshot): Option>; + + /// Desired number of targets to elect for this round. + /// + /// Only exists when [`Snapshot`] is present. + pub DesiredTargets get(fn desired_targets): Option; + + /// The metadata of the [`RoundSnapshot`] + /// + /// Only exists when [`Snapshot`] is present. + pub SnapshotMetadata get(fn snapshot_metadata): Option; } } @@ -556,26 +584,22 @@ decl_module! { let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); let unsigned_deadline = T::UnsignedPhase::get(); - sp_std::if_std! { - dbg!(now, next_election, signed_deadline, unsigned_deadline); - } let remaining = next_election - now; match Self::current_phase() { Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { // signed phase can only start after Off. >::put(Phase::Signed); - Round::mutate(|r| *r +=1); Self::start_signed_phase(); log!(info, "Starting signed phase at #{:?} , round {}.", now, Self::round()); T::WeightInfo::on_initialize_open_signed_phase() }, Phase::Signed | Phase::Off if remaining <= unsigned_deadline && remaining > 0u32.into() => { // unsigned phase can start after Off or Signed. - let _ = Self::finalize_signed_phase(); + let (_, consumed_weight) = Self::finalize_signed_phase(); // for now always start the unsigned phase. >::put(Phase::Unsigned((true, now))); log!(info, "Starting unsigned phase at #{:?}.", now); - T::WeightInfo::on_initialize_open_unsigned_phase() + consumed_weight }, _ => { Zero::zero() @@ -626,8 +650,7 @@ decl_module! { // build witness. Note: this is not needed for weight calc, thus not input. // defensive-only: if phase is signed, snapshot will exist. - let RoundSnapshot { voters, targets, .. } = Self::snapshot().unwrap_or_default(); - let witness = WitnessData { voters: voters.len() as u32, targets: targets.len() as u32 }; + let witness = Self::build_witness().unwrap_or_default(); // ensure solution claims is better. let mut signed_submissions = Self::signed_submissions(); @@ -676,10 +699,9 @@ decl_module! { let _ = Self::unsigned_pre_dispatch_checks(&solution)?; // ensure witness was correct. - // TODO: probably split these again.. - let RoundSnapshot { voters, targets, .. } = Self::snapshot().unwrap_or_default(); - ensure!(voters.len() as u32 == witness.voters, PalletError::::InvalidWitness); - ensure!(targets.len() as u32 == witness.targets, PalletError::::InvalidWitness); + let RoundSnapshotMetadata { voters_len, targets_len } = Self::snapshot_metadata().unwrap_or_default(); + ensure!(voters_len as u32 == witness.voters, PalletError::::InvalidWitness); + ensure!(targets_len as u32 == witness.targets, PalletError::::InvalidWitness); let ready = Self::feasibility_check(solution, ElectionCompute::Unsigned) @@ -699,6 +721,33 @@ impl Module where ExtendedBalance: From>>, { + /// Perform the tasks to be done after a new `elect` has been triggered: + /// + /// 1. Increment round. + /// 2. Change phase to [`Phase::Off`] + /// 3. Clear all snapshot data. + fn post_elect() { + // inc round + Round::mutate(|r| *r = *r + 1); + + // change phase + >::put(Phase::Off); + + // kill snapshots + >::kill(); + SnapshotMetadata::kill(); + DesiredTargets::kill(); + } + + /// Build the witness data from the snapshot metadata, if it exists. Else, returns `None`. + fn build_witness() -> Option { + let metadata = Self::snapshot_metadata()?; + Some(WitnessData { + voters: metadata.voters_len as u32, + targets: metadata.targets_len as u32, + }) + } + /// Checks the feasibility of a solution. /// /// This checks the solution for the following: @@ -717,18 +766,20 @@ where // winners are not directly encoded in the solution. let winners = compact.unique_targets(); - // read the entire snapshot. NOTE: could be optimized. - let RoundSnapshot { - voters: snapshot_voters, - targets: snapshot_targets, - desired_targets, - } = Self::snapshot().ok_or(FeasibilityError::SnapshotUnavailable)?; + let desired_targets = + Self::desired_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; ensure!( winners.len() as u32 == desired_targets, FeasibilityError::WrongWinnerCount, ); + // read the entire snapshot. + let RoundSnapshot { + voters: snapshot_voters, + targets: snapshot_targets, + } = Self::snapshot().ok_or(FeasibilityError::SnapshotUnavailable)?; + // ----- Start building. First, we need some closures. let voter_at = crate::voter_at_fn!(snapshot_voters, T::AccountId, T); let target_at = crate::target_at_fn!(snapshot_targets, T::AccountId, T); @@ -792,23 +843,15 @@ where fn onchain_fallback() -> Result, Error> { // If the length of singed phase is zero, the signed phase never starts and thus snapshot is // never created. - let get_snapshot_backup = || { + let snapshot_backup = || { let targets = T::ElectionDataProvider::targets(); let voters = T::ElectionDataProvider::voters(); - let desired_targets = T::ElectionDataProvider::desired_targets(); - - RoundSnapshot { - voters, - targets, - desired_targets, - } + RoundSnapshot { voters, targets } }; + let desired_targets_backup = || T::ElectionDataProvider::desired_targets(); - let RoundSnapshot { - desired_targets, - voters, - targets, - } = Self::snapshot().unwrap_or_else(get_snapshot_backup); + let RoundSnapshot { voters, targets } = Self::snapshot().unwrap_or_else(snapshot_backup); + let desired_targets = Self::desired_targets().unwrap_or_else(desired_targets_backup); >::elect::( desired_targets as usize, targets, @@ -844,11 +887,7 @@ where |ReadySolution { supports, compute, ..}| Ok((supports, compute)), ) .map(|(supports, compute)| { - // reset phase. - >::put(Phase::Off); - // clear snapshots. - >::kill(); - + Self::post_elect(); Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); log!(info, "Finalized election round with compute {:?}.", compute); supports @@ -880,12 +919,12 @@ mod tests { assert_eq!(System::block_number(), 0); assert_eq!(TwoPhase::current_phase(), Phase::Off); - assert_eq!(TwoPhase::round(), 0); + assert_eq!(TwoPhase::round(), 1); roll_to(4); assert_eq!(TwoPhase::current_phase(), Phase::Off); assert!(TwoPhase::snapshot().is_none()); - assert_eq!(TwoPhase::round(), 0); + assert_eq!(TwoPhase::round(), 1); roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Signed); @@ -919,7 +958,7 @@ mod tests { assert!(TwoPhase::current_phase().is_off()); assert!(TwoPhase::snapshot().is_none()); - assert_eq!(TwoPhase::round(), 1); + assert_eq!(TwoPhase::round(), 2); roll_to(44); assert!(TwoPhase::current_phase().is_off()); @@ -1037,4 +1076,9 @@ mod tests { assert!(TwoPhase::current_phase().is_off()); }); } + + #[test] + fn early_termination() { + // un expectedly early call to `elect`, at the middle of signed phase or unsigned phase. + } } diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index 9cb2e073e5e99..19cafc99b306b 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -39,11 +39,12 @@ where let voters = T::ElectionDataProvider::voters(); let desired_targets = T::ElectionDataProvider::desired_targets(); - >::put(RoundSnapshot { - voters, - targets, - desired_targets, + SnapshotMetadata::put(RoundSnapshotMetadata { + voters_len: voters.len() as u32, + targets_len: targets.len() as u32, }); + DesiredTargets::put(desired_targets); + >::put(RoundSnapshot { voters, targets }); } /// Finish the singed phase. Process the signed submissions from best to worse until a valid one @@ -53,7 +54,7 @@ where /// /// This drains the [`SignedSubmissions`], potentially storing the best valid one in /// [`QueuedSolution`]. - pub fn finalize_signed_phase() -> bool { + pub fn finalize_signed_phase() -> (bool, Weight) { let mut all_submission: Vec> = >::take(); let mut found_solution = false; let mut weight = T::DbWeight::get().reads(1); @@ -66,6 +67,19 @@ where reward, } = best; let active_voters = solution.compact.voters_count() as u32; + let feasibility_weight = { + // defensive only: at the end of signed phase, snapshot will exits. + let RoundSnapshotMetadata { + voters_len, + targets_len, + } = Self::snapshot_metadata().unwrap_or_default(); + let desired_targets = Self::desired_targets().unwrap_or_default(); + let v = voters_len as u32; + let t = targets_len as u32; + let a = active_voters; + let w = desired_targets; + T::WeightInfo::feasibility_check(v, t, a, w) + }; match Self::feasibility_check(solution, ElectionCompute::Signed) { Ok(ready_solution) => { Self::finalize_signed_phase_accept_solution( @@ -76,26 +90,14 @@ where ); found_solution = true; - let feasibility_weight = { - // TODO: might be easier to just store the weight in `SignedSubmission`? - let RoundSnapshot { - voters, - targets, - desired_targets, - } = Self::snapshot().unwrap_or_default(); - let v = voters.len() as u32; - let t = targets.len() as u32; - let a = active_voters; - let w = desired_targets; - T::WeightInfo::feasibility_check(v, t, a, w) - }; - weight = weight.saturating_add(feasibility_weight); weight = weight .saturating_add(T::WeightInfo::finalize_signed_phase_accept_solution()); break; } Err(_) => { + // we assume a worse ase feasibility check happened anyhow. + weight = weight.saturating_add(feasibility_weight); Self::finalize_signed_phase_reject_solution(&who, deposit); weight = weight .saturating_add(T::WeightInfo::finalize_signed_phase_reject_solution()); @@ -112,7 +114,7 @@ where debug_assert!(_remaining.is_zero()); }); - found_solution + (found_solution, weight) } /// Helper function for the case where a solution is accepted in the signed phase. @@ -332,7 +334,7 @@ mod tests { assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(balances(&99), (95, 5)); - assert!(TwoPhase::finalize_signed_phase()); + assert!(TwoPhase::finalize_signed_phase().0); assert_eq!(balances(&99), (100 + 7, 0)); }) } @@ -352,7 +354,7 @@ mod tests { assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(balances(&99), (95, 5)); - assert!(TwoPhase::finalize_signed_phase()); + assert!(TwoPhase::finalize_signed_phase().0); // expected reward is 5 + 10 assert_eq!(balances(&99), (100 + 10, 0)); }); @@ -370,7 +372,7 @@ mod tests { assert_ok!(submit_with_witness(Origin::signed(99), solution)); assert_eq!(balances(&99), (95, 5)); - assert!(TwoPhase::finalize_signed_phase()); + assert!(TwoPhase::finalize_signed_phase().0); // expected reward is 5 + 10 assert_eq!(balances(&99), (100 + 15, 0)); }); @@ -392,7 +394,7 @@ mod tests { assert_eq!(balances(&99), (95, 5)); // no good solution was stored. - assert!(!TwoPhase::finalize_signed_phase()); + assert!(!TwoPhase::finalize_signed_phase().0); // and the bond is gone. assert_eq!(balances(&99), (95, 0)); }) @@ -418,7 +420,7 @@ mod tests { assert_eq!(balances(&999), (95, 5)); // _some_ good solution was stored. - assert!(TwoPhase::finalize_signed_phase()); + assert!(TwoPhase::finalize_signed_phase().0); // 99 is rewarded. assert_eq!(balances(&99), (100 + 7, 0)); @@ -710,7 +712,7 @@ mod tests { ); // _some_ good solution was stored. - assert!(TwoPhase::finalize_signed_phase()); + assert!(TwoPhase::finalize_signed_phase().0); // 99 is rewarded. assert_eq!(balances(&99), (100 + 7, 0)); diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index cc2e1e04c4bf5..292af9202ba4f 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -46,11 +46,9 @@ where { /// Min a new npos solution. pub fn mine_solution(iters: usize) -> Result<(RawSolution>, WitnessData), Error> { - let RoundSnapshot { - desired_targets, - voters, - targets, - } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; + let RoundSnapshot { voters, targets } = + Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; + let desired_targets = Self::desired_targets().ok_or(Error::SnapshotUnAvailable)?; seq_phragmen::<_, CompactAccuracyOf>( desired_targets as usize, @@ -70,9 +68,9 @@ where election_result: ElectionResult>, ) -> Result<(RawSolution>, WitnessData), Error> { // storage items. Note: we have already read this from storage, they must be in cache. - let RoundSnapshot { - voters, targets, desired_targets, - } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; + let RoundSnapshot { voters, targets } = + Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; + let desired_targets = Self::desired_targets().ok_or(Error::SnapshotUnAvailable)?; // closures. let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); @@ -700,7 +698,7 @@ mod tests { // ensure we have snapshots in place. assert!(TwoPhase::snapshot().is_some()); - assert_eq!(TwoPhase::snapshot().unwrap().desired_targets, 2); + assert_eq!(TwoPhase::desired_targets().unwrap(), 2); // mine seq_phragmen solution with 2 iters. let (solution, witness) = TwoPhase::mine_solution(2).unwrap(); @@ -733,7 +731,7 @@ mod tests { roll_to(25); assert!(TwoPhase::current_phase().is_unsigned()); - assert_eq!(TwoPhase::snapshot().unwrap().desired_targets, 1); + assert_eq!(TwoPhase::desired_targets().unwrap(), 1); // an initial solution let result = ElectionResult { diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 9c54831ac8095..018feb6a2da47 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -199,9 +199,9 @@ benchmarks! { assert!(Validators::::contains_key(stash)); } - // Worst case scenario, MAX_NOMINATIONS + // Worst case scenario, T::MaxNominations::get() nominate { - let n in 1 .. MAX_NOMINATIONS as u32; + let n in 1 .. T::MaxNominations::get() as u32; let (stash, controller) = create_stash_controller::(n + 1, 100, Default::default())?; let validators = create_validators::(n, 100)?; whitelist_account!(controller); @@ -410,7 +410,7 @@ benchmarks! { let v in 1 .. 10; let n in 1 .. 100; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None)?; + create_validators_with_nominators_for_era::(v, n, T::MaxNominations::get() as usize, false, None)?; let session_index = SessionIndex::one(); }: { let validators = Staking::::new_era(session_index).ok_or("`new_era` failed")?; @@ -421,7 +421,7 @@ benchmarks! { payout_all { let v in 1 .. 10; let n in 1 .. 100; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None)?; + create_validators_with_nominators_for_era::(v, n, T::MaxNominations::get() as usize, false, None)?; // Start a new Era let new_validators = Staking::::new_era(SessionIndex::one()).unwrap(); assert!(new_validators.len() == v as usize); @@ -498,12 +498,12 @@ benchmarks! { // number of winners, also ValidatorCount. This will be equal to `winner.len()`. let w in 16 .. 100; - ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); + ensure!(w >= T::MaxNominations::get(), "doesn't support lower value"); let winners = create_validators_with_nominators_for_era::( v, n, - MAX_NOMINATIONS, + T::MaxNominations::get(), false, Some(w), )?; @@ -569,12 +569,12 @@ benchmarks! { // number of winners, also ValidatorCount. let w in 16 .. 100; - ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); + ensure!(w as usize >= T::MaxNominations::get(), "doesn't support lower value"); let winners = create_validators_with_nominators_for_era::( v, n, - MAX_NOMINATIONS, + T::MaxNominations::get(), false, Some(w), )?; @@ -659,7 +659,7 @@ benchmarks! { // number of nominator intention. let n in 500 .. 1000; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None)?; + create_validators_with_nominators_for_era::(v, n, T::MaxNominations::get(), false, None)?; // needed for the solution to be generates. assert!(>::create_stakers_snapshot().0); @@ -723,7 +723,7 @@ mod tests { let v = 10; let n = 100; - create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None) + create_validators_with_nominators_for_era::(v, n, ::MaxNominations::get() as usize, false, None) .unwrap(); let count_validators = Validators::::iter().count(); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index d76c9d820982e..19cc590bf48c8 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -298,7 +298,7 @@ use frame_support::{ use frame_system::{self as system, ensure_root, ensure_signed, offchain::SendTransactionTypes}; use pallet_session::historical; use sp_election_providers::{ElectionDataProvider, ElectionProvider, Supports}; -use sp_npos_elections::{generate_solution_type, CompactSolution, ExtendedBalance, VoteWeight}; +use sp_npos_elections::{ExtendedBalance, VoteWeight}; use sp_runtime::{ curve::PiecewiseLinear, traits::{ @@ -313,20 +313,11 @@ use sp_staking::{ offence::{Offence, OffenceDetails, OffenceError, OnOffenceHandler, ReportOffence}, SessionIndex, }; -use sp_std::{ - collections::btree_map::BTreeMap, - convert::{From, TryInto}, - mem::size_of, - prelude::*, - result, -}; +use sp_std::{collections::btree_map::BTreeMap, convert::From, mem::size_of, prelude::*, result}; use weights::WeightInfo; const STAKING_ID: LockIdentifier = *b"staking "; pub const MAX_UNLOCKING_CHUNKS: usize = 32; -// TODO: This should be moved to the runtime level, and there's no need for type CompactSolution in -// `ElectionDataProvider`. TwoPhase can just have a `type Compact = ...` in its `Config`. -pub const MAX_NOMINATIONS: usize = ::LIMIT; pub(crate) const LOG_TARGET: &'static str = "staking"; // syntactic sugar for logging. @@ -358,12 +349,6 @@ pub type EraIndex = u32; /// Counter for the number of "reward" points earned by a given validator. pub type RewardPoint = u32; -// Note: Maximum nomination limit is set here -- 16. -generate_solution_type!( - #[compact] - pub struct CompactU16Solution::(16) -); - /// Accuracy used for on-chain election. pub type ChainAccuracy = Perbill; @@ -799,6 +784,9 @@ pub trait Config: frame_system::Config + SendTransactionTypes> { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + + /// Maximum number of nominations allowed per nominator. + type MaxNominations: Get; } decl_storage! { @@ -1150,24 +1138,25 @@ decl_module! { ) ); - use sp_runtime::UpperOf; + // use sp_runtime::UpperOf; // see the documentation of `Assignment::try_normalize`. Now we can ensure that this // will always return `Ok`. // 1. Maximum sum of Vec must fit into `UpperOf`. - assert!( - >>::try_into(MAX_NOMINATIONS) - .unwrap() - .checked_mul(::one().deconstruct().try_into().unwrap()) - .is_some() - ); - - // 2. Maximum sum of Vec must fit into `UpperOf`. - assert!( - >>::try_into(MAX_NOMINATIONS) - .unwrap() - .checked_mul(::one().deconstruct().try_into().unwrap()) - .is_some() - ); + // TODO: these must go elsewhere + // assert!( + // >>::try_into(MAX_NOMINATIONS) + // .unwrap() + // .checked_mul(::one().deconstruct().try_into().unwrap()) + // .is_some() + // ); + + // // 2. Maximum sum of Vec must fit into `UpperOf`. + // assert!( + // >>::try_into(MAX_NOMINATIONS) + // .unwrap() + // .checked_mul(::one().deconstruct().try_into().unwrap()) + // .is_some() + // ); } /// Take the origin account as a stash and lock up `value` of its balance. `controller` will @@ -1444,7 +1433,7 @@ decl_module! { /// /// # /// - The transaction's complexity is proportional to the size of `targets` (N) - /// which is capped at CompactAssignments::LIMIT (MAX_NOMINATIONS). + /// which is capped at T::MaxNominations. /// - Both the reads and writes follow a similar pattern. /// --------- /// Weight: O(N) @@ -1460,7 +1449,7 @@ decl_module! { let stash = &ledger.stash; ensure!(!targets.is_empty(), Error::::EmptyTargets); let targets = targets.into_iter() - .take(MAX_NOMINATIONS) + .take(T::MaxNominations::get() as usize) .map(|t| T::Lookup::lookup(t)) .collect::, _>>()?; @@ -2140,7 +2129,6 @@ impl Module { *s = Some(s.map(|s| s + 1).unwrap_or(0)); s.unwrap() }); - println!("❌ ErasStartSessionIndex::insert({}, {});", current_era, start_session_index); ErasStartSessionIndex::insert(¤t_era, &start_session_index); // Clean old era information. @@ -2429,8 +2417,6 @@ impl Module { } impl ElectionDataProvider for Module { - type CompactSolution = CompactU16Solution; - fn desired_targets() -> u32 { Self::validator_count() } @@ -2466,16 +2452,6 @@ impl ElectionDataProvider for Module .saturating_sub(1) // one session is computed in this_session_end. .into(); - dbg!( - now, - session_index, - current_era_start_session_index, - era_length, - T::NextNewSession::estimate_next_new_session(now).unwrap(), - this_session_end, - sessions_left, - session_length, - ); this_session_end.saturating_add(sessions_left.saturating_mul(session_length)) } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index b42d344820059..cea388c0a81ff 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -224,6 +224,7 @@ pallet_staking_reward_curve::build! { ); } parameter_types! { + pub const MaxNominations: u32 = 16; pub const BondingDuration: EraIndex = 3; pub const RewardCurve: &'static PiecewiseLinear<'static> = &I_NPOS; pub const MaxNominatorRewardedPerValidator: u32 = 64; @@ -251,6 +252,7 @@ impl Config for Test { type Currency = Balances; type UnixTime = Timestamp; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; + type MaxNominations = MaxNominations; type RewardRemainder = RewardRemainderMock; type Event = MetaEvent; type Slash = (); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 143aee845e218..3c7f5a3476c2d 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4791,66 +4791,67 @@ fn cannot_rebond_to_lower_than_ed() { }) } -mod election_provider { - use super::*; - - #[test] - fn estimate_next_election_works() { - ExtBuilder::default() - .session_per_era(5) - .session_length(5) - .build() - .execute_with(|| { - // TODO: prediction for the first session is incorrect. correct is 20 because of - // first session having zero length - assert_session_era!(0, 0); - assert_eq!( - Staking::next_election_prediction(System::block_number()), - 25 - ); - - run_to_block(4); - assert_session_era!(0, 0); - assert_eq!( - Staking::next_election_prediction(System::block_number()), - 25 - ); - - run_to_block(19); - assert_session_era!(3, 0); - assert_eq!( - Staking::next_election_prediction(System::block_number()), - 25 - ); - - run_to_block(20); - assert_session_era!(4, 1); - assert_eq!( - Staking::next_election_prediction(System::block_number()), - 45 - ); - - run_to_block(21); - assert_session_era!(4, 1); - assert_eq!( - Staking::next_election_prediction(System::block_number()), - 45 - ); - - // run_to_block(25); - // assert_eq!(System::block_number(), 25); - // assert_session_era!(5, 1); - // assert_eq!( - // Staking::next_election_prediction(System::block_number()), - // 45 - // ); - - run_to_block(32); - assert_session_era!(6, 1); - assert_eq!( - Staking::next_election_prediction(System::block_number()), - 45 - ); - }) - } -} +// TODO: uncomment once https://github.com/paritytech/substrate/pull/7719 is merged. +// mod election_provider { +// use super::*; + +// #[test] +// fn estimate_next_election_works() { +// ExtBuilder::default() +// .session_per_era(5) +// .session_length(5) +// .build() +// .execute_with(|| { +// // TODO: prediction for the first session is incorrect. correct is 20 because of +// // first session having zero length +// assert_session_era!(0, 0); +// assert_eq!( +// Staking::next_election_prediction(System::block_number()), +// 25 +// ); + +// run_to_block(4); +// assert_session_era!(0, 0); +// assert_eq!( +// Staking::next_election_prediction(System::block_number()), +// 25 +// ); + +// run_to_block(19); +// assert_session_era!(3, 0); +// assert_eq!( +// Staking::next_election_prediction(System::block_number()), +// 25 +// ); + +// run_to_block(20); +// assert_session_era!(4, 1); +// assert_eq!( +// Staking::next_election_prediction(System::block_number()), +// 45 +// ); + +// run_to_block(21); +// assert_session_era!(4, 1); +// assert_eq!( +// Staking::next_election_prediction(System::block_number()), +// 45 +// ); + +// run_to_block(25); +// assert_eq!(System::block_number(), 25); +// assert_session_era!(5, 1); +// assert_eq!( +// Staking::next_election_prediction(System::block_number()), +// 45 +// ); + +// run_to_block(32); +// assert_session_era!(6, 1); +// assert_eq!( +// Staking::next_election_prediction(System::block_number()), +// 45 +// ); +// }) +// } +// } diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index 446f6e8fce488..6d45384accbc6 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -23,12 +23,11 @@ #![cfg_attr(not(feature = "std"), no_std)] -use sp_std::{fmt::Debug, prelude::*}; +use sp_std::prelude::*; use sp_arithmetic::PerThing; /// Re-export some type as they are used in the interface. -pub use sp_npos_elections::{CompactSolution, ExtendedBalance, PerThing128, VoteWeight, Supports}; - +pub use sp_npos_elections::{CompactSolution, ExtendedBalance, PerThing128, Supports, VoteWeight}; /// Something that can provide the data to something else that implements [`ElectionProvider`], such /// as the [`two_phase`] module. @@ -55,11 +54,6 @@ pub use sp_npos_elections::{CompactSolution, ExtendedBalance, PerThing128, VoteW /// } /// ``` pub trait ElectionDataProvider { - /// The compact solution type. - /// - /// This should encode the entire solution with the least possible space usage. - type CompactSolution: codec::Codec + Default + PartialEq + Eq + Clone + Debug + CompactSolution; - /// All possible targets for the election, i.e. the candidates. fn targets() -> Vec; diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index a88275e4bf137..634c5541a6b54 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -135,9 +135,16 @@ impl __OrInvalidIndex for Option { /// /// See [`compact`] for more info. pub trait CompactSolution: Sized { + /// The maximum number of votes that are allowed. const LIMIT: usize; + + /// The voter type. type Voter: UniqueSaturatedInto + TryInto + TryFrom + Debug + Copy + Clone; + + /// The target type type Target: UniqueSaturatedInto + TryInto + TryFrom + Debug + Copy + Clone; + + /// The weight type of each vote. type VoteWeight: PerThing128; fn from_assignment( From ef593a7670a87b72016478fa120e50749d6d3b7e Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 15 Dec 2020 10:55:02 +0000 Subject: [PATCH 23/62] Fix a bunch more issues. --- .../election-providers/src/two_phase/mock.rs | 36 +++++++++++++++-- frame/election-providers/src/two_phase/mod.rs | 40 ++++++++++++++++++- 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index a416de23d803a..8a38ea90040fd 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -35,6 +35,21 @@ sp_npos_elections::generate_solution_type!( pub struct TestCompact::(16) ); +/// All events of this pallet. +pub(crate) fn two_phase_events() -> Vec> { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| { + if let MetaEvent::two_phase(inner) = e { + Some(inner) + } else { + None + } + }) + .collect::>() +} + /// To from `now` to block `n`. pub fn roll_to(n: u64) { let now = System::block_number(); @@ -107,6 +122,21 @@ frame_support::impl_outer_origin! { pub enum Origin for Runtime where system = frame_system {} } +mod two_phase { + // Re-export needed for `impl_outer_event!`. + pub use super::super::*; +} +use frame_system as system; +use pallet_balances as balances; + +frame_support::impl_outer_event! { + pub enum MetaEvent for Runtime { + system, + balances, + two_phase, + } +} + impl frame_system::Config for Runtime { type BaseCallFilter = (); type Origin = Origin; @@ -118,7 +148,7 @@ impl frame_system::Config for Runtime { type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; - type Event = (); + type Event = MetaEvent; type BlockHashCount = (); type DbWeight = (); type BlockLength = (); @@ -137,7 +167,7 @@ parameter_types! { impl pallet_balances::Config for Runtime { type Balance = Balance; - type Event = (); + type Event = MetaEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -176,7 +206,7 @@ parameter_types! { } impl crate::two_phase::Config for Runtime { - type Event = (); + type Event = MetaEvent; type Currency = Balances; type SignedPhase = SignedPhase; type UnsignedPhase = UnsignedPhase; diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index b2094b610abf7..2dee722423171 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -548,6 +548,10 @@ decl_event!( Rewarded(AccountId), /// An account has been slashed for submitting an invalid signed submission. Slashed(AccountId), + /// The signed phase of the given round has started. + SignedPhaseStarted(u32), + /// The unsigned phase of the given round has started. + UnsignedPhaseStarted(u32), } ); @@ -590,6 +594,7 @@ decl_module! { // signed phase can only start after Off. >::put(Phase::Signed); Self::start_signed_phase(); + Self::deposit_event(RawEvent::SignedPhaseStarted(Self::round())); log!(info, "Starting signed phase at #{:?} , round {}.", now, Self::round()); T::WeightInfo::on_initialize_open_signed_phase() }, @@ -598,6 +603,7 @@ decl_module! { let (_, consumed_weight) = Self::finalize_signed_phase(); // for now always start the unsigned phase. >::put(Phase::Unsigned((true, now))); + Self::deposit_event(RawEvent::UnsignedPhaseStarted(Self::round())); log!(info, "Starting unsigned phase at #{:?}.", now); consumed_weight }, @@ -928,6 +934,7 @@ mod tests { roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Signed); + assert_eq!(two_phase_events(), vec![RawEvent::SignedPhaseStarted(1)]); assert!(TwoPhase::snapshot().is_some()); assert_eq!(TwoPhase::round(), 1); @@ -938,6 +945,7 @@ mod tests { roll_to(25); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); + assert_eq!(two_phase_events(), vec![RawEvent::SignedPhaseStarted(1), RawEvent::UnsignedPhaseStarted(1)]); assert!(TwoPhase::snapshot().is_some()); roll_to(29); @@ -1079,6 +1087,36 @@ mod tests { #[test] fn early_termination() { - // un expectedly early call to `elect`, at the middle of signed phase or unsigned phase. + // an early termination in the signed phase, with no queued solution. + ExtBuilder::default().build_and_execute(|| { + // signed phase started at block 15 and will end at 25. + roll_to(14); + assert_eq!(TwoPhase::current_phase(), Phase::Off); + + roll_to(15); + assert_eq!(two_phase_events(), vec![RawEvent::SignedPhaseStarted(1)]); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + assert_eq!(TwoPhase::round(), 1); + + // an unexpected call to elect. + roll_to(20); + TwoPhase::elect::(2, Default::default(), Default::default()) + .unwrap(); + + // we surely can't have any feasible solutions. This will cause an on-chain election. + assert_eq!( + two_phase_events(), + vec![ + RawEvent::SignedPhaseStarted(1), + RawEvent::ElectionFinalized(Some(ElectionCompute::OnChain)) + ], + ); + // all storage items must be cleared. + assert_eq!(TwoPhase::round(), 2); + assert!(TwoPhase::snapshot().is_none()); + assert!(TwoPhase::snapshot_metadata().is_none()); + assert!(TwoPhase::desired_targets().is_none()); + assert!(TwoPhase::queued_solution().is_none()); + }) } } From 8661814f28f3dcfa6916889e1030acd9c5af739b Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 18 Dec 2020 17:37:49 +0000 Subject: [PATCH 24/62] check new design --- primitives/election-providers/src/lib.rs | 218 +++++++++++++++++------ 1 file changed, 168 insertions(+), 50 deletions(-) diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index 6d45384accbc6..812260ed1cbe0 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -17,43 +17,166 @@ //! Primitive traits for providing election functionality. //! -//! This crate provides two traits that could potentially be implemented by two struct. The struct -//! receiving the functionality election could potentially implement [`ElectionDataProvider`] and -//! the struct providing the election functionality implements [`ElectionProvider`]. +//! This crate provides two traits that could potentially be implemented by two entities. The struct +//! receiving the functionality election should implement [`ElectionDataProvider`] and the struct +//! providing the election functionality implements [`ElectionProvider`], as such: +//! +//! ```ignore +//! ElectionDataProvider +//! <------------------------------------------+ +//! | | +//! v | +//! +-----+----+ +------+---+ +//! | | | | +//! pallet-do-election | | | |pallet-elect-winner +//! | | | | +//! | | | | +//! +-----+----+ +------+---+ +//! | ^ +//! | | +//! +------------------------------------------+ +//! ElectionProvider +//! +//! ``` +//! +//! > It could also be possible that a third party pallet (C), provides the data of election to an +//! > election provider (B), which then passes the election result to another pallet (A). +//! +//! Note that the [`ElectionProvider`] does not have a hard tie to the [`ElectionDataProvider`], +//! rather the link must be created by other means during implementation (i.e. an associated type in +//! `Config` trait the case of FRAME pallets). +//! +//! ## Election Types +//! +//! Typically, two types of elections exist: +//! +//! 1. Stateless: Election data is provided, and the election result is immediately ready. +//! 2. Stateful: Election data is is provided, and the election result might be ready some number of +//! blocks in the future. +//! +//! To accommodate both type of elections, the traits lean toward stateless election, as it is more +//! general than the stateless. This translates to the [`ElectionProvider::elect`] to have no +//! parameters. All value and type parameter must be provided by the [`ElectionDataProvider`] trait. +//! +//! ## Election Data +//! +//! The data associated with an election, essentially what the [`ElectionDataProvider`] must convey +//! is as follows: +//! +//! 1. A list of voters, with their stake. +//! 2. A list of targets (i.e. _candidates_). +//! 3. A number of desired targets to be elected (i.e. _winners_) +//! 4. An accuracy for the election's fixed point arithmetic. +//! +//! In addition to that, the [`ElectionDataProvider`] must also hint [`ElectionProvider`] at when +//! the next election might happen ([`ElectionDataProvider::next_election_prediction`]). +//! Nonetheless, an [`ElectionProvider`] shan't rely on this and should preferably provide some +//! means of fallback election as well. +//! +//! ## Example +//! +//! ```rust +//! # use sp_election_providers::*; +//! # use sp_npos_elections::Support; +//! +//! type AccountId = u64; +//! type Balance = u64; +//! type BlockNumber = u32; +//! +//! mod data_provider { +//! use super::*; +//! +//! pub trait Config { +//! type AccountId; +//! type ElectionProvider: ElectionProvider; +//! } +//! +//! pub struct Module(std::marker::PhantomData); +//! +//! impl ElectionDataProvider for Module { +//! fn desired_targets() -> u32 { +//! 1 +//! } +//! fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { +//! Default::default() +//! } +//! fn targets() -> Vec { +//! vec![10, 20, 30] +//! } +//! fn feasibility_check_assignment( +//! who: &AccountId, +//! distribution: &[(AccountId, P)], +//! ) -> bool { +//! true +//! } +//! fn next_election_prediction(now: BlockNumber) -> BlockNumber { +//! 0 +//! } +//! } +//! } +//! +//! +//! mod election_provider { +//! use super::*; +//! +//! pub struct SomeElectionProvider(std::marker::PhantomData); +//! +//! pub trait Config { +//! type DataProvider: ElectionDataProvider; +//! } +//! +//! impl ElectionProvider for SomeElectionProvider { +//! type Error = (); +//! +//! fn elect() -> Result, Self::Error> { +//! T::DataProvider::targets() +//! .first() +//! .map(|winner| vec![(*winner, Support::default())]) +//! .ok_or(()) +//! } +//! fn ongoing() -> bool { +//! false +//! } +//! } +//! } +//! +//! mod runtime { +//! use super::election_provider; +//! use super::data_provider; +//! use super::AccountId; +//! +//! struct Runtime; +//! impl election_provider::Config for Runtime { +//! type DataProvider = data_provider::Module; +//! } +//! +//! impl data_provider::Config for Runtime { +//! type AccountId = AccountId; +//! type ElectionProvider = election_provider::SomeElectionProvider; +//! } +//! +//! } +//! +//! # fn main() {} +//! ``` +//! +//! +//! ### ['ElectionDataProvider']'s side #![cfg_attr(not(feature = "std"), no_std)] use sp_std::prelude::*; -use sp_arithmetic::PerThing; /// Re-export some type as they are used in the interface. pub use sp_npos_elections::{CompactSolution, ExtendedBalance, PerThing128, Supports, VoteWeight}; +pub use sp_arithmetic::PerThing; -/// Something that can provide the data to something else that implements [`ElectionProvider`], such -/// as the [`two_phase`] module. -/// -/// The underlying purpose of this is to provide auxillary data to long-lasting election providers. -/// For example, the [`two_phase`] election provider needs to know the voters/targets list well in -/// advance and before a call to [`ElectionProvider::elect`]. -/// -/// For example, if pallet A wants to use the two-phase election: -/// -/// ```rust,ignore -/// pub trait TraitA { -/// type ElectionProvider: ElectionProvider<_, _>; -/// } -/// -/// // these function will be called by `Self::ElectionProvider` whenever needed. -/// impl ElectionDataProvider for PalletA { /* .. */ } +/// Something that can provide the data to something else that implements [`ElectionProvider`]. /// -/// impl Module { -/// fn do_election() { -/// // finalize the election. -/// T::ElectionProvider::elect( /* .. */ ); -/// } -/// } -/// ``` -pub trait ElectionDataProvider { +/// The underlying purpose of this is to provide auxillary data to stateful election providers. For +/// example, multi-block election provider needs to know the voters/targets list well in advance and +/// before a call to [`ElectionProvider::elect`]. +pub trait ElectionDataProvider { /// All possible targets for the election, i.e. the candidates. fn targets() -> Vec; @@ -69,7 +192,11 @@ pub trait ElectionDataProvider { /// words, check if `who` having a weight distribution described as `distribution` is correct or /// not. /// - /// This might be called by the [`ElectionProvider`] upon processing solutions. + /// This might be called by the [`ElectionProvider`] upon processing election solutions. + /// + /// Note that this is any feasibility check specific to `Self` that `ElectionProvider` is not + /// aware of. Simple feasibility (such as "did voter X actually vote for Y") should be checked + /// by `ElectionProvider` in any case. fn feasibility_check_assignment( who: &AccountId, distribution: &[(AccountId, P)], @@ -77,40 +204,31 @@ pub trait ElectionDataProvider { /// Provide a best effort prediction about when the next election is about to happen. /// - /// In essence, `Self` should predict with this function when it will trigger the - /// `ElectionDataProvider::elect`. - fn next_election_prediction(now: B) -> B; + /// In essence, the implementor should predict with this function when it will trigger the + /// [`ElectionDataProvider::elect`]. + fn next_election_prediction(now: BlockNumber) -> BlockNumber; } /// Something that can compute the result of an election and pass it back to the caller. +/// +/// This trait only provides an interface to _request_ an election, i.e. +/// [`ElectionProvider::elect`]. That data required for the election need to be passed to the +/// implemented of this trait through some other way. One example of such is the +/// [`ElectionDataProvider`] traits. pub trait ElectionProvider { - /// Indicate weather this election provider needs data when calling [`elect`] or not. If - /// `false`, then the call site can ignore all parameters of [`elect`]. - const NEEDS_ELECT_DATA: bool; - /// The error type that is returned by the provider. type Error; /// Elect a new set of winners. /// - /// The result is returned in a target major format, namely as a support map. - /// - /// Note that based on the logic of the type that will implement this trait, the input data may - /// or may not be used. To hint about this to the call site, [`NEEDS_ELECT_DATA`] should be - /// properly set. + /// The result is returned in a target major format, namely as vector of supports. /// /// The implementation should, if possible, use the accuracy `P` to compute the election result. - fn elect( - to_elect: usize, - targets: Vec, - voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>; + fn elect() -> Result, Self::Error>; /// Returns true if an election is still ongoing. /// - /// This can be used by the call site to dynamically check of a long-lasting election (such as - /// [`two_phase`]) is still on-going or not. + /// This can be used by the call site to dynamically check of a stateful is still on-going or + /// not. fn ongoing() -> bool; } From 57f7294d1a9fbe19183440956cf8107587663774 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Mon, 21 Dec 2020 16:08:34 +0000 Subject: [PATCH 25/62] Everything within the module works and compiles. --- frame/election-providers/src/onchain.rs | 170 ++++++++++++++--- .../src/two_phase/benchmarking.rs | 1 + .../election-providers/src/two_phase/mock.rs | 8 +- frame/election-providers/src/two_phase/mod.rs | 114 ++++++----- .../src/two_phase/unsigned.rs | 1 + primitives/election-providers/src/lib.rs | 177 +++++++++--------- 6 files changed, 297 insertions(+), 174 deletions(-) diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs index a7391652d7e6e..c2d60a6854764 100644 --- a/frame/election-providers/src/onchain.rs +++ b/frame/election-providers/src/onchain.rs @@ -1,16 +1,38 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! An implementation of [`sp_election_providers::ElectionProvider`] that does an on-chain +//! sequential phragmen. + use sp_arithmetic::PerThing; -use sp_election_providers::ElectionProvider; +use sp_election_providers::{ElectionDataProvider, ElectionProvider}; use sp_npos_elections::{ ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Supports, VoteWeight, }; use sp_runtime::RuntimeDebug; -use sp_std::{collections::btree_map::BTreeMap, prelude::*}; +use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*}; /// Errors of the on-chain election. #[derive(RuntimeDebug, Eq, PartialEq)] pub enum Error { /// An internal error in the NPoS elections crate. NposElections(sp_npos_elections::Error), + /// An assignment failed to pass the feasibility check + Feasibility(&'static str), } impl From for Error { @@ -26,47 +48,139 @@ impl From for Error { /// ### Warning /// /// This can be very expensive to run frequently on-chain. Use with care. -pub struct OnChainSequentialPhragmen; +pub struct OnChainSequentialPhragmen(PhantomData); -impl ElectionProvider for OnChainSequentialPhragmen { +/// Configuration trait of [`OnChainSequentialPhragmen`]. +/// +/// Note that this is similar to a pallet traits, but [`OnChainSequentialPhragmen`] is not a pallet. +pub trait Config { + /// The account identifier type. + type AccountId: IdentifierT; + /// The block number type. + type BlockNumber; + /// Something that provides the data for election. + type ElectionDataProvider: ElectionDataProvider; +} + +impl ElectionProvider for OnChainSequentialPhragmen { type Error = Error; - const NEEDS_ELECT_DATA: bool = true; - fn elect( - to_elect: usize, - targets: Vec, - voters: Vec<(AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> + fn elect() -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, { - let mut stake_map: BTreeMap = BTreeMap::new(); + let voters = T::ElectionDataProvider::voters(); + let targets = T::ElectionDataProvider::targets(); + let desired_targets = T::ElectionDataProvider::desired_targets() as usize; + + let mut stake_map: BTreeMap = BTreeMap::new(); + voters.iter().for_each(|(v, s, _)| { stake_map.insert(v.clone(), *s); }); - let stake_of = Box::new(|w: &AccountId| -> VoteWeight { + + let stake_of = Box::new(|w: &T::AccountId| -> VoteWeight { stake_map.get(w).cloned().unwrap_or_default() }); - sp_npos_elections::seq_phragmen::<_, P>(to_elect, targets, voters, None) - .and_then(|e| { - // these could use potential simplifications. - let ElectionResult { - winners, - assignments, - } = e; - let staked = sp_npos_elections::assignment_ratio_to_staked_normalized( - assignments, - &stake_of, - )?; - let winners = sp_npos_elections::to_without_backing(winners); - - sp_npos_elections::to_supports(&winners, &staked) - }) - .map_err(From::from) + let ElectionResult { + winners, + assignments, + } = sp_npos_elections::seq_phragmen::<_, P>(desired_targets, targets, voters, None) + .map_err(Error::from)?; + + // check all assignments for feasibility, based on election data provider. + assignments + .iter() + .map(T::ElectionDataProvider::feasibility_check_assignment) + .collect::>() + .map_err(|e| Error::Feasibility(e))?; + + let staked = + sp_npos_elections::assignment_ratio_to_staked_normalized(assignments, &stake_of)?; + let winners = sp_npos_elections::to_without_backing(winners); + + sp_npos_elections::to_supports(&winners, &staked).map_err(Error::from) } fn ongoing() -> bool { false } } + +#[cfg(test)] +mod tests { + use super::*; + use sp_election_providers::{Assignment, VoteWeight}; + use sp_npos_elections::Support; + + type AccountId = u64; + type BlockNumber = u32; + type Accuracy = sp_runtime::Perbill; + + struct Runtime; + impl Config for Runtime { + type AccountId = AccountId; + type BlockNumber = BlockNumber; + type ElectionDataProvider = mock_data_provider::DataProvider; + } + + type OnChainPhragmen = OnChainSequentialPhragmen; + + mod mock_data_provider { + use super::*; + + pub struct DataProvider; + + impl ElectionDataProvider for DataProvider { + fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { + vec![ + (1, 10, vec![10, 20]), + (2, 20, vec![30, 20]), + (3, 30, vec![10, 30]), + ] + } + + fn targets() -> Vec { + vec![10, 20, 30] + } + + fn desired_targets() -> u32 { + 2 + } + + fn feasibility_check_assignment( + _: &Assignment, + ) -> Result<(), &'static str> { + Ok(()) + } + + fn next_election_prediction(_: BlockNumber) -> BlockNumber { + 0 + } + } + } + + #[test] + fn onchain_seq_phragmen_works() { + assert_eq!( + OnChainPhragmen::elect::().unwrap(), + vec![ + ( + 10, + Support { + total: 25, + voters: vec![(1, 10), (3, 15)] + } + ), + ( + 30, + Support { + total: 35, + voters: vec![(2, 20), (3, 15)] + } + ) + ] + ); + } +} diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index ec2ea0737f7b3..a0f539cf5690b 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -24,6 +24,7 @@ pub use frame_benchmarking::{account, benchmarks, whitelist_account, whitelisted use frame_support::{assert_ok, traits::OnInitialize}; use frame_system::RawOrigin; use rand::{prelude::SliceRandom, rngs::SmallRng, SeedableRng}; +use sp_election_providers::Assignment; use sp_npos_elections::ExtendedBalance; use sp_runtime::InnerOf; use sp_std::convert::TryInto; diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 8a38ea90040fd..7cbc7b87d1512 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -8,7 +8,7 @@ use sp_core::{ }, H256, }; -use sp_election_providers::ElectionDataProvider; +use sp_election_providers::{Assignment, ElectionDataProvider}; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, to_without_backing, CompactSolution, ElectionResult, EvaluateSupport, @@ -252,8 +252,10 @@ impl ElectionDataProvider for StakingMock { fn desired_targets() -> u32 { DesiredTargets::get() } - fn feasibility_check_assignment(_: &AccountId, _: &[(AccountId, P)]) -> bool { - true + fn feasibility_check_assignment( + _: &Assignment, + ) -> Result<(), &'static str> { + Ok(()) } fn next_election_prediction(now: u64) -> u64 { now + EpochLength::get() - now % EpochLength::get() diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 2dee722423171..fb8eecc36f59a 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -146,8 +146,8 @@ use frame_support::{ use frame_system::{ensure_none, ensure_signed, offchain::SendTransactionTypes}; use sp_election_providers::{ElectionDataProvider, ElectionProvider}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, is_score_better, Assignment, CompactSolution, - ElectionScore, EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, + assignment_ratio_to_staked_normalized, is_score_better, CompactSolution, ElectionScore, + EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, }; use sp_runtime::{ traits::Zero, transaction_validity::TransactionPriority, InnerOf, PerThing, Perbill, @@ -178,10 +178,24 @@ pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -type PositiveImbalanceOf = - <::Currency as Currency<::AccountId>>::PositiveImbalance; -type NegativeImbalanceOf = - <::Currency as Currency<::AccountId>>::NegativeImbalance; +type PositiveImbalanceOf = <::Currency as Currency< + ::AccountId, +>>::PositiveImbalance; +type NegativeImbalanceOf = <::Currency as Currency< + ::AccountId, +>>::NegativeImbalance; + +struct OnChainConfig(sp_std::marker::PhantomData) +where + ExtendedBalance: From>>; +impl crate::onchain::Config for OnChainConfig +where + ExtendedBalance: From>>, +{ + type AccountId = T::AccountId; + type BlockNumber = T::BlockNumber; + type ElectionDataProvider = T::ElectionDataProvider; +} /// Current phase of the pallet. #[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] @@ -805,21 +819,30 @@ where // given snapshot, and check with the `ElectionDataProvider`. let _ = assignments .iter() - .map(|Assignment { who, distribution }| { - snapshot_voters.iter().find(|(v, _, _)| v == who).map_or( - Err(FeasibilityError::InvalidVoter), - |(_voter, _stake, targets)| { - if distribution.iter().map(|(d, _)| d).all(|d| targets.contains(d)) - && T::ElectionDataProvider::feasibility_check_assignment::< - CompactAccuracyOf, - >(who, distribution) - { - Ok(()) - } else { - Err(FeasibilityError::InvalidVote) - } - }, - ) + .map(|ref assignment| { + // TODO: better to rewrite this more with ? + snapshot_voters + .iter() + .find(|(v, _, _)| v == &assignment.who) + .map_or( + Err(FeasibilityError::InvalidVoter), + |(_voter, _stake, targets)| { + if assignment + .distribution + .iter() + .map(|(d, _)| d) + .all(|d| targets.contains(d)) + && T::ElectionDataProvider::feasibility_check_assignment::< + CompactAccuracyOf, + >(assignment) + .is_ok() + { + Ok(()) + } else { + Err(FeasibilityError::InvalidVote) + } + }, + ) }) .collect::>()?; @@ -847,22 +870,9 @@ where /// On-chain fallback of election. fn onchain_fallback() -> Result, Error> { - // If the length of singed phase is zero, the signed phase never starts and thus snapshot is - // never created. - let snapshot_backup = || { - let targets = T::ElectionDataProvider::targets(); - let voters = T::ElectionDataProvider::voters(); - RoundSnapshot { voters, targets } - }; - let desired_targets_backup = || T::ElectionDataProvider::desired_targets(); - - let RoundSnapshot { voters, targets } = Self::snapshot().unwrap_or_else(snapshot_backup); - let desired_targets = Self::desired_targets().unwrap_or_else(desired_targets_backup); - >::elect::( - desired_targets as usize, - targets, - voters, - ) + > as ElectionProvider>::elect::< + Perbill, + >() .map_err(Into::into) } } @@ -871,14 +881,9 @@ impl ElectionProvider for Module where ExtendedBalance: From>>, { - const NEEDS_ELECT_DATA: bool = false; type Error = Error; - fn elect( - _to_elect: usize, - _targets: Vec, - _voters: Vec<(T::AccountId, VoteWeight, Vec)>, - ) -> Result, Self::Error> + fn elect() -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, { @@ -915,6 +920,7 @@ mod tests { use super::{mock::*, *}; use sp_election_providers::ElectionProvider; use sp_npos_elections::Support; + use sp_runtime::Perbill; #[test] fn phase_rotation_works() { @@ -961,8 +967,7 @@ mod tests { assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); assert!(TwoPhase::snapshot().is_some()); - TwoPhase::elect::(2, Default::default(), Default::default()) - .unwrap(); + TwoPhase::elect::().unwrap(); assert!(TwoPhase::current_phase().is_off()); assert!(TwoPhase::snapshot().is_none()); @@ -989,9 +994,7 @@ mod tests { assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); // zilch solutions thus far. - let supports = - TwoPhase::elect::(2, Default::default(), Default::default()) - .unwrap(); + let supports = TwoPhase::elect::().unwrap(); assert_eq!( supports, @@ -1030,9 +1033,7 @@ mod tests { roll_to(30); assert!(TwoPhase::current_phase().is_unsigned_open_at(20)); - let _ = - TwoPhase::elect::(2, Default::default(), Default::default()) - .unwrap(); + TwoPhase::elect::().unwrap(); assert!(TwoPhase::current_phase().is_off()); }); @@ -1053,9 +1054,7 @@ mod tests { roll_to(30); assert!(TwoPhase::current_phase().is_signed()); - let _ = - TwoPhase::elect::(2, Default::default(), Default::default()) - .unwrap(); + let _ = TwoPhase::elect::().unwrap(); assert!(TwoPhase::current_phase().is_off()); }); @@ -1077,9 +1076,7 @@ mod tests { assert!(TwoPhase::current_phase().is_off()); // this module is now only capable of doing on-chain backup. - let _ = - TwoPhase::elect::(2, Default::default(), Default::default()) - .unwrap(); + let _ = TwoPhase::elect::().unwrap(); assert!(TwoPhase::current_phase().is_off()); }); @@ -1100,8 +1097,7 @@ mod tests { // an unexpected call to elect. roll_to(20); - TwoPhase::elect::(2, Default::default(), Default::default()) - .unwrap(); + TwoPhase::elect::().unwrap(); // we surely can't have any feasible solutions. This will cause an on-chain election. assert_eq!( diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 292af9202ba4f..621d48b71e233 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -553,6 +553,7 @@ fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { mod tests { use super::{mock::*, *}; use frame_support::{dispatch::Dispatchable, traits::OffchainWorker}; + use sp_election_providers::Assignment; use sp_runtime::PerU16; #[test] diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index 812260ed1cbe0..877856131c84b 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -50,12 +50,12 @@ //! //! Typically, two types of elections exist: //! -//! 1. Stateless: Election data is provided, and the election result is immediately ready. -//! 2. Stateful: Election data is is provided, and the election result might be ready some number of -//! blocks in the future. +//! 1. **Stateless**: Election data is provided, and the election result is immediately ready. +//! 2. **Stateful**: Election data is is provided, and the election result might be ready some +//! number of blocks in the future. //! -//! To accommodate both type of elections, the traits lean toward stateless election, as it is more -//! general than the stateless. This translates to the [`ElectionProvider::elect`] to have no +//! To accommodate both type of elections in one trait, the traits lean toward stateful election, as +//! it is more general than the stateless. This is why [`ElectionProvider::elect`] has no //! parameters. All value and type parameter must be provided by the [`ElectionDataProvider`] trait. //! //! ## Election Data @@ -66,7 +66,6 @@ //! 1. A list of voters, with their stake. //! 2. A list of targets (i.e. _candidates_). //! 3. A number of desired targets to be elected (i.e. _winners_) -//! 4. An accuracy for the election's fixed point arithmetic. //! //! In addition to that, the [`ElectionDataProvider`] must also hint [`ElectionProvider`] at when //! the next election might happen ([`ElectionDataProvider::next_election_prediction`]). @@ -80,96 +79,104 @@ //! # use sp_npos_elections::Support; //! //! type AccountId = u64; -//! type Balance = u64; -//! type BlockNumber = u32; +//! type Balance = u64; +//! type BlockNumber = u32; //! //! mod data_provider { -//! use super::*; -//! -//! pub trait Config { -//! type AccountId; -//! type ElectionProvider: ElectionProvider; -//! } -//! -//! pub struct Module(std::marker::PhantomData); -//! -//! impl ElectionDataProvider for Module { -//! fn desired_targets() -> u32 { -//! 1 -//! } -//! fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { -//! Default::default() -//! } -//! fn targets() -> Vec { -//! vec![10, 20, 30] -//! } -//! fn feasibility_check_assignment( -//! who: &AccountId, -//! distribution: &[(AccountId, P)], -//! ) -> bool { -//! true -//! } -//! fn next_election_prediction(now: BlockNumber) -> BlockNumber { -//! 0 -//! } -//! } +//! use super::*; +//! +//! pub trait Config { +//! type AccountId; +//! type ElectionProvider: ElectionProvider; +//! } +//! +//! pub struct Module(std::marker::PhantomData); +//! +//! impl ElectionDataProvider for Module { +//! fn desired_targets() -> u32 { +//! 1 +//! } +//! fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { +//! Default::default() +//! } +//! fn targets() -> Vec { +//! vec![10, 20, 30] +//! } +//! fn feasibility_check_assignment( +//! who: &AccountId, +//! distribution: &[(AccountId, P)], +//! ) -> bool { +//! true +//! } +//! fn next_election_prediction(now: BlockNumber) -> BlockNumber { +//! 0 +//! } +//! } //! } //! //! //! mod election_provider { -//! use super::*; -//! -//! pub struct SomeElectionProvider(std::marker::PhantomData); -//! -//! pub trait Config { -//! type DataProvider: ElectionDataProvider; -//! } -//! -//! impl ElectionProvider for SomeElectionProvider { -//! type Error = (); -//! -//! fn elect() -> Result, Self::Error> { -//! T::DataProvider::targets() -//! .first() -//! .map(|winner| vec![(*winner, Support::default())]) -//! .ok_or(()) -//! } -//! fn ongoing() -> bool { -//! false -//! } -//! } +//! use super::*; +//! +//! pub struct SomeElectionProvider(std::marker::PhantomData); +//! +//! pub trait Config { +//! type DataProvider: ElectionDataProvider; +//! } +//! +//! impl ElectionProvider for SomeElectionProvider { +//! type Error = (); +//! +//! fn elect() -> Result, Self::Error> { +//! T::DataProvider::targets() +//! .first() +//! .map(|winner| vec![(*winner, Support::default())]) +//! .ok_or(()) +//! } +//! fn ongoing() -> bool { +//! false +//! } +//! } //! } //! //! mod runtime { -//! use super::election_provider; -//! use super::data_provider; -//! use super::AccountId; +//! use super::election_provider; +//! use super::data_provider; +//! use super::AccountId; //! -//! struct Runtime; -//! impl election_provider::Config for Runtime { -//! type DataProvider = data_provider::Module; -//! } +//! struct Runtime; +//! impl election_provider::Config for Runtime { +//! type DataProvider = data_provider::Module; +//! } //! -//! impl data_provider::Config for Runtime { -//! type AccountId = AccountId; -//! type ElectionProvider = election_provider::SomeElectionProvider; -//! } +//! impl data_provider::Config for Runtime { +//! type AccountId = AccountId; +//! type ElectionProvider = election_provider::SomeElectionProvider; +//! } //! //! } //! //! # fn main() {} //! ``` //! +//! ## Interoperability //! -//! ### ['ElectionDataProvider']'s side +//! Note that [`ElectionProvider`] and [`ElectionDataProvider`] are not linked to one another in a +//! strict way. Nonetheless, it is strictly recommended to adhere to these traits for election +//! processes as there are a number of assumptions in each of them that rely on one another. +//! +//! That being said, once could create similar traits to achieve similar functionalities, and +//! replace one or both of of the traits provided in this crate. #![cfg_attr(not(feature = "std"), no_std)] use sp_std::prelude::*; -/// Re-export some type as they are used in the interface. -pub use sp_npos_elections::{CompactSolution, ExtendedBalance, PerThing128, Supports, VoteWeight}; pub use sp_arithmetic::PerThing; +/// Re-export some type as they are used in the interface. +pub use sp_npos_elections::{ + Assignment, CompactSolution, ExtendedBalance, PerThing128, Supports, VoteWeight, +}; /// Something that can provide the data to something else that implements [`ElectionProvider`]. /// @@ -188,24 +195,25 @@ pub trait ElectionDataProvider { /// The number of targets to elect. fn desired_targets() -> u32; - /// Check the feasibility of a single assignment for the underlying `ElectionProvider`. In other - /// words, check if `who` having a weight distribution described as `distribution` is correct or - /// not. + /// Check the feasibility of a single assignment for the underlying [`ElectionProvider`]. In + /// other words, check if `who` having a weight distribution described as `distribution` is + /// correct or not. /// /// This might be called by the [`ElectionProvider`] upon processing election solutions. /// - /// Note that this is any feasibility check specific to `Self` that `ElectionProvider` is not - /// aware of. Simple feasibility (such as "did voter X actually vote for Y") should be checked - /// by `ElectionProvider` in any case. + /// Note that each this must only contain checks that the [`ElectionProvider`] cannot know + /// about. Basics checks that can be known from [`Self::voters`] and [`Self::targets`] can be + /// assumed to be done by [`ElectionProvider`]. fn feasibility_check_assignment( - who: &AccountId, - distribution: &[(AccountId, P)], - ) -> bool; + assignment: &Assignment, + ) -> Result<(), &'static str>; /// Provide a best effort prediction about when the next election is about to happen. /// /// In essence, the implementor should predict with this function when it will trigger the /// [`ElectionDataProvider::elect`]. + /// + /// This is useful for stateful election providers only. fn next_election_prediction(now: BlockNumber) -> BlockNumber; } @@ -224,11 +232,12 @@ pub trait ElectionProvider { /// The result is returned in a target major format, namely as vector of supports. /// /// The implementation should, if possible, use the accuracy `P` to compute the election result. - fn elect() -> Result, Self::Error>; + fn elect() -> Result, Self::Error> + where + ExtendedBalance: From<

::Inner>; /// Returns true if an election is still ongoing. /// - /// This can be used by the call site to dynamically check of a stateful is still on-going or - /// not. + /// This can be used to dynamically check if a stateful election is still on-going or not. fn ongoing() -> bool; } From af304d10c3473bb33489090b9330f2d8d442156a Mon Sep 17 00:00:00 2001 From: kianenigma Date: Mon, 21 Dec 2020 17:07:27 +0000 Subject: [PATCH 26/62] Stkaing also builds --- frame/staking/src/lib.rs | 26 ++++++-------------------- frame/staking/src/mock.rs | 8 +++++++- frame/staking/src/tests.rs | 12 ++---------- 3 files changed, 15 insertions(+), 31 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 19cc590bf48c8..e0856c662a1b5 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -297,7 +297,7 @@ use frame_support::{ }; use frame_system::{self as system, ensure_root, ensure_signed, offchain::SendTransactionTypes}; use pallet_session::historical; -use sp_election_providers::{ElectionDataProvider, ElectionProvider, Supports}; +use sp_election_providers::{ElectionDataProvider, ElectionProvider, Supports, Assignment}; use sp_npos_elections::{ExtendedBalance, VoteWeight}; use sp_runtime::{ curve::PiecewiseLinear, @@ -2249,23 +2249,12 @@ impl Module { /// /// This will also process the election, as noted in [`process_election`]. fn enact_election(current_era: EraIndex) -> Option> { - if T::ElectionProvider::NEEDS_ELECT_DATA { - // This election will need the real data. - T::ElectionProvider::elect::( - Self::validator_count() as usize, - Self::get_npos_targets(), - Self::get_npos_voters(), - ) + // TODO: Worthy to denote how exactly the accuracy is playing a role here. We could at this + // point remove this generic as well, maybe it will also simplify some other stuff. + T::ElectionProvider::elect::() .map_err(|_| ()) .and_then(|flat_supports| Self::process_election(flat_supports, current_era)) .ok() - } else { - // no need to fetch the params. - T::ElectionProvider::elect::(0, vec![], vec![]) - .map_err(|_| ()) - .and_then(|flat_supports| Self::process_election(flat_supports, current_era)) - .ok() - } } /// Remove all associated data of a stash account from the staking system. @@ -2455,12 +2444,9 @@ impl ElectionDataProvider for Module this_session_end.saturating_add(sessions_left.saturating_mul(session_length)) } - fn feasibility_check_assignment( - _who: &T::AccountId, - _distribution: &[(T::AccountId, P)], - ) -> bool { + fn feasibility_check_assignment(_: &Assignment) -> Result<(), &'static str> { // TODO - true + Ok(()) } } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index cea388c0a81ff..1239ea898d74c 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -33,6 +33,7 @@ use sp_runtime::{ }; use sp_staking::offence::{OffenceDetails, OnOffenceHandler}; use std::{cell::RefCell, collections::HashSet}; +use frame_election_providers::onchain; pub const INIT_TIMESTAMP: u64 = 30_000; @@ -248,6 +249,11 @@ impl OnUnbalanced> for RewardRemainderMock { } } +impl onchain::Config for Test { + type AccountId = AccountId; + type BlockNumber = BlockNumber; + type ElectionDataProvider = Staking; +} impl Config for Test { type Currency = Balances; type UnixTime = Timestamp; @@ -265,7 +271,7 @@ impl Config for Test { type RewardCurve = RewardCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; - type ElectionProvider = frame_election_providers::onchain::OnChainSequentialPhragmen; + type ElectionProvider = onchain::OnChainSequentialPhragmen; type WeightInfo = (); } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 3c7f5a3476c2d..dc2074918c74d 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1752,11 +1752,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election() { // winners should be 21 and 31. Otherwise this election is taking duplicates into // account. - let election_result = ::ElectionProvider::elect::( - Staking::validator_count() as usize, - Staking::get_npos_targets(), - Staking::get_npos_voters(), - ).unwrap(); + let election_result = ::ElectionProvider::elect::().unwrap(); assert_eq_uvec!( election_result, @@ -1803,11 +1799,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election_elected() { assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31])); // winners should be 21 and 31. Otherwise this election is taking duplicates into account. - let election_result = ::ElectionProvider::elect::( - Staking::validator_count() as usize, - Staking::get_npos_targets(), - Staking::get_npos_voters(), - ).unwrap(); + let election_result = ::ElectionProvider::elect::().unwrap(); assert_eq_uvec!( election_result, From 80e7450693d6bf8eadff1a9701eac33edeedb57a Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 25 Dec 2020 19:48:15 +0000 Subject: [PATCH 27/62] Everything builds with the new scheme. --- bin/node/runtime/src/lib.rs | 3 +- frame/election-providers/src/onchain.rs | 15 ++--- .../src/two_phase/benchmarking.rs | 4 +- .../election-providers/src/two_phase/mock.rs | 3 +- frame/election-providers/src/two_phase/mod.rs | 57 ++++++++++++++----- .../src/two_phase/signed.rs | 7 ++- .../src/two_phase/unsigned.rs | 3 +- frame/staking/src/lib.rs | 2 +- frame/staking/src/mock.rs | 2 +- primitives/election-providers/src/lib.rs | 35 ++++++------ 10 files changed, 83 insertions(+), 48 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 1600af453d8bf..17b43db986505 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -528,8 +528,9 @@ impl pallet_two_phase_election_provider::Config for Runtime { type MinerMaxIterations = MaxUnsignedIterations; type MinerMaxWeight = (); type UnsignedPriority = (); - type ElectionDataProvider = Staking; + type DataProvider = Staking; type CompactSolution = CompactU16Solution; + type OnChainAccuracy = Perbill; type WeightInfo = (); } diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs index c2d60a6854764..d8238571d937a 100644 --- a/frame/election-providers/src/onchain.rs +++ b/frame/election-providers/src/onchain.rs @@ -59,19 +59,20 @@ pub trait Config { /// The block number type. type BlockNumber; /// Something that provides the data for election. - type ElectionDataProvider: ElectionDataProvider; + type DataProvider: ElectionDataProvider; } -impl ElectionProvider for OnChainSequentialPhragmen { +impl ElectionProvider for OnChainSequentialPhragmen { type Error = Error; + type DataProvider = T::DataProvider; fn elect() -> Result, Self::Error> where ExtendedBalance: From<

::Inner>, { - let voters = T::ElectionDataProvider::voters(); - let targets = T::ElectionDataProvider::targets(); - let desired_targets = T::ElectionDataProvider::desired_targets() as usize; + let voters = Self::DataProvider::voters(); + let targets = Self::DataProvider::targets(); + let desired_targets = Self::DataProvider::desired_targets() as usize; let mut stake_map: BTreeMap = BTreeMap::new(); @@ -92,7 +93,7 @@ impl ElectionProvider for OnChainSequentialPhragmen // check all assignments for feasibility, based on election data provider. assignments .iter() - .map(T::ElectionDataProvider::feasibility_check_assignment) + .map(Self::DataProvider::feasibility_check_assignment) .collect::>() .map_err(|e| Error::Feasibility(e))?; @@ -122,7 +123,7 @@ mod tests { impl Config for Runtime { type AccountId = AccountId; type BlockNumber = BlockNumber; - type ElectionDataProvider = mock_data_provider::DataProvider; + type DataProvider = mock_data_provider::DataProvider; } type OnChainPhragmen = OnChainSequentialPhragmen; diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index a0f539cf5690b..6ed401a798fd2 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -43,6 +43,7 @@ fn solution_with_size( ) -> RawSolution> where ExtendedBalance: From>>, + ExtendedBalance: From>>, > as sp_std::convert::TryFrom>::Error: sp_std::fmt::Debug, { assert!(witness.targets >= winners_count, "must have enough targets"); @@ -152,6 +153,7 @@ benchmarks! { where_clause { where ExtendedBalance: From>>, > as sp_std::convert::TryFrom>::Error: sp_std::fmt::Debug, + ExtendedBalance: From>>, } _{} @@ -166,7 +168,7 @@ benchmarks! { on_initialize_open_signed_phase { assert!(>::snapshot().is_none()); assert!(>::current_phase().is_off()); - let next_election = T::ElectionDataProvider::next_election_prediction(1u32.into()); + let next_election = T::DataProvider::next_election_prediction(1u32.into()); let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); let unsigned_deadline = T::UnsignedPhase::get(); diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 7cbc7b87d1512..6b0644287f1ab 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -223,8 +223,9 @@ impl crate::two_phase::Config for Runtime { type MinerMaxIterations = MinerMaxIterations; type MinerMaxWeight = MinerMaxWeight; type UnsignedPriority = UnsignedPriority; - type ElectionDataProvider = StakingMock; + type DataProvider = StakingMock; type WeightInfo = (); + type OnChainAccuracy = Perbill; type CompactSolution = TestCompact; } diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index fb8eecc36f59a..ce69d4f55b2ea 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -118,7 +118,10 @@ //! //! ## Accuracy //! -//! Solutions are encoded using indices of the [Snapshot]. The accuracy used for these indices +//! +//! TODO: onchain: whatever comes through elect, offchain, whatever is configured in trait. +//! +//! Solutions are encoded using indices of the [`Snapshot`]. The accuracy used for these indices //! heavily influences the size of the solution. These indices are configured by an upstream user of //! this pallet, through `CompactSolution` type of the `ElectionDataProvider`. //! @@ -172,8 +175,10 @@ pub type CompactOf = ::CompactSolution; pub type CompactVoterIndexOf = as CompactSolution>::Voter; /// The target index. Derived from [`CompactOf`]. pub type CompactTargetIndexOf = as CompactSolution>::Target; -/// The accuracy of the election. Derived from [`CompactOf`]. +/// The accuracy of the election, when submitted from offchain. Derived from [`CompactOf`]. pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; +/// The accuracy of the election, when computed on-chain. Equal to [`T::OnChainAccuracy`]. +pub type OnChainAccuracyOf = ::OnChainAccuracy; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -187,14 +192,16 @@ type NegativeImbalanceOf = <::Currency as Currency< struct OnChainConfig(sp_std::marker::PhantomData) where - ExtendedBalance: From>>; + ExtendedBalance: From>>, + ExtendedBalance: From>>; impl crate::onchain::Config for OnChainConfig where ExtendedBalance: From>>, + ExtendedBalance: From>>, { type AccountId = T::AccountId; type BlockNumber = T::BlockNumber; - type ElectionDataProvider = T::ElectionDataProvider; + type DataProvider = T::DataProvider; } /// Current phase of the pallet. @@ -459,6 +466,7 @@ impl WeightInfo for () { pub trait Config: frame_system::Config + SendTransactionTypes> where ExtendedBalance: From>>, + ExtendedBalance: From>>, { /// Event type. type Event: From> + Into<::Event>; @@ -498,7 +506,7 @@ where type RewardHandler: OnUnbalanced>; /// Something that will provide the election data. - type ElectionDataProvider: ElectionDataProvider; + type DataProvider: ElectionDataProvider; /// The compact solution type type CompactSolution: codec::Codec @@ -509,12 +517,19 @@ where + sp_std::fmt::Debug + CompactSolution; + /// Accuracy used for fallback on-chain election. + type OnChainAccuracy: PerThing128; + /// The weight of the pallet. type WeightInfo: WeightInfo; } decl_storage! { - trait Store for Module as TwoPhaseElectionProvider where ExtendedBalance: From>> { + trait Store for Module as TwoPhaseElectionProvider + where + ExtendedBalance: From>>, + ExtendedBalance: From>> + { /// Internal counter for the number of rounds. /// /// This is useful for de-duplication of transactions submitted to the pool, and general @@ -570,7 +585,11 @@ decl_event!( ); frame_support::decl_error! { - pub enum PalletError for Module where ExtendedBalance: From>> { + pub enum PalletError for Module + where + ExtendedBalance: From>>, + ExtendedBalance: From>> + { /// Submission was too early. EarlySubmission, /// Submission was too weak, score-wise. @@ -590,13 +609,14 @@ decl_module! { pub struct Module for enum Call where origin: T::Origin, - ExtendedBalance: From>> + ExtendedBalance: From>>, + ExtendedBalance: From>> { type Error = PalletError; fn deposit_event() = default; fn on_initialize(now: T::BlockNumber) -> Weight { - let next_election = T::ElectionDataProvider::next_election_prediction(now); + let next_election = T::DataProvider::next_election_prediction(now); let next_election = next_election.max(now); let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); @@ -740,6 +760,7 @@ decl_module! { impl Module where ExtendedBalance: From>>, + ExtendedBalance: From>>, { /// Perform the tasks to be done after a new `elect` has been triggered: /// @@ -832,7 +853,7 @@ where .iter() .map(|(d, _)| d) .all(|d| targets.contains(d)) - && T::ElectionDataProvider::feasibility_check_assignment::< + && T::DataProvider::feasibility_check_assignment::< CompactAccuracyOf, >(assignment) .is_ok() @@ -869,19 +890,25 @@ where } /// On-chain fallback of election. - fn onchain_fallback() -> Result, Error> { - > as ElectionProvider>::elect::< - Perbill, - >() + fn onchain_fallback() -> Result, Error> + where + ExtendedBalance: From<::Inner>, + { + > as ElectionProvider< + T::AccountId, + T::BlockNumber, + >>::elect::() .map_err(Into::into) } } -impl ElectionProvider for Module +impl ElectionProvider for Module where ExtendedBalance: From>>, + ExtendedBalance: From>>, { type Error = Error; + type DataProvider = T::DataProvider; fn elect() -> Result, Self::Error> where diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index 19cafc99b306b..3813470888d4f 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -27,6 +27,7 @@ use sp_npos_elections::CompactSolution; impl Module where ExtendedBalance: From>>, + ExtendedBalance: From>> { /// Start the signed phase. /// @@ -35,9 +36,9 @@ where /// /// The signed phase must always start before the unsigned phase. pub fn start_signed_phase() { - let targets = T::ElectionDataProvider::targets(); - let voters = T::ElectionDataProvider::voters(); - let desired_targets = T::ElectionDataProvider::desired_targets(); + let targets = T::DataProvider::targets(); + let voters = T::DataProvider::voters(); + let desired_targets = T::DataProvider::desired_targets(); SnapshotMetadata::put(RoundSnapshotMetadata { voters_len: voters.len() as u32, diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 621d48b71e233..3e88809944649 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -42,7 +42,7 @@ pub(crate) const DEFAULT_LONGEVITY: u64 = 25; impl Module where - ExtendedBalance: From>>, + ExtendedBalance: From>> + From>>, { /// Min a new npos solution. pub fn mine_solution(iters: usize) -> Result<(RawSolution>, WitnessData), Error> { @@ -344,6 +344,7 @@ where impl ValidateUnsigned for Module where ExtendedBalance: From>>, + ExtendedBalance: From>> { type Call = Call; fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index e0856c662a1b5..89d0053ab8e2a 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -736,7 +736,7 @@ pub trait Config: frame_system::Config + SendTransactionTypes> { type CurrencyToVote: CurrencyToVote>; /// Something that provides the election functionality. - type ElectionProvider: ElectionProvider; + type ElectionProvider: ElectionProvider>; /// Tokens have been minted and are unused for validator-reward. /// See [Era payout](./index.html#era-payout). diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 1239ea898d74c..e2400d62e6a29 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -252,7 +252,7 @@ impl OnUnbalanced> for RewardRemainderMock { impl onchain::Config for Test { type AccountId = AccountId; type BlockNumber = BlockNumber; - type ElectionDataProvider = Staking; + type DataProvider = Staking; } impl Config for Test { type Currency = Balances; diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index 877856131c84b..1a980ab524c64 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -76,7 +76,7 @@ //! //! ```rust //! # use sp_election_providers::*; -//! # use sp_npos_elections::Support; +//! # use sp_npos_elections::{Support, Assignment}; //! //! type AccountId = u64; //! type Balance = u64; @@ -85,9 +85,8 @@ //! mod data_provider { //! use super::*; //! -//! pub trait Config { -//! type AccountId; -//! type ElectionProvider: ElectionProvider; +//! pub trait Config: Sized { +//! type ElectionProvider: ElectionProvider>; //! } //! //! pub struct Module(std::marker::PhantomData); @@ -103,10 +102,9 @@ //! vec![10, 20, 30] //! } //! fn feasibility_check_assignment( -//! who: &AccountId, -//! distribution: &[(AccountId, P)], -//! ) -> bool { -//! true +//! _: &Assignment, +//! ) -> Result<(), &'static str> { +//! Ok(()) //! } //! fn next_election_prediction(now: BlockNumber) -> BlockNumber { //! 0 @@ -115,20 +113,21 @@ //! } //! //! -//! mod election_provider { +//! mod generic_election_provider { //! use super::*; //! -//! pub struct SomeElectionProvider(std::marker::PhantomData); +//! pub struct GenericElectionProvider(std::marker::PhantomData); //! //! pub trait Config { //! type DataProvider: ElectionDataProvider; //! } //! -//! impl ElectionProvider for SomeElectionProvider { +//! impl ElectionProvider for GenericElectionProvider { //! type Error = (); +//! type DataProvider = T::DataProvider; //! //! fn elect() -> Result, Self::Error> { -//! T::DataProvider::targets() +//! Self::DataProvider::targets() //! .first() //! .map(|winner| vec![(*winner, Support::default())]) //! .ok_or(()) @@ -140,18 +139,17 @@ //! } //! //! mod runtime { -//! use super::election_provider; +//! use super::generic_election_provider; //! use super::data_provider; //! use super::AccountId; //! //! struct Runtime; -//! impl election_provider::Config for Runtime { +//! impl generic_election_provider::Config for Runtime { //! type DataProvider = data_provider::Module; //! } //! //! impl data_provider::Config for Runtime { -//! type AccountId = AccountId; -//! type ElectionProvider = election_provider::SomeElectionProvider; +//! type ElectionProvider = generic_election_provider::GenericElectionProvider; //! } //! //! } @@ -223,10 +221,13 @@ pub trait ElectionDataProvider { /// [`ElectionProvider::elect`]. That data required for the election need to be passed to the /// implemented of this trait through some other way. One example of such is the /// [`ElectionDataProvider`] traits. -pub trait ElectionProvider { +pub trait ElectionProvider { /// The error type that is returned by the provider. type Error; + /// The data provider of this election. + type DataProvider: ElectionDataProvider; + /// Elect a new set of winners. /// /// The result is returned in a target major format, namely as vector of supports. From 206933a6b7423c08260dd188fa90b64e0845fc20 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sat, 26 Dec 2020 08:00:44 +0000 Subject: [PATCH 28/62] Simplify elect API. --- frame/election-providers/src/lib.rs | 4 +- frame/election-providers/src/onchain.rs | 19 +++-- frame/election-providers/src/two_phase/mod.rs | 21 ++--- primitives/election-providers/src/lib.rs | 82 +++++++++---------- 4 files changed, 59 insertions(+), 67 deletions(-) diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs index adf308038879b..fbd20a9287aed 100644 --- a/frame/election-providers/src/lib.rs +++ b/frame/election-providers/src/lib.rs @@ -19,10 +19,10 @@ //! //! Two main election providers are implemented in this crate. //! -//! 1. [onchain]: A `struct` that perform the election onchain (i.e. in the fly). This type is +//! 1. [`onchain`]: A `struct` that perform the election onchain (i.e. in the fly). This type is //! likely to be expensive for most chains and damage the block time. Only use when you are sure //! that the inputs are bounded and small enough. -//! 2. [two_phase]: An individual `pallet` that performs the election in two phases, signed and +//! 2. [`two_phase`]: An individual `pallet` that performs the election in two phases, signed and //! unsigned. Needless to say, the pallet needs to be included in the final runtime. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs index d8238571d937a..efda232ade34f 100644 --- a/frame/election-providers/src/onchain.rs +++ b/frame/election-providers/src/onchain.rs @@ -58,18 +58,20 @@ pub trait Config { type AccountId: IdentifierT; /// The block number type. type BlockNumber; + /// The accuracy used to compute the election: + type Accuracy: PerThing128; /// Something that provides the data for election. type DataProvider: ElectionDataProvider; } -impl ElectionProvider for OnChainSequentialPhragmen { +impl ElectionProvider for OnChainSequentialPhragmen +where + ExtendedBalance: From<::Inner>, +{ type Error = Error; type DataProvider = T::DataProvider; - fn elect() -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>, - { + fn elect() -> Result, Self::Error> { let voters = Self::DataProvider::voters(); let targets = Self::DataProvider::targets(); let desired_targets = Self::DataProvider::desired_targets() as usize; @@ -87,7 +89,7 @@ impl ElectionProvider for OnChainSequen let ElectionResult { winners, assignments, - } = sp_npos_elections::seq_phragmen::<_, P>(desired_targets, targets, voters, None) + } = sp_npos_elections::seq_phragmen::<_, T::Accuracy>(desired_targets, targets, voters, None) .map_err(Error::from)?; // check all assignments for feasibility, based on election data provider. @@ -114,15 +116,16 @@ mod tests { use super::*; use sp_election_providers::{Assignment, VoteWeight}; use sp_npos_elections::Support; + use sp_runtime::Perbill; type AccountId = u64; type BlockNumber = u32; - type Accuracy = sp_runtime::Perbill; struct Runtime; impl Config for Runtime { type AccountId = AccountId; type BlockNumber = BlockNumber; + type Accuracy = Perbill; type DataProvider = mock_data_provider::DataProvider; } @@ -165,7 +168,7 @@ mod tests { #[test] fn onchain_seq_phragmen_works() { assert_eq!( - OnChainPhragmen::elect::().unwrap(), + OnChainPhragmen::elect().unwrap(), vec![ ( 10, diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index ce69d4f55b2ea..556525818b102 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -201,6 +201,7 @@ where { type AccountId = T::AccountId; type BlockNumber = T::BlockNumber; + type Accuracy = T::OnChainAccuracy; type DataProvider = T::DataProvider; } @@ -897,7 +898,7 @@ where > as ElectionProvider< T::AccountId, T::BlockNumber, - >>::elect::() + >>::elect() .map_err(Into::into) } } @@ -910,10 +911,7 @@ where type Error = Error; type DataProvider = T::DataProvider; - fn elect() -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>, - { + fn elect() -> Result, Self::Error> { Self::queued_solution() .map_or_else( || { @@ -947,7 +945,6 @@ mod tests { use super::{mock::*, *}; use sp_election_providers::ElectionProvider; use sp_npos_elections::Support; - use sp_runtime::Perbill; #[test] fn phase_rotation_works() { @@ -994,7 +991,7 @@ mod tests { assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); assert!(TwoPhase::snapshot().is_some()); - TwoPhase::elect::().unwrap(); + TwoPhase::elect().unwrap(); assert!(TwoPhase::current_phase().is_off()); assert!(TwoPhase::snapshot().is_none()); @@ -1021,7 +1018,7 @@ mod tests { assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); // zilch solutions thus far. - let supports = TwoPhase::elect::().unwrap(); + let supports = TwoPhase::elect().unwrap(); assert_eq!( supports, @@ -1060,7 +1057,7 @@ mod tests { roll_to(30); assert!(TwoPhase::current_phase().is_unsigned_open_at(20)); - TwoPhase::elect::().unwrap(); + TwoPhase::elect().unwrap(); assert!(TwoPhase::current_phase().is_off()); }); @@ -1081,7 +1078,7 @@ mod tests { roll_to(30); assert!(TwoPhase::current_phase().is_signed()); - let _ = TwoPhase::elect::().unwrap(); + let _ = TwoPhase::elect().unwrap(); assert!(TwoPhase::current_phase().is_off()); }); @@ -1103,7 +1100,7 @@ mod tests { assert!(TwoPhase::current_phase().is_off()); // this module is now only capable of doing on-chain backup. - let _ = TwoPhase::elect::().unwrap(); + let _ = TwoPhase::elect().unwrap(); assert!(TwoPhase::current_phase().is_off()); }); @@ -1124,7 +1121,7 @@ mod tests { // an unexpected call to elect. roll_to(20); - TwoPhase::elect::().unwrap(); + TwoPhase::elect().unwrap(); // we surely can't have any feasible solutions. This will cause an on-chain election. assert_eq!( diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index 1a980ab524c64..5d6f9334c38bf 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -17,9 +17,13 @@ //! Primitive traits for providing election functionality. //! -//! This crate provides two traits that could potentially be implemented by two entities. The struct -//! receiving the functionality election should implement [`ElectionDataProvider`] and the struct -//! providing the election functionality implements [`ElectionProvider`], as such: +//! This crate provides two traits that could interact to enable extensible election functionality +//! within FRAME pallets. +//! +//! Something that will provide the functionality of election will implement [`ElectionProvider`], +//! whilst needing an associated [`ElectionProvider::DataProvider`], which needs to be fulfilled by +//! an entity implementing [`ElectionDataProvider`]. Most often, the data provider *is* the receiver +//! of the election, resulting in a diagram as below: //! //! ```ignore //! ElectionDataProvider @@ -28,7 +32,7 @@ //! v | //! +-----+----+ +------+---+ //! | | | | -//! pallet-do-election | | | |pallet-elect-winner +//! pallet-do-election | | | | pallet-needs-election //! | | | | //! | | | | //! +-----+----+ +------+---+ @@ -36,27 +40,23 @@ //! | | //! +------------------------------------------+ //! ElectionProvider -//! //! ``` //! //! > It could also be possible that a third party pallet (C), provides the data of election to an //! > election provider (B), which then passes the election result to another pallet (A). //! -//! Note that the [`ElectionProvider`] does not have a hard tie to the [`ElectionDataProvider`], -//! rather the link must be created by other means during implementation (i.e. an associated type in -//! `Config` trait the case of FRAME pallets). -//! //! ## Election Types //! //! Typically, two types of elections exist: //! //! 1. **Stateless**: Election data is provided, and the election result is immediately ready. -//! 2. **Stateful**: Election data is is provided, and the election result might be ready some -//! number of blocks in the future. +//! 2. **Stateful**: Election data is is queried ahead of time, and the election result might be +//! ready some number of blocks in the future. //! -//! To accommodate both type of elections in one trait, the traits lean toward stateful election, as -//! it is more general than the stateless. This is why [`ElectionProvider::elect`] has no -//! parameters. All value and type parameter must be provided by the [`ElectionDataProvider`] trait. +//! To accommodate both type of elections in one trait, the traits lean toward **stateful +//! election**, as it is more general than the stateless. This is why [`ElectionProvider::elect`] +//! has no parameters. All value and type parameter must be provided by the [`ElectionDataProvider`] +//! trait, even if the election happens immediately. //! //! ## Election Data //! @@ -86,7 +86,11 @@ //! use super::*; //! //! pub trait Config: Sized { -//! type ElectionProvider: ElectionProvider>; +//! type ElectionProvider: ElectionProvider< +//! AccountId, +//! BlockNumber, +//! DataProvider = Module, +//! >; //! } //! //! pub struct Module(std::marker::PhantomData); @@ -124,9 +128,9 @@ //! //! impl ElectionProvider for GenericElectionProvider { //! type Error = (); -//! type DataProvider = T::DataProvider; +//! type DataProvider = T::DataProvider; //! -//! fn elect() -> Result, Self::Error> { +//! fn elect() -> Result, Self::Error> { //! Self::DataProvider::targets() //! .first() //! .map(|winner| vec![(*winner, Support::default())]) @@ -156,31 +160,20 @@ //! //! # fn main() {} //! ``` -//! -//! ## Interoperability -//! -//! Note that [`ElectionProvider`] and [`ElectionDataProvider`] are not linked to one another in a -//! strict way. Nonetheless, it is strictly recommended to adhere to these traits for election -//! processes as there are a number of assumptions in each of them that rely on one another. -//! -//! That being said, once could create similar traits to achieve similar functionalities, and -//! replace one or both of of the traits provided in this crate. #![cfg_attr(not(feature = "std"), no_std)] use sp_std::prelude::*; -pub use sp_arithmetic::PerThing; /// Re-export some type as they are used in the interface. +pub use sp_arithmetic::PerThing; pub use sp_npos_elections::{ - Assignment, CompactSolution, ExtendedBalance, PerThing128, Supports, VoteWeight, + Assignment, ExtendedBalance, PerThing128, Supports, VoteWeight, }; /// Something that can provide the data to something else that implements [`ElectionProvider`]. /// -/// The underlying purpose of this is to provide auxillary data to stateful election providers. For -/// example, multi-block election provider needs to know the voters/targets list well in advance and -/// before a call to [`ElectionProvider::elect`]. +/// The underlying purpose of this is to provide auxillary data to stateful election providers. pub trait ElectionDataProvider { /// All possible targets for the election, i.e. the candidates. fn targets() -> Vec; @@ -193,15 +186,17 @@ pub trait ElectionDataProvider { /// The number of targets to elect. fn desired_targets() -> u32; - /// Check the feasibility of a single assignment for the underlying [`ElectionProvider`]. In - /// other words, check if `who` having a weight distribution described as `distribution` is - /// correct or not. + /// Check the feasibility of a single assignment for the underlying [`ElectionProvider`]. /// /// This might be called by the [`ElectionProvider`] upon processing election solutions. /// /// Note that each this must only contain checks that the [`ElectionProvider`] cannot know - /// about. Basics checks that can be known from [`Self::voters`] and [`Self::targets`] can be - /// assumed to be done by [`ElectionProvider`]. + /// about. Basics checks that can be known from [`Self::voters`] and [`Self::targets`] should + /// typically be done by [`ElectionProvider`]. + /// + /// For example, if a pallet contains some *private* knowledge that could potentially invalidate + /// an `assignment`, it should be checked here, as [`ElectionProvider`] has no way of knowing + /// about this. fn feasibility_check_assignment( assignment: &Assignment, ) -> Result<(), &'static str>; @@ -211,7 +206,7 @@ pub trait ElectionDataProvider { /// In essence, the implementor should predict with this function when it will trigger the /// [`ElectionDataProvider::elect`]. /// - /// This is useful for stateful election providers only. + /// This is only useful for stateful election providers. fn next_election_prediction(now: BlockNumber) -> BlockNumber; } @@ -219,23 +214,20 @@ pub trait ElectionDataProvider { /// /// This trait only provides an interface to _request_ an election, i.e. /// [`ElectionProvider::elect`]. That data required for the election need to be passed to the -/// implemented of this trait through some other way. One example of such is the -/// [`ElectionDataProvider`] traits. +/// implemented of this trait through [`ElectionProvider::DataProvider`]. pub trait ElectionProvider { /// The error type that is returned by the provider. type Error; - /// The data provider of this election. + /// The data provider of the election. type DataProvider: ElectionDataProvider; /// Elect a new set of winners. /// /// The result is returned in a target major format, namely as vector of supports. - /// - /// The implementation should, if possible, use the accuracy `P` to compute the election result. - fn elect() -> Result, Self::Error> - where - ExtendedBalance: From<

::Inner>; + fn elect() -> Result, Self::Error>; + // where + // ExtendedBalance: From<

::Inner>; /// Returns true if an election is still ongoing. /// From af9b97dba54ba7f29cba24821723ed938e388413 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sat, 26 Dec 2020 14:18:37 +0000 Subject: [PATCH 29/62] Fix all other tests. --- Cargo.lock | 21 - Cargo.toml | 1 - .../src/two_phase/benchmarking.rs | 15 + frame/election-providers/src/two_phase/mod.rs | 144 +- .../src/two_phase/signed.rs | 23 +- frame/offences/benchmarking/src/lib.rs | 14 +- frame/session/benchmarking/src/lib.rs | 14 +- frame/staking/fuzzer/.gitignore | 2 - frame/staking/fuzzer/Cargo.lock | 2294 ----------------- frame/staking/fuzzer/Cargo.toml | 34 - frame/staking/fuzzer/src/mock.rs | 183 -- frame/staking/fuzzer/src/submit_solution.rs | 182 -- frame/staking/src/lib.rs | 2 +- frame/staking/src/mock.rs | 1 + frame/staking/src/tests.rs | 4 +- primitives/npos-elections/compact/src/lib.rs | 2 +- primitives/npos-elections/src/lib.rs | 10 +- 17 files changed, 144 insertions(+), 2802 deletions(-) delete mode 100644 frame/staking/fuzzer/.gitignore delete mode 100644 frame/staking/fuzzer/Cargo.lock delete mode 100644 frame/staking/fuzzer/Cargo.toml delete mode 100644 frame/staking/fuzzer/src/mock.rs delete mode 100644 frame/staking/fuzzer/src/submit_solution.rs diff --git a/Cargo.lock b/Cargo.lock index 3f2c983f64d6b..53f2baac8a45b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5011,27 +5011,6 @@ dependencies = [ "substrate-test-utils", ] -[[package]] -name = "pallet-staking-fuzz" -version = "0.0.0" -dependencies = [ - "frame-support", - "frame-system", - "honggfuzz", - "pallet-balances", - "pallet-indices", - "pallet-session", - "pallet-staking", - "pallet-staking-reward-curve", - "pallet-timestamp", - "parity-scale-codec", - "sp-core", - "sp-io", - "sp-npos-elections", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-staking-reward-curve" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 09ee8b742dffe..58641c66e4ee4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,7 +97,6 @@ members = [ "frame/session/benchmarking", "frame/society", "frame/staking", - "frame/staking/fuzzer", "frame/staking/reward-curve", "frame/election-providers", "frame/sudo", diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index 6ed401a798fd2..3efb4e48476a6 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -166,6 +166,9 @@ benchmarks! { } on_initialize_open_signed_phase { + // NOTE: this benchmark currently doesn't have any components because the length of a db + // read/write is not captured. Otherwise, it is quite influenced by how much data + // `T::ElectionDataProvider` is reading and passing on. assert!(>::snapshot().is_none()); assert!(>::current_phase().is_off()); let next_election = T::DataProvider::next_election_prediction(1u32.into()); @@ -210,6 +213,14 @@ benchmarks! { assert_eq!(T::Currency::reserved_balance(&receiver), 0u32.into()); } + create_snapshot { + assert!(>::snapshot().is_none()); + }: { + >::create_snapshot() + } verify { + assert!(>::snapshot().is_some()); + } + submit { let c in 1 .. (T::MaxSignedSubmissions::get() - 1); @@ -318,5 +329,9 @@ mod test { Runtime, >()); }); + + ExtBuilder::default().build_and_execute(|| { + assert_ok!(test_benchmark_create_snapshot::()); + }); } } diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 556525818b102..1da3b0808fc0a 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -15,10 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Two phase election provider pallet. +//! # Two phase, offchain election provider pallet. //! -//! As the name suggests, this election-provider has two distinct phases (see -//! [Phase](two_phase::Phase)), signed and unsigned. +//! As the name suggests, this election-provider has two distinct phases (see [`Phase`]), signed and +//! unsigned. //! //! ## Phases //! @@ -35,24 +35,24 @@ //! //! ``` //! -//! Note that the unsigned phase starts [Config::UnsignedPhase](two_phase::Config::UnsignedPhase) -//! blocks before the `next_election_prediction`, but only ends when a call to -//! `ElectionProvider::elect` happens. +//! Note that the unsigned phase starts [`Config::UnsignedPhase`] blocks before the +//! `next_election_prediction`, but only ends when a call to [`Config::ElectionProvider::elect`] +//! happens. //! //! Each of the phases can be disabled by essentially setting their length to zero. If both phases //! have length zero, then the pallet essentially runs only the on-chain backup. //! //! ### Signed Phase //! -//! In the signed phase, solutions (of type [RawSolution](struct.RawSolution.html)) are submitted -//! and queued on chain. A deposit is reserved, based on the size of the solution, for the cost of -//! keeping this solution on-chain for a number of blocks, and the potential weight of the solution -//! upon being checked. A maximum of [`Config::MaxSignedSubmissions`] solutions are stored. The -//! queue is always sorted based on score (worse to best). +//! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A +//! deposit is reserved, based on the size of the solution, for the cost of keeping this solution +//! on-chain for a number of blocks, and the potential weight of the solution upon being checked. A +//! maximum of [`Config::MaxSignedSubmissions`] solutions are stored. The queue is always sorted +//! based on score (worse to best). //! //! Upon arrival of a new solution: //! -//! 1. If the queue is not full, it is stored in the appropriate index. +//! 1. If the queue is not full, it is stored in the appropriate sorted index. //! 2. If the queue is full but the submitted solution is better than one of the queued ones, the //! worse solution is discarded, the bond of the outgoing solution is returned, and the new //! solution is stored in the correct index. @@ -60,14 +60,14 @@ //! ones, it is instantly rejected and no additional bond is reserved. //! //! A signed solution cannot be reversed, taken back, updated, or retracted. In other words, the -//! origin can not bail out in any way. +//! origin can not bail out in any way, if their solution is queued. //! -//! Upon the end of the signed phase, the solutions are examined from worse to best (i.e. `pop()`ed -//! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which ensure -//! the score claimed by this score was correct, among other checks. At each step, if the current -//! best solution passes the feasibility check, it is considered to be the best one. The sender of -//! the origin is rewarded, and the rest of the queued solutions get their deposit back, without -//! being checked. +//! Upon the end of the signed phase, the solutions are examined from best to worse (i.e. `pop()`ed +//! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which +//! ensures the score claimed by this score was correct, and it is valid based on the election data +//! (i.e. votes and candidates). At each step, if the current best solution passes the feasibility +//! check, it is considered to be the best one. The sender of the origin is rewarded, and the rest +//! of the queued solutions get their deposit back and are discarded, without being checked. //! //! The following example covers all of the cases at the end of the signed phase: //! @@ -76,7 +76,7 @@ //! +-------------------------------+ //! |Solution(score=20, valid=false)| +--> Slashed //! +-------------------------------+ -//! |Solution(score=15, valid=true )| +--> Rewarded +//! |Solution(score=15, valid=true )| +--> Rewarded, Saved //! +-------------------------------+ //! |Solution(score=10, valid=true )| +--> Discarded //! +-------------------------------+ @@ -87,43 +87,50 @@ //! ``` //! //! Note that both of the bottom solutions end up being discarded and get their deposit back, -//! despite one of them being invalid. +//! despite one of them being *invalid*. //! //! ## Unsigned Phase //! //! The unsigned phase will always follow the signed phase, with the specified duration. In this //! phase, only validator nodes can submit solutions. A validator node who has offchain workers //! enabled will start to mine a solution in this phase and submits it back to the chain as an -//! unsigned transaction, thus the name _unsigned_ phase. +//! unsigned transaction, thus the name _unsigned_ phase. This unsigned transaction can never be +//! valid if propagated, and it acts similar to an inherent. //! //! Validators will only submit solutions if the one that they have computed is sufficiently better -//! than the best queued one (see [SolutionImprovementThreshold]) and will limit the weigh of the -//! solution to [MinerMaxWeight]. +//! than the best queued one (see [`SolutionImprovementThreshold`]) and will limit the weigh of the +//! solution to [`MinerMaxWeight`]. //! //! ### Fallback //! -//! If we reach the end of both phases (i.e. call to [ElectionProvider::elect] happens) and no good -//! solution is queued, then we fallback to an on-chain election. The on-chain election is slow, and -//! contains to balancing or reduction post-processing. +//! If we reach the end of both phases (i.e. call to [`ElectionProvider::elect`] happens) and no +//! good solution is queued, then we fallback to an on-chain election. The on-chain election is +//! slow, and contains no balancing or reduction post-processing. See +//! [`onchain::OnChainSequentialPhragmen`]. //! //! ## Feasible Solution (correct solution) //! -//! All submissions must undergo a feasibility check. A feasible solution is as follows: +//! All submissions must undergo a feasibility check. Signed solutions are checked on by one at the +//! end of the signed phase, and the unsigned solutions are checked on the spot. A feasible solution +//! is as follows: //! //! 0. **all** of the used indices must be correct. //! 1. present correct number of winners. -//! 2. any assignment is checked to match with [Snapshot::voters]. -//! 3. for each assignment, the check of `ElectionDataProvider` is also examined. +//! 2. any assignment is checked to match with [`Snapshot::voters`]. +//! 3. for each assignment, the check of ``ElectionDataProvider::feasibility_check_assignment`` is +//! also examined and must be correct. //! 4. the claimed score is valid. //! //! ## Accuracy //! +//! The accuracy of the election is configured via two trait parameters. namely, +//! [`Config::OnChainAccuracy`] dictates the accuracy used to compute the on-chain fallback election +//! (see [`OnChainAccuracyOf`]) and `[Config::DataProvider::CompactSolution::Accuracy]` is the +//! accuracy that the submitted solutions must adhere to. //! -//! TODO: onchain: whatever comes through elect, offchain, whatever is configured in trait. -//! -//! Solutions are encoded using indices of the [`Snapshot`]. The accuracy used for these indices -//! heavily influences the size of the solution. These indices are configured by an upstream user of -//! this pallet, through `CompactSolution` type of the `ElectionDataProvider`. +//! Note that both accuracies are of great importance. The offchain solution should be as small as +//! possible, reducing solutions size/weight. The on-chain solution can use more space for accuracy, +//! but should still be fast to prevent massively large blocks in case of a fallback. //! //! ## Future Plans //! @@ -136,6 +143,18 @@ //! 1. We must surely slash whoever submitted that solution (might be a challenge for unsigned //! solutions). //! 2. It is probably fine to fallback to the on-chain election, as we expect this to happen rarely. +//! +//! **Bailing out**. The functionality of bailing out of a queued solution is nice. A miner can +//! submit a solution as soon as they _think_ it is high probability feasible, and do the checks +//! afterwards, and remove their solution (for a small cost of probably just transaction fees, or a +//! portion of the bond). +//! +//! ** Conditionally open unsigned phase: Currently, the unsigned phase is always opened. This is +//! useful because an honest validation will run our OCW code, which should be good enough to trump +//! a mediocre or malicious signed submission (assuming in the absence of honest signed bots). If an +//! when the signed submissions are checked against an absolute measure (e.g. PJR), then we can only +//! open the unsigned phase in extreme conditions (i.e. "not good signed solution received") to +//! spare some work in the validators use crate::onchain::OnChainSequentialPhragmen; use codec::{Decode, Encode, HasCompact}; @@ -176,7 +195,7 @@ pub type CompactVoterIndexOf = as CompactSolution>::Voter; /// The target index. Derived from [`CompactOf`]. pub type CompactTargetIndexOf = as CompactSolution>::Target; /// The accuracy of the election, when submitted from offchain. Derived from [`CompactOf`]. -pub type CompactAccuracyOf = as CompactSolution>::VoteWeight; +pub type CompactAccuracyOf = as CompactSolution>::Accuracy; /// The accuracy of the election, when computed on-chain. Equal to [`T::OnChainAccuracy`]. pub type OnChainAccuracyOf = ::OnChainAccuracy; @@ -435,6 +454,7 @@ pub trait WeightInfo { fn on_initialize_open_signed_phase() -> Weight; fn finalize_signed_phase_accept_solution() -> Weight; fn finalize_signed_phase_reject_solution() -> Weight; + fn create_snapshot() -> Weight; fn feasibility_check(v: u32, t: u32, a: u32, d: u32) -> Weight; fn submit(c: u32) -> Weight; fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight; @@ -456,6 +476,9 @@ impl WeightInfo for () { fn on_initialize_open_signed_phase() -> Weight { Default::default() } + fn create_snapshot() -> Weight { + Default::default() + } fn finalize_signed_phase_accept_solution() -> Weight { Default::default() } @@ -624,21 +647,37 @@ decl_module! { let unsigned_deadline = T::UnsignedPhase::get(); let remaining = next_election - now; - match Self::current_phase() { + let current_phase = Self::current_phase(); + match current_phase { Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { - // signed phase can only start after Off. >::put(Phase::Signed); - Self::start_signed_phase(); + Self::create_snapshot(); + Self::deposit_event(RawEvent::SignedPhaseStarted(Self::round())); log!(info, "Starting signed phase at #{:?} , round {}.", now, Self::round()); + T::WeightInfo::on_initialize_open_signed_phase() }, Phase::Signed | Phase::Off if remaining <= unsigned_deadline && remaining > 0u32.into() => { - // unsigned phase can start after Off or Signed. - let (_, consumed_weight) = Self::finalize_signed_phase(); + let mut consumed_weight: Weight = 0; + if current_phase == Phase::Off { + // if not being followed by a signed phase, then create the snapshots. + debug_assert!(Self::snapshot().is_none()); + Self::create_snapshot(); + consumed_weight = consumed_weight.saturating_add(T::WeightInfo::create_snapshot()); + } else { + // if followed by a signed phase, then finalize the signed stuff. + debug_assert!(Self::signed_submissions().is_empty()); + } + + // noop if no signed phase has been open + let (_, weight) = Self::finalize_signed_phase(); + consumed_weight = consumed_weight.saturating_add(weight); + // for now always start the unsigned phase. >::put(Phase::Unsigned((true, now))); Self::deposit_event(RawEvent::UnsignedPhaseStarted(Self::round())); + log!(info, "Starting unsigned phase at #{:?}.", now); consumed_weight }, @@ -763,6 +802,25 @@ where ExtendedBalance: From>>, ExtendedBalance: From>>, { + /// Creates the snapshot. Writes new data to: + /// + /// 1. [`SnapshotMetadata`] + /// 2. [`RoundSnapshot`] + /// 3. [`DesiredTargets`] + pub fn create_snapshot() { + // if any of them don't exist, create all of them. This is a bit conservative. + let targets = T::DataProvider::targets(); + let voters = T::DataProvider::voters(); + let desired_targets = T::DataProvider::desired_targets(); + + SnapshotMetadata::put(RoundSnapshotMetadata { + voters_len: voters.len() as u32, + targets_len: targets.len() as u32, + }); + DesiredTargets::put(desired_targets); + >::put(RoundSnapshot { voters, targets }); + } + /// Perform the tasks to be done after a new `elect` has been triggered: /// /// 1. Increment round. @@ -1053,6 +1111,7 @@ mod tests { roll_to(20); assert!(TwoPhase::current_phase().is_unsigned_open_at(20)); + assert!(TwoPhase::snapshot().is_some()); roll_to(30); assert!(TwoPhase::current_phase().is_unsigned_open_at(20)); @@ -1060,6 +1119,7 @@ mod tests { TwoPhase::elect().unwrap(); assert!(TwoPhase::current_phase().is_off()); + assert!(TwoPhase::snapshot().is_none()); }); } @@ -1074,6 +1134,7 @@ mod tests { roll_to(20); assert!(TwoPhase::current_phase().is_signed()); + assert!(TwoPhase::snapshot().is_some()); roll_to(30); assert!(TwoPhase::current_phase().is_signed()); @@ -1081,6 +1142,7 @@ mod tests { let _ = TwoPhase::elect().unwrap(); assert!(TwoPhase::current_phase().is_off()); + assert!(TwoPhase::snapshot().is_none()); }); } diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index 3813470888d4f..b92f047942a89 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -27,27 +27,8 @@ use sp_npos_elections::CompactSolution; impl Module where ExtendedBalance: From>>, - ExtendedBalance: From>> + ExtendedBalance: From>>, { - /// Start the signed phase. - /// - /// Upon calling this, auxillary data for election is stored and signed solutions will be - /// accepted. - /// - /// The signed phase must always start before the unsigned phase. - pub fn start_signed_phase() { - let targets = T::DataProvider::targets(); - let voters = T::DataProvider::voters(); - let desired_targets = T::DataProvider::desired_targets(); - - SnapshotMetadata::put(RoundSnapshotMetadata { - voters_len: voters.len() as u32, - targets_len: targets.len() as u32, - }); - DesiredTargets::put(desired_targets); - >::put(RoundSnapshot { voters, targets }); - } - /// Finish the singed phase. Process the signed submissions from best to worse until a valid one /// is found, rewarding the best oen and slashing the invalid ones along the way. /// @@ -294,7 +275,7 @@ mod tests { assert_eq!(TwoPhase::current_phase(), Phase::Off); // create a temp snapshot only for this test. - TwoPhase::start_signed_phase(); + TwoPhase::create_snapshot(); let solution = raw_solution(); assert_noop!( diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 01fab9a29cd5a..fbb695a3facea 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -24,9 +24,9 @@ mod mock; use sp_std::prelude::*; use sp_std::vec; -use frame_system::{RawOrigin, Module as System, Config as SystemConfig}; -use frame_benchmarking::{benchmarks, account}; -use frame_support::traits::{Currency, OnInitialize}; +use frame_benchmarking::{account, benchmarks}; +use frame_support::traits::{Currency, Get, OnInitialize}; +use frame_system::{Config as SystemConfig, Module as System, RawOrigin}; use sp_runtime::{ traits::{Convert, Saturating, StaticLookup, UniqueSaturatedInto}, @@ -45,7 +45,7 @@ use pallet_session::{ }; use pallet_staking::{ Config as StakingConfig, Event as StakingEvent, Exposure, IndividualExposure, - Module as Staking, RewardDestination, ValidatorPrefs, MAX_NOMINATIONS, + Module as Staking, RewardDestination, ValidatorPrefs, }; const SEED: u32 = 0; @@ -214,7 +214,7 @@ benchmarks! { let r in 1 .. MAX_REPORTERS; // we skip 1 offender, because in such case there is no slashing let o in 2 .. MAX_OFFENDERS; - let n in 0 .. MAX_NOMINATORS.min(MAX_NOMINATIONS as u32); + let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); // Make r reporters let mut reporters = vec![]; @@ -288,7 +288,7 @@ benchmarks! { } report_offence_grandpa { - let n in 0 .. MAX_NOMINATORS.min(MAX_NOMINATIONS as u32); + let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); // for grandpa equivocation reports the number of reporters // and offenders is always 1 @@ -324,7 +324,7 @@ benchmarks! { } report_offence_babe { - let n in 0 .. MAX_NOMINATORS.min(MAX_NOMINATIONS as u32); + let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); // for babe equivocation reports the number of reporters // and offenders is always 1 diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index bd85b97c0d33e..6a5a065af2e01 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -28,14 +28,14 @@ use sp_std::vec; use frame_benchmarking::benchmarks; use frame_support::{ codec::Decode, - storage::{StorageValue, StorageMap}, - traits::{KeyOwnerProofSystem, OnInitialize}, + storage::{StorageMap, StorageValue}, + traits::{Get, KeyOwnerProofSystem, OnInitialize}, }; use frame_system::RawOrigin; use pallet_session::{historical::Module as Historical, Module as Session, *}; use pallet_staking::{ benchmarking::create_validator_with_nominators, testing_utils::create_validators, - MAX_NOMINATIONS, RewardDestination, + RewardDestination, }; use sp_runtime::traits::{One, StaticLookup}; @@ -54,10 +54,10 @@ benchmarks! { _ { } set_keys { - let n = MAX_NOMINATIONS as u32; + let n = ::MaxNominations::get(); let (v_stash, _) = create_validator_with_nominators::( n, - MAX_NOMINATIONS as u32, + ::MaxNominations::get(), false, RewardDestination::Staked, )?; @@ -70,10 +70,10 @@ benchmarks! { }: _(RawOrigin::Signed(v_controller), keys, proof) purge_keys { - let n = MAX_NOMINATIONS as u32; + let n = ::MaxNominations::get(); let (v_stash, _) = create_validator_with_nominators::( n, - MAX_NOMINATIONS as u32, + ::MaxNominations::get(), false, RewardDestination::Staked )?; diff --git a/frame/staking/fuzzer/.gitignore b/frame/staking/fuzzer/.gitignore deleted file mode 100644 index 3ebcb104d4a50..0000000000000 --- a/frame/staking/fuzzer/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -hfuzz_target -hfuzz_workspace diff --git a/frame/staking/fuzzer/Cargo.lock b/frame/staking/fuzzer/Cargo.lock deleted file mode 100644 index e451e12d10131..0000000000000 --- a/frame/staking/fuzzer/Cargo.lock +++ /dev/null @@ -1,2294 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "ahash" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f33b5018f120946c1dcf279194f238a9f146725593ead1c08fa47ff22b0b5d3" -dependencies = [ - "const-random", -] - -[[package]] -name = "aho-corasick" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" -dependencies = [ - "memchr", -] - -[[package]] -name = "alga" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f823d037a7ec6ea2197046bafd4ae150e6bc36f9ca347404f46a46823fa84f2" -dependencies = [ - "approx", - "num-complex", - "num-traits", -] - -[[package]] -name = "approx" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" -dependencies = [ - "num-traits", -] - -[[package]] -name = "arbitrary" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75153c95fdedd7db9732dfbfc3702324a1627eec91ba56e37cd0ac78314ab2ed" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] - -[[package]] -name = "arrayvec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" - -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" - -[[package]] -name = "autocfg" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" - -[[package]] -name = "backtrace" -version = "0.3.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e" -dependencies = [ - "backtrace-sys", - "cfg-if", - "libc", - "rustc-demangle", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "base58" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "bitmask" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da9b3d9f6f585199287a473f4f8dfab6566cf827d15c00c219f53c645687ead" - -[[package]] -name = "bitvec" -version = "0.17.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" -dependencies = [ - "either", - "radium", -] - -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" -dependencies = [ - "arrayvec 0.4.12", - "constant_time_eq", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - -[[package]] -name = "bumpalo" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" - -[[package]] -name = "byte-slice-cast" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - -[[package]] -name = "cc" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "clear_on_drop" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" -dependencies = [ - "cc", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - -[[package]] -name = "const-random" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" -dependencies = [ - "const-random-macro", - "proc-macro-hack", -] - -[[package]] -name = "const-random-macro" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" -dependencies = [ - "getrandom", - "proc-macro-hack", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-mac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -dependencies = [ - "generic-array", - "subtle 1.0.0", -] - -[[package]] -name = "curve25519-dalek" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26778518a7f6cffa1d25a44b602b62b979bd88adb9e99ffec546998cf3404839" -dependencies = [ - "byteorder", - "digest", - "rand_core 0.5.1", - "subtle 2.2.2", - "zeroize", -] - -[[package]] -name = "derive_more" -version = "0.99.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2323f3f47db9a0e77ce7a300605d8d2098597fc451ed1a97bb1f6411bb550a7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.0-pre.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978710b352437433c97b2bff193f2fb1dfd58a093f863dd95e225a19baa599a2" -dependencies = [ - "clear_on_drop", - "curve25519-dalek", - "rand 0.7.3", - "sha2", -] - -[[package]] -name = "either" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" - -[[package]] -name = "environmental" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516aa8d7a71cb00a1c4146f0798549b93d083d4f189b3ced8f3de6b8f11ee6c4" - -[[package]] -name = "failure" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "fixed-hash" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32529fc42e86ec06e5047092082aab9ad459b070c5d2a76b14f4f5ce70bf2e84" -dependencies = [ - "byteorder", - "rand 0.7.3", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "frame-benchmarking" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "frame-system", - "linregress", - "parity-scale-codec", - "sp-api", - "sp-io", - "sp-runtime", - "sp-runtime-interface", - "sp-std", -] - -[[package]] -name = "frame-metadata" -version = "11.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "serde", - "sp-core", - "sp-std", -] - -[[package]] -name = "frame-support" -version = "2.0.0-alpha.5" -dependencies = [ - "bitmask", - "frame-metadata", - "frame-support-procedural", - "impl-trait-for-tuples", - "log", - "once_cell", - "parity-scale-codec", - "paste", - "serde", - "sp-arithmetic", - "sp-core", - "sp-inherents", - "sp-io", - "sp-runtime", - "sp-state-machine", - "sp-std", - "tracing", -] - -[[package]] -name = "frame-support-procedural" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support-procedural-tools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "frame-support-procedural-tools" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support-procedural-tools-derive", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "frame-support-procedural-tools-derive" -version = "2.0.0-alpha.5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "frame-system" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "impl-trait-for-tuples", - "parity-scale-codec", - "serde", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "sp-version", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - -[[package]] -name = "futures" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" - -[[package]] -name = "futures-executor" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", - "num_cpus", -] - -[[package]] -name = "futures-io" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" - -[[package]] -name = "futures-macro" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" - -[[package]] -name = "futures-task" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" - -[[package]] -name = "futures-util" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-utils", - "proc-macro-hack", - "proc-macro-nested", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -dependencies = [ - "typenum", -] - -[[package]] -name = "getrandom" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hash-db" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" - -[[package]] -name = "hash256-std-hasher" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" -dependencies = [ - "crunchy", -] - -[[package]] -name = "hashbrown" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" -dependencies = [ - "ahash", - "autocfg 0.1.7", -] - -[[package]] -name = "heck" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "hermit-abi" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" - -[[package]] -name = "hmac" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" -dependencies = [ - "crypto-mac", - "digest", -] - -[[package]] -name = "hmac-drbg" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" -dependencies = [ - "digest", - "generic-array", - "hmac", -] - -[[package]] -name = "impl-codec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-serde" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-serde" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bbe9ea9b182f0fb1cabbd61f4ff9b7b7b9197955e95a7e4c27de5055eb29ff8" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef5550a42e3740a0e71f909d4c861056a284060af885ae7aa6242820f920d9d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "integer-sqrt" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f65877bf7d44897a473350b1046277941cee20b263397e90869c50b6e766088b" - -[[package]] -name = "js-sys" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a27d435371a2fa5b6d2b028a74bbdb1234f308da363226a2854ca3ff8ba7055" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "keccak" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" - -[[package]] -name = "libfuzzer-sys" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d718794b8e23533b9069bd2c4597d69e41cc7ab1c02700a502971aca0cdcf24" -dependencies = [ - "arbitrary", - "cc", -] - -[[package]] -name = "libm" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" - -[[package]] -name = "libsecp256k1" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" -dependencies = [ - "arrayref", - "crunchy", - "digest", - "hmac-drbg", - "rand 0.7.3", - "sha2", - "subtle 2.2.2", - "typenum", -] - -[[package]] -name = "linregress" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9290cf6f928576eeb9c096c6fad9d8d452a0a1a70a2bbffa6e36064eedc0aac9" -dependencies = [ - "failure", - "nalgebra", - "statrs", -] - -[[package]] -name = "lock_api" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "matrixmultiply" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4f7ec66360130972f34830bfad9ef05c6610a43938a467bcc9ab9369ab3478f" -dependencies = [ - "rawpointer", -] - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - -[[package]] -name = "memchr" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" - -[[package]] -name = "memory-db" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58381b20ebe2c578e75dececd9da411414903415349548ccc46aac3209cdfbc" -dependencies = [ - "ahash", - "hash-db", - "hashbrown", - "parity-util-mem", -] - -[[package]] -name = "memory_units" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" - -[[package]] -name = "merlin" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6feca46f4fa3443a01769d768727f10c10a20fdb65e52dc16a81f0c8269bb78" -dependencies = [ - "byteorder", - "keccak", - "rand_core 0.5.1", - "zeroize", -] - -[[package]] -name = "nalgebra" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaa9fddbc34c8c35dd2108515587b8ce0cab396f17977b8c738568e4edb521a2" -dependencies = [ - "alga", - "approx", - "generic-array", - "matrixmultiply", - "num-complex", - "num-rational", - "num-traits", - "rand 0.6.5", - "typenum", -] - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg 1.0.0", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" -dependencies = [ - "autocfg 1.0.0", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" -dependencies = [ - "autocfg 1.0.0", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" -dependencies = [ - "autocfg 1.0.0", - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" -dependencies = [ - "autocfg 1.0.0", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" -dependencies = [ - "parking_lot 0.9.0", -] - -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "pallet-authorship" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "parity-scale-codec", - "sp-authorship", - "sp-core", - "sp-inherents", - "sp-io", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-balances" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "parity-scale-codec", - "serde", - "sp-io", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-indices" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "frame-system", - "parity-scale-codec", - "serde", - "sp-core", - "sp-io", - "sp-keyring", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-session" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "pallet-timestamp", - "parity-scale-codec", - "serde", - "sp-io", - "sp-runtime", - "sp-staking", - "sp-std", - "sp-trie", -] - -[[package]] -name = "pallet-staking" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "frame-system", - "pallet-authorship", - "pallet-indices", - "pallet-session", - "parity-scale-codec", - "rand 0.7.3", - "serde", - "sp-application-crypto", - "sp-core", - "sp-io", - "sp-npos-elections", - "sp-runtime", - "sp-staking", - "sp-std", - "static_assertions", -] - -[[package]] -name = "pallet-staking-fuzz" -version = "0.0.0" -dependencies = [ - "frame-support", - "frame-system", - "libfuzzer-sys", - "pallet-balances", - "pallet-indices", - "pallet-session", - "pallet-staking", - "pallet-staking-reward-curve", - "pallet-timestamp", - "parity-scale-codec", - "rand 0.7.3", - "sp-core", - "sp-io", - "sp-npos-elections", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-staking-reward-curve" -version = "2.0.0-alpha.5" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pallet-timestamp" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "parity-scale-codec", - "serde", - "sp-inherents", - "sp-runtime", - "sp-std", - "sp-timestamp", -] - -[[package]] -name = "parity-scale-codec" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329c8f7f4244ddb5c37c103641027a76c530e65e8e4b8240b29f81ea40508b17" -dependencies = [ - "arrayvec 0.5.1", - "bitvec", - "byte-slice-cast", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0ec292e92e8ec7c58e576adacc1e3f399c597c8f263c42f18420abe58e7245" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "parity-util-mem" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e42755f26e5ea21a6a819d9e63cbd70713e9867a2b767ec2cc65ca7659532c5" -dependencies = [ - "cfg-if", - "impl-trait-for-tuples", - "parity-util-mem-derive", - "parking_lot 0.10.0", - "primitive-types", - "winapi", -] - -[[package]] -name = "parity-util-mem-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" -dependencies = [ - "proc-macro2", - "syn", - "synstructure", -] - -[[package]] -name = "parity-wasm" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" - -[[package]] -name = "parking_lot" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -dependencies = [ - "lock_api", - "parking_lot_core 0.6.2", - "rustc_version", -] - -[[package]] -name = "parking_lot" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" -dependencies = [ - "lock_api", - "parking_lot_core 0.7.0", -] - -[[package]] -name = "parking_lot_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -dependencies = [ - "cfg-if", - "cloudabi", - "libc", - "redox_syscall", - "rustc_version", - "smallvec 0.6.13", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" -dependencies = [ - "cfg-if", - "cloudabi", - "libc", - "redox_syscall", - "smallvec 1.2.0", - "winapi", -] - -[[package]] -name = "paste" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092d791bf7847f70bbd49085489fba25fc2c193571752bff9e36e74e72403932" -dependencies = [ - "paste-impl", - "proc-macro-hack", -] - -[[package]] -name = "paste-impl" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406c23fb4c45cc6f68a9bbabb8ec7bd6f8cfcbd17e9e8f72c2460282f8325729" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pbkdf2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" -dependencies = [ - "byteorder", - "crypto-mac", -] - -[[package]] -name = "pin-utils" -version = "0.1.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" - -[[package]] -name = "ppv-lite86" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" - -[[package]] -name = "primitive-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5e4b9943a2da369aec5e96f7c10ebc74fcf434d39590d974b0a3460e6f67fbb" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-serde 0.3.0", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420" - -[[package]] -name = "proc-macro-nested" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" - -[[package]] -name = "proc-macro2" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" - -[[package]] -name = "rand" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "winapi", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.7", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc 0.1.0", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.3.1", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "redox_syscall" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" - -[[package]] -name = "regex" -version = "1.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", - "thread_local", -] - -[[package]] -name = "regex-syntax" -version = "0.6.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" - -[[package]] -name = "rustc-demangle" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "schnorrkel" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" -dependencies = [ - "arrayref", - "arrayvec 0.5.1", - "curve25519-dalek", - "getrandom", - "merlin", - "rand 0.7.3", - "rand_core 0.5.1", - "sha2", - "subtle 2.2.2", - "zeroize", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "send_wrapper" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4" - -[[package]] -name = "serde" -version = "1.0.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sha2" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" -dependencies = [ - "block-buffer", - "digest", - "fake-simd", - "opaque-debug", -] - -[[package]] -name = "slab" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" - -[[package]] -name = "smallvec" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -dependencies = [ - "maybe-uninit", -] - -[[package]] -name = "smallvec" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" - -[[package]] -name = "sp-api" -version = "2.0.0-alpha.5" -dependencies = [ - "hash-db", - "parity-scale-codec", - "sp-api-proc-macro", - "sp-core", - "sp-runtime", - "sp-state-machine", - "sp-std", - "sp-version", -] - -[[package]] -name = "sp-api-proc-macro" -version = "2.0.0-alpha.5" -dependencies = [ - "blake2-rfc", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-application-crypto" -version = "2.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "serde", - "sp-core", - "sp-io", - "sp-std", -] - -[[package]] -name = "sp-arithmetic" -version = "2.0.0-alpha.5" -dependencies = [ - "integer-sqrt", - "num-traits", - "parity-scale-codec", - "serde", - "sp-debug-derive", - "sp-std", -] - -[[package]] -name = "sp-authorship" -version = "2.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "sp-inherents", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "sp-core" -version = "2.0.0-alpha.5" -dependencies = [ - "base58", - "blake2-rfc", - "byteorder", - "ed25519-dalek", - "futures", - "hash-db", - "hash256-std-hasher", - "hex", - "impl-serde 0.3.0", - "lazy_static", - "libsecp256k1", - "log", - "num-traits", - "parity-scale-codec", - "parity-util-mem", - "parking_lot 0.10.0", - "primitive-types", - "rand 0.7.3", - "regex", - "schnorrkel", - "serde", - "sha2", - "sp-debug-derive", - "sp-externalities", - "sp-runtime-interface", - "sp-std", - "sp-storage", - "substrate-bip39", - "tiny-bip39", - "tiny-keccak", - "twox-hash", - "wasmi", - "zeroize", -] - -[[package]] -name = "sp-debug-derive" -version = "2.0.0-alpha.5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-externalities" -version = "0.8.0-alpha.5" -dependencies = [ - "environmental", - "sp-std", - "sp-storage", -] - -[[package]] -name = "sp-inherents" -version = "2.0.0-alpha.5" -dependencies = [ - "derive_more", - "parity-scale-codec", - "parking_lot 0.10.0", - "sp-core", - "sp-std", -] - -[[package]] -name = "sp-io" -version = "2.0.0-alpha.5" -dependencies = [ - "hash-db", - "libsecp256k1", - "log", - "parity-scale-codec", - "sp-core", - "sp-externalities", - "sp-runtime-interface", - "sp-state-machine", - "sp-std", - "sp-trie", - "sp-wasm-interface", -] - -[[package]] -name = "sp-keyring" -version = "2.0.0-alpha.5" -dependencies = [ - "lazy_static", - "sp-core", - "sp-runtime", - "strum", -] - -[[package]] -name = "sp-panic-handler" -version = "2.0.0-alpha.5" -dependencies = [ - "backtrace", - "log", -] - -[[package]] -name = "sp-npos-elections" -version = "2.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "serde", - "sp-npos-elections-compact", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "sp-npos-elections-compact" -version = "2.0.0-rc3" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-runtime" -version = "2.0.0-alpha.5" -dependencies = [ - "hash256-std-hasher", - "impl-trait-for-tuples", - "log", - "parity-scale-codec", - "parity-util-mem", - "paste", - "rand 0.7.3", - "serde", - "sp-application-crypto", - "sp-arithmetic", - "sp-core", - "sp-inherents", - "sp-io", - "sp-std", -] - -[[package]] -name = "sp-runtime-interface" -version = "2.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "primitive-types", - "sp-externalities", - "sp-runtime-interface-proc-macro", - "sp-std", - "sp-wasm-interface", - "static_assertions", -] - -[[package]] -name = "sp-runtime-interface-proc-macro" -version = "2.0.0-alpha.5" -dependencies = [ - "Inflector", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-staking" -version = "2.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "sp-state-machine" -version = "0.8.0-alpha.5" -dependencies = [ - "hash-db", - "log", - "num-traits", - "parity-scale-codec", - "parking_lot 0.10.0", - "rand 0.7.3", - "sp-core", - "sp-externalities", - "sp-panic-handler", - "sp-trie", - "trie-db", - "trie-root", -] - -[[package]] -name = "sp-std" -version = "2.0.0-alpha.5" - -[[package]] -name = "sp-storage" -version = "2.0.0-alpha.5" -dependencies = [ - "impl-serde 0.2.3", - "serde", - "sp-debug-derive", - "sp-std", -] - -[[package]] -name = "sp-timestamp" -version = "2.0.0-alpha.5" -dependencies = [ - "impl-trait-for-tuples", - "parity-scale-codec", - "sp-api", - "sp-inherents", - "sp-runtime", - "sp-std", - "wasm-timer", -] - -[[package]] -name = "sp-trie" -version = "2.0.0-alpha.5" -dependencies = [ - "hash-db", - "memory-db", - "parity-scale-codec", - "sp-core", - "sp-std", - "trie-db", - "trie-root", -] - -[[package]] -name = "sp-version" -version = "2.0.0-alpha.5" -dependencies = [ - "impl-serde 0.2.3", - "parity-scale-codec", - "serde", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "sp-wasm-interface" -version = "2.0.0-alpha.5" -dependencies = [ - "impl-trait-for-tuples", - "parity-scale-codec", - "sp-std", - "wasmi", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "statrs" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10102ac8d55e35db2b3fafc26f81ba8647da2e15879ab686a67e6d19af2685e8" -dependencies = [ - "rand 0.5.6", -] - -[[package]] -name = "strum" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0054a7df764039a6cd8592b9de84be4bec368ff081d203a7d5371cbfa8e65c81" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "substrate-bip39" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c004e8166d6e0aa3a9d5fa673e5b7098ff25f930de1013a21341988151e681bb" -dependencies = [ - "hmac", - "pbkdf2", - "schnorrkel", - "sha2", -] - -[[package]] -name = "subtle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" - -[[package]] -name = "subtle" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" - -[[package]] -name = "syn" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "synstructure" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "tiny-bip39" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0165e045cc2ae1660270ca65e1676dbaab60feb0f91b10f7d0665e9b47e31f2" -dependencies = [ - "failure", - "hmac", - "once_cell", - "pbkdf2", - "rand 0.7.3", - "rustc-hash", - "sha2", - "unicode-normalization", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2953ca5148619bc99695c1274cb54c5275bbb913c6adad87e72eaf8db9787f69" -dependencies = [ - "crunchy", -] - -[[package]] -name = "toml" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" -dependencies = [ - "serde", -] - -[[package]] -name = "tracing" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1721cc8cf7d770cc4257872507180f35a4797272f5962f24c806af9e7faf52ab" -dependencies = [ - "cfg-if", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbad39da2f9af1cae3016339ad7f2c7a9e870f12e8fd04c4fd7ef35b30c0d2b" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "trie-db" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de9222c50cc325855621271157c973da27a0dcd26fa06f8edf81020bd2333df0" -dependencies = [ - "hash-db", - "hashbrown", - "log", - "rustc-hex", - "smallvec 1.2.0", -] - -[[package]] -name = "trie-root" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "652931506d2c1244d7217a70b99f56718a7b4161b37f04e7cd868072a99f68cd" -dependencies = [ - "hash-db", -] - -[[package]] -name = "twox-hash" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" -dependencies = [ - "rand 0.7.3", -] - -[[package]] -name = "typenum" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" - -[[package]] -name = "uint" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75a4cdd7b87b28840dba13c483b9a88ee6bbf16ba5c951ee1ecfcf723078e0d" -dependencies = [ - "byteorder", - "crunchy", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" -dependencies = [ - "smallvec 1.2.0", -] - -[[package]] -name = "unicode-segmentation" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" - -[[package]] -name = "unicode-xid" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasm-bindgen" -version = "0.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc57ce05287f8376e998cbddfb4c8cb43b84a7ec55cf4551d7c00eef317a47f" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967d37bf6c16cca2973ca3af071d0a2523392e4a594548155d89a678f4237cd" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7add542ea1ac7fdaa9dc25e031a6af33b7d63376292bd24140c637d00d1c312a" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf76fe7d25ac79748a37538b7daeed1c7a6867c92d3245c12c6222e4a20d639" - -[[package]] -name = "wasm-timer" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324c5e65a08699c9c4334ba136597ab22b85dccd4b65dd1e36ccf8f723a95b54" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.9.0", - "pin-utils", - "send_wrapper", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wasmi" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf617d864d25af3587aa745529f7aaa541066c876d57e050c0d0c85c61c92aff" -dependencies = [ - "libc", - "memory_units", - "num-rational", - "num-traits", - "parity-wasm", - "wasmi-validation", -] - -[[package]] -name = "wasmi-validation" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93" -dependencies = [ - "parity-wasm", -] - -[[package]] -name = "web-sys" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6f51648d8c56c366144378a33290049eafdd784071077f6fe37dae64c1c4cb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "zeroize" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] diff --git a/frame/staking/fuzzer/Cargo.toml b/frame/staking/fuzzer/Cargo.toml deleted file mode 100644 index e1431aa54d4a7..0000000000000 --- a/frame/staking/fuzzer/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "pallet-staking-fuzz" -version = "0.0.0" -authors = ["Automatically generated"] -publish = false -edition = "2018" -license = "Apache-2.0" -homepage = "https://substrate.dev" -repository = "https://github.com/paritytech/substrate/" -description = "FRAME pallet staking fuzzing" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -honggfuzz = "0.5" -codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false, features = ["derive"] } -pallet-staking = { version = "2.0.0", path = "..", features = ["runtime-benchmarks"] } -pallet-staking-reward-curve = { version = "2.0.0", path = "../reward-curve" } -pallet-session = { version = "2.0.0", path = "../../session" } -pallet-indices = { version = "2.0.0", path = "../../indices" } -pallet-balances = { version = "2.0.0", path = "../../balances" } -pallet-timestamp = { version = "2.0.0", path = "../../timestamp" } -frame-system = { version = "2.0.0", path = "../../system" } -frame-support = { version = "2.0.0", path = "../../support" } -sp-std = { version = "2.0.0", path = "../../../primitives/std" } -sp-io ={ version = "2.0.0", path = "../../../primitives/io" } -sp-core = { version = "2.0.0", path = "../../../primitives/core" } -sp-npos-elections = { version = "2.0.0", path = "../../../primitives/npos-elections" } -sp-runtime = { version = "2.0.0", path = "../../../primitives/runtime" } - -[[bin]] -name = "submit_solution" -path = "src/submit_solution.rs" diff --git a/frame/staking/fuzzer/src/mock.rs b/frame/staking/fuzzer/src/mock.rs deleted file mode 100644 index 6f58d6a669d7c..0000000000000 --- a/frame/staking/fuzzer/src/mock.rs +++ /dev/null @@ -1,183 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020 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 -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Mock file for staking fuzzing. - -use frame_support::{impl_outer_origin, impl_outer_dispatch, parameter_types}; - -type AccountId = u64; -type AccountIndex = u32; -type BlockNumber = u64; -type Balance = u64; - -pub type System = frame_system::Module; -pub type Balances = pallet_balances::Module; -pub type Staking = pallet_staking::Module; -pub type Indices = pallet_indices::Module; -pub type Session = pallet_session::Module; - -impl_outer_origin! { - pub enum Origin for Test where system = frame_system {} -} - -impl_outer_dispatch! { - pub enum Call for Test where origin: Origin { - staking::Staking, - } -} - -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct Test; - -impl frame_system::Config for Test { - type BaseCallFilter = (); - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type Origin = Origin; - type Index = AccountIndex; - type BlockNumber = BlockNumber; - type Call = Call; - type Hash = sp_core::H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; - type AccountId = AccountId; - type Lookup = Indices; - type Header = sp_runtime::testing::Header; - type Event = (); - type BlockHashCount = (); - type Version = (); - type PalletInfo = (); - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (Balances,); - type SystemWeightInfo = (); -} -parameter_types! { - pub const ExistentialDeposit: Balance = 10; -} -impl pallet_balances::Config for Test { - type MaxLocks = (); - type Balance = Balance; - type Event = (); - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); -} -impl pallet_indices::Config for Test { - type AccountIndex = AccountIndex; - type Event = (); - type Currency = Balances; - type Deposit = (); - type WeightInfo = (); -} -parameter_types! { - pub const MinimumPeriod: u64 = 5; -} -impl pallet_timestamp::Config for Test { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; - type WeightInfo = (); -} -impl pallet_session::historical::Config for Test { - type FullIdentification = pallet_staking::Exposure; - type FullIdentificationOf = pallet_staking::ExposureOf; -} - -sp_runtime::impl_opaque_keys! { - pub struct SessionKeys { - pub foo: sp_runtime::testing::UintAuthorityId, - } -} - -pub struct TestSessionHandler; -impl pallet_session::SessionHandler for TestSessionHandler { - const KEY_TYPE_IDS: &'static [sp_runtime::KeyTypeId] = &[]; - - fn on_genesis_session(_validators: &[(AccountId, Ks)]) {} - - fn on_new_session( - _: bool, - _: &[(AccountId, Ks)], - _: &[(AccountId, Ks)], - ) {} - - fn on_disabled(_: usize) {} -} - -impl pallet_session::Config for Test { - type SessionManager = pallet_session::historical::NoteHistoricalRoot; - type Keys = SessionKeys; - type ShouldEndSession = pallet_session::PeriodicSessions<(), ()>; - type NextSessionRotation = pallet_session::PeriodicSessions<(), ()>; - type SessionHandler = TestSessionHandler; - type Event = (); - type ValidatorId = AccountId; - type ValidatorIdOf = pallet_staking::StashOf; - type DisabledValidatorsThreshold = (); - type WeightInfo = (); -} -pallet_staking_reward_curve::build! { - const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( - min_inflation: 0_025_000, - max_inflation: 0_100_000, - ideal_stake: 0_500_000, - falloff: 0_050_000, - max_piece_count: 40, - test_precision: 0_005_000, - ); -} -parameter_types! { - pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; - pub const MaxNominatorRewardedPerValidator: u32 = 64; - pub const MaxIterations: u32 = 20; -} - -pub type Extrinsic = sp_runtime::testing::TestXt; - -impl frame_system::offchain::SendTransactionTypes for Test where - Call: From, -{ - type OverarchingCall = Call; - type Extrinsic = Extrinsic; -} - -impl pallet_staking::Config for Test { - type Currency = Balances; - type UnixTime = pallet_timestamp::Module; - type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; - type RewardRemainder = (); - type Event = (); - type Slash = (); - type Reward = (); - type SessionsPerEra = (); - type SlashDeferDuration = (); - type SlashCancelOrigin = frame_system::EnsureRoot; - type BondingDuration = (); - type SessionInterface = Self; - type RewardCurve = RewardCurve; - type NextNewSession = Session; - type ElectionLookahead = (); - type Call = Call; - type MaxIterations = MaxIterations; - type MinSolutionScoreBump = (); - type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; - type UnsignedPriority = (); - type OffchainSolutionWeightLimit = (); - type WeightInfo = (); -} diff --git a/frame/staking/fuzzer/src/submit_solution.rs b/frame/staking/fuzzer/src/submit_solution.rs deleted file mode 100644 index 4f85066f7f66a..0000000000000 --- a/frame/staking/fuzzer/src/submit_solution.rs +++ /dev/null @@ -1,182 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020 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 -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Fuzzing for staking pallet. -//! -//! HFUZZ_RUN_ARGS="-n 8" cargo hfuzz run submit_solution - -use honggfuzz::fuzz; - -use mock::Test; -use pallet_staking::testing_utils::*; -use frame_support::{assert_ok, storage::StorageValue, traits::UnfilteredDispatchable}; -use frame_system::RawOrigin; -use sp_runtime::DispatchError; -use sp_core::offchain::{testing::TestOffchainExt, OffchainExt}; -use pallet_staking::{EraElectionStatus, ElectionStatus, Module as Staking, Call as StakingCall}; - -mod mock; - -#[repr(u32)] -#[allow(dead_code)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum Mode { - /// Initial submission. This will be rather cheap. - InitialSubmission, - /// A better submission that will replace the previous ones. This is the most expensive. - StrongerSubmission, - /// A weak submission that will be rejected. This will be rather cheap. - WeakerSubmission, -} - -pub fn new_test_ext(iterations: u32) -> sp_io::TestExternalities { - let mut ext: sp_io::TestExternalities = frame_system::GenesisConfig::default() - .build_storage::() - .map(Into::into) - .expect("Failed to create test externalities."); - - let (offchain, offchain_state) = TestOffchainExt::new(); - - let mut seed = [0u8; 32]; - seed[0..4].copy_from_slice(&iterations.to_le_bytes()); - offchain_state.write().seed = seed; - - ext.register_extension(OffchainExt::new(offchain)); - - ext -} - -fn main() { - let to_range = |x: u32, a: u32, b: u32| { - let collapsed = x % b; - if collapsed >= a { - collapsed - } else { - collapsed + a - } - }; - loop { - fuzz!(|data: (u32, u32, u32, u32, u32)| { - let (mut num_validators, mut num_nominators, mut edge_per_voter, mut to_elect, mode_u32) = data; - // always run with 5 iterations. - let mut ext = new_test_ext(5); - let mode: Mode = unsafe { std::mem::transmute(mode_u32) }; - num_validators = to_range(num_validators, 50, 1000); - num_nominators = to_range(num_nominators, 50, 2000); - edge_per_voter = to_range(edge_per_voter, 1, 16); - to_elect = to_range(to_elect, 20, num_validators); - - let do_reduce = true; - - println!("+++ instance with params {} / {} / {} / {} / {:?}({})", - num_nominators, - num_validators, - edge_per_voter, - to_elect, - mode, - mode_u32, - ); - - ext.execute_with(|| { - // initial setup - init_active_era(); - - assert_ok!(create_validators_with_nominators_for_era::( - num_validators, - num_nominators, - edge_per_voter as usize, - true, - None, - )); - - >::put(ElectionStatus::Open(1)); - assert!(>::create_stakers_snapshot().0); - - let origin = RawOrigin::Signed(create_funded_user::("fuzzer", 0, 100)); - - // stuff to submit - let (winners, compact, score, size) = match mode { - Mode::InitialSubmission => { - // No need to setup anything - get_seq_phragmen_solution::(do_reduce) - }, - Mode::StrongerSubmission => { - let (winners, compact, score, size) = get_weak_solution::(false); - println!("Weak on chain score = {:?}", score); - assert_ok!( - >::submit_election_solution( - origin.clone().into(), - winners, - compact, - score, - current_era::(), - size, - ) - ); - get_seq_phragmen_solution::(do_reduce) - }, - Mode::WeakerSubmission => { - let (winners, compact, score, size) = get_seq_phragmen_solution::(do_reduce); - println!("Strong on chain score = {:?}", score); - assert_ok!( - >::submit_election_solution( - origin.clone().into(), - winners, - compact, - score, - current_era::(), - size, - ) - ); - get_weak_solution::(false) - } - }; - - // must have chosen correct number of winners. - assert_eq!(winners.len() as u32, >::validator_count()); - - // final call and origin - let call = StakingCall::::submit_election_solution( - winners, - compact, - score, - current_era::(), - size, - ); - - // actually submit - match mode { - Mode::WeakerSubmission => { - assert_eq!( - call.dispatch_bypass_filter(origin.into()).unwrap_err().error, - DispatchError::Module { - index: 0, - error: 16, - message: Some("OffchainElectionWeakSubmission"), - }, - ); - }, - // NOTE: so exhaustive pattern doesn't work here.. maybe some rust issue? - // or due to `#[repr(u32)]`? - Mode::InitialSubmission | Mode::StrongerSubmission => { - assert_ok!(call.dispatch_bypass_filter(origin.into())); - } - }; - }) - }); - } -} diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 0b5bc3ac79d4d..4525675f9a1bd 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -2257,7 +2257,7 @@ impl Module { fn enact_election(current_era: EraIndex) -> Option> { // TODO: Worthy to denote how exactly the accuracy is playing a role here. We could at this // point remove this generic as well, maybe it will also simplify some other stuff. - T::ElectionProvider::elect::() + T::ElectionProvider::elect() .map_err(|_| ()) .and_then(|flat_supports| Self::process_election(flat_supports, current_era)) .ok() diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 4f2cc90f4ec68..a57bb0a47f07b 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -253,6 +253,7 @@ impl OnUnbalanced> for RewardRemainderMock { impl onchain::Config for Test { type AccountId = AccountId; type BlockNumber = BlockNumber; + type Accuracy = Perbill; type DataProvider = Staking; } impl Config for Test { diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 760834f6b989e..7fc58f1d4922f 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1817,7 +1817,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election() { // winners should be 21 and 31. Otherwise this election is taking duplicates into // account. - let election_result = ::ElectionProvider::elect::().unwrap(); + let election_result = ::ElectionProvider::elect().unwrap(); assert_eq_uvec!( election_result, @@ -1864,7 +1864,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election_elected() { assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31])); // winners should be 21 and 31. Otherwise this election is taking duplicates into account. - let election_result = ::ElectionProvider::elect::().unwrap(); + let election_result = ::ElectionProvider::elect().unwrap(); assert_eq_uvec!( election_result, diff --git a/primitives/npos-elections/compact/src/lib.rs b/primitives/npos-elections/compact/src/lib.rs index 48136f25c7f82..9874255689eb0 100644 --- a/primitives/npos-elections/compact/src/lib.rs +++ b/primitives/npos-elections/compact/src/lib.rs @@ -177,7 +177,7 @@ fn struct_def( const LIMIT: usize = #count; type Voter = #voter_type; type Target = #target_type; - type VoteWeight = #weight_type; + type Accuracy = #weight_type; fn voters_count(&self) -> usize { let mut all_len = 0usize; diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 634c5541a6b54..3c4695e846e6b 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -144,11 +144,11 @@ pub trait CompactSolution: Sized { /// The target type type Target: UniqueSaturatedInto + TryInto + TryFrom + Debug + Copy + Clone; - /// The weight type of each vote. - type VoteWeight: PerThing128; + /// The weight/accuracy type of each vote. + type Accuracy: PerThing128; fn from_assignment( - assignments: Vec>, + assignments: Vec>, voter_index: FV, target_index: FT, ) -> Result @@ -161,7 +161,7 @@ pub trait CompactSolution: Sized { self, voter_at: impl Fn(Self::Voter) -> Option, target_at: impl Fn(Self::Target) -> Option, - ) -> Result>, Error>; + ) -> Result>, Error>; /// Get the length of all the assignments that this type is encoding. /// @@ -211,7 +211,7 @@ pub trait CompactSolution: Sized { where for<'r> FS: Fn(&'r A) -> VoteWeight, A: IdentifierT, - ExtendedBalance: From>, + ExtendedBalance: From>, { let ratio = self.into_assignment(voter_at, target_at)?; let staked = helpers::assignment_ratio_to_staked_normalized(ratio, stake_of)?; From 9663fea89c7fc914dd9d8dbc909549e5bdb79a0f Mon Sep 17 00:00:00 2001 From: kianenigma Date: Mon, 4 Jan 2021 15:33:34 +0000 Subject: [PATCH 30/62] make the staking api better and well tested. --- frame/babe/src/lib.rs | 4 + frame/election-providers/Cargo.toml | 1 + .../src/two_phase/benchmarking.rs | 42 +- .../election-providers/src/two_phase/mock.rs | 5 +- frame/election-providers/src/two_phase/mod.rs | 154 ++++---- .../src/two_phase/unsigned.rs | 360 ++++++++++-------- .../src/two_phase/weights.rs | 183 +++++++++ frame/session/src/lib.rs | 15 +- frame/staking/Cargo.toml | 2 + frame/staking/src/lib.rs | 106 ++++-- frame/staking/src/mock.rs | 2 +- frame/staking/src/tests.rs | 200 +++++----- frame/support/src/traits.rs | 65 ++-- primitives/election-providers/Cargo.toml | 1 + primitives/election-providers/src/lib.rs | 15 +- 15 files changed, 750 insertions(+), 405 deletions(-) create mode 100644 frame/election-providers/src/two_phase/weights.rs diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 9c229c297e498..3e84ebf22a821 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -695,6 +695,10 @@ impl OnTimestampSet for Module { } impl frame_support::traits::EstimateNextSessionRotation for Module { + fn average_session_length() -> T::BlockNumber { + T::EpochDuration::get().saturated_into() + } + fn estimate_next_session_rotation(now: T::BlockNumber) -> Option { Self::next_expected_epoch_change(now) } diff --git a/frame/election-providers/Cargo.toml b/frame/election-providers/Cargo.toml index e90c90d11e2bf..ddd40f986bb59 100644 --- a/frame/election-providers/Cargo.toml +++ b/frame/election-providers/Cargo.toml @@ -42,6 +42,7 @@ parking_lot = "0.10.2" sp-tracing = { version = "2.0.0", path = "../../primitives/tracing" } rand = { version = "0.7.3" } frame-benchmarking = { path = "../benchmarking" } +sp-election-providers = { version = "2.0.0", features = ["runtime-benchmarks"], path = "../../primitives/election-providers" } [features] diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index 3efb4e48476a6..9979dae6ba301 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -34,8 +34,6 @@ const SEED: u32 = 0; /// Creates a **valid** solution with exactly the given size. /// /// The snapshot is also created internally. -/// -/// The snapshot size must be bigger, otherwise this will panic. fn solution_with_size( witness: WitnessData, active_voters_count: u32, @@ -117,6 +115,7 @@ where voters: all_voters.clone(), targets: targets.clone(), }); + T::DataProvider::put_npos_snapshot(all_voters.clone(), targets.clone()); let stake_of = crate::stake_of_fn!(all_voters, T::AccountId); let voter_index = crate::voter_index_fn!(all_voters, T::AccountId, T); @@ -165,54 +164,63 @@ benchmarks! { assert!(>::current_phase().is_off()); } - on_initialize_open_signed_phase { + on_initialize_open_signed { // NOTE: this benchmark currently doesn't have any components because the length of a db // read/write is not captured. Otherwise, it is quite influenced by how much data // `T::ElectionDataProvider` is reading and passing on. assert!(>::snapshot().is_none()); assert!(>::current_phase().is_off()); - let next_election = T::DataProvider::next_election_prediction(1u32.into()); - - let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); - let unsigned_deadline = T::UnsignedPhase::get(); }: { - >::on_initialize(next_election - signed_deadline + 1u32.into()); + >::on_initialize_open_signed(); } verify { assert!(>::snapshot().is_some()); assert!(>::current_phase().is_signed()); } + on_initialize_open_unsigned { + assert!(>::snapshot().is_none()); + assert!(>::current_phase().is_off()); + }: { + >::on_initialize_open_unsigned(Phase::Off, 1u32.into()); + } verify { + assert!(>::snapshot().is_some()); + assert!(>::current_phase().is_unsigned()); + } + finalize_signed_phase_accept_solution { let receiver = account("receiver", 0, SEED); - T::Currency::make_free_balance_be(&receiver, 100u32.into()); + let initial_balance = T::Currency::minimum_balance() * 10u32.into(); + T::Currency::make_free_balance_be(&receiver, initial_balance); let ready: ReadySolution = Default::default(); let deposit: BalanceOf = 10u32.into(); let reward: BalanceOf = 20u32.into(); assert_ok!(T::Currency::reserve(&receiver, deposit)); - assert_eq!(T::Currency::free_balance(&receiver), 90u32.into()); + assert_eq!(T::Currency::free_balance(&receiver), initial_balance - 10u32.into()); }: { >::finalize_signed_phase_accept_solution(ready, &receiver, deposit, reward) } verify { - assert_eq!(T::Currency::free_balance(&receiver), 120u32.into()); + assert_eq!(T::Currency::free_balance(&receiver), initial_balance + 20u32.into()); assert_eq!(T::Currency::reserved_balance(&receiver), 0u32.into()); } finalize_signed_phase_reject_solution { let receiver = account("receiver", 0, SEED); + let initial_balance = T::Currency::minimum_balance() * 10u32.into(); let deposit: BalanceOf = 10u32.into(); - T::Currency::make_free_balance_be(&receiver, 100u32.into()); + T::Currency::make_free_balance_be(&receiver, initial_balance); assert_ok!(T::Currency::reserve(&receiver, deposit)); - assert_eq!(T::Currency::free_balance(&receiver), 90u32.into()); + assert_eq!(T::Currency::free_balance(&receiver), initial_balance - 10u32.into()); assert_eq!(T::Currency::reserved_balance(&receiver), 10u32.into()); }: { >::finalize_signed_phase_reject_solution(&receiver, deposit) } verify { - assert_eq!(T::Currency::free_balance(&receiver), 90u32.into()); + assert_eq!(T::Currency::free_balance(&receiver), initial_balance - 10u32.into()); assert_eq!(T::Currency::reserved_balance(&receiver), 0u32.into()); } + #[extra] create_snapshot { assert!(>::snapshot().is_none()); }: { @@ -311,7 +319,11 @@ mod test { }); ExtBuilder::default().build_and_execute(|| { - assert_ok!(test_benchmark_on_initialize_open_signed_phase::()); + assert_ok!(test_benchmark_on_initialize_open_signed::()); + }); + + ExtBuilder::default().build_and_execute(|| { + assert_ok!(test_benchmark_on_initialize_open_unsigned::()); }); ExtBuilder::default().build_and_execute(|| { diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 6b0644287f1ab..aa0ac5d315674 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -161,8 +161,11 @@ impl frame_system::Config for Runtime { type SystemWeightInfo = (); } +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); parameter_types! { pub const ExistentialDeposit: u64 = 1; + pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights + ::with_sensible_defaults(2 * frame_support::weights::constants::WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); } impl pallet_balances::Config for Runtime { @@ -201,7 +204,7 @@ parameter_types! { pub static MinerMaxIterations: u32 = 5; pub static UnsignedPriority: u64 = 100; pub static SolutionImprovementThreshold: Perbill = Perbill::zero(); - pub static MinerMaxWeight: Weight = 128; + pub static MinerMaxWeight: Weight = BlockWeights::get().max_block; pub static EpochLength: u64 = 30; } diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 1da3b0808fc0a..fe38dd8f73e8f 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -186,6 +186,9 @@ pub(crate) mod macros; pub mod signed; pub mod unsigned; +pub mod weights; + +use weights::WeightInfo; /// The compact solution type used by this crate. pub type CompactOf = ::CompactSolution; @@ -441,6 +444,8 @@ pub enum FeasibilityError { InvalidWinner, /// The given score was invalid. InvalidScore, + /// An error from the data provider's feasibility check + DataProvider(&'static str), } impl From for FeasibilityError { @@ -449,44 +454,6 @@ impl From for FeasibilityError { } } -pub trait WeightInfo { - fn on_initialize_nothing() -> Weight; - fn on_initialize_open_signed_phase() -> Weight; - fn finalize_signed_phase_accept_solution() -> Weight; - fn finalize_signed_phase_reject_solution() -> Weight; - fn create_snapshot() -> Weight; - fn feasibility_check(v: u32, t: u32, a: u32, d: u32) -> Weight; - fn submit(c: u32) -> Weight; - fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight; -} - -impl WeightInfo for () { - fn feasibility_check(_: u32, _: u32, _: u32, _: u32) -> Weight { - Default::default() - } - fn submit(_: u32) -> Weight { - Default::default() - } - fn submit_unsigned(_: u32, _: u32, _: u32, _: u32) -> Weight { - Default::default() - } - fn on_initialize_nothing() -> Weight { - Default::default() - } - fn on_initialize_open_signed_phase() -> Weight { - Default::default() - } - fn create_snapshot() -> Weight { - Default::default() - } - fn finalize_signed_phase_accept_solution() -> Weight { - Default::default() - } - fn finalize_signed_phase_reject_solution() -> Weight { - Default::default() - } -} - pub trait Config: frame_system::Config + SendTransactionTypes> where ExtendedBalance: From>>, @@ -648,41 +615,20 @@ decl_module! { let remaining = next_election - now; let current_phase = Self::current_phase(); + match current_phase { Phase::Off if remaining <= signed_deadline && remaining > unsigned_deadline => { - >::put(Phase::Signed); - Self::create_snapshot(); - - Self::deposit_event(RawEvent::SignedPhaseStarted(Self::round())); + Self::on_initialize_open_signed(); log!(info, "Starting signed phase at #{:?} , round {}.", now, Self::round()); - - T::WeightInfo::on_initialize_open_signed_phase() + T::WeightInfo::on_initialize_open_signed() }, Phase::Signed | Phase::Off if remaining <= unsigned_deadline && remaining > 0u32.into() => { - let mut consumed_weight: Weight = 0; - if current_phase == Phase::Off { - // if not being followed by a signed phase, then create the snapshots. - debug_assert!(Self::snapshot().is_none()); - Self::create_snapshot(); - consumed_weight = consumed_weight.saturating_add(T::WeightInfo::create_snapshot()); - } else { - // if followed by a signed phase, then finalize the signed stuff. - debug_assert!(Self::signed_submissions().is_empty()); - } - - // noop if no signed phase has been open - let (_, weight) = Self::finalize_signed_phase(); - consumed_weight = consumed_weight.saturating_add(weight); - - // for now always start the unsigned phase. - >::put(Phase::Unsigned((true, now))); - Self::deposit_event(RawEvent::UnsignedPhaseStarted(Self::round())); - + let additional = Self::on_initialize_open_unsigned(current_phase, now); log!(info, "Starting unsigned phase at #{:?}.", now); - consumed_weight + T::WeightInfo::on_initialize_open_signed().saturating_add(additional) }, _ => { - Zero::zero() + T::WeightInfo::on_initialize_nothing() } } } @@ -802,6 +748,43 @@ where ExtendedBalance: From>>, ExtendedBalance: From>>, { + /// Logic for [`Module::on_initialize`] when signed phase is being opened. + /// + /// This is decoupled for easy weight calculation. + pub fn on_initialize_open_signed() { + >::put(Phase::Signed); + Self::create_snapshot(); + Self::deposit_event(RawEvent::SignedPhaseStarted(Self::round())); + } + + /// Logic for [`Module::on_initialize`] when unsigned phase is being opened. + /// + /// This is decoupled for easy weight calculation. Note that the default weight benchmark of + /// this function will assume an empty signed queue for `finalize_signed_phase`. + pub fn on_initialize_open_unsigned( + current_phase: Phase, + now: T::BlockNumber, + ) -> Weight { + if current_phase == Phase::Off { + // if not being followed by a signed phase, then create the snapshots. + debug_assert!(Self::snapshot().is_none()); + Self::create_snapshot(); + } else { + // if followed by a signed phase, then finalize the signed stuff. + debug_assert!(Self::signed_submissions().is_empty()); + } + + // noop if no signed phase has been open. NOTE: benchmarks assume this is noop, we return + //additional weight manually. + let (_, additional_weight) = Self::finalize_signed_phase(); + + // for now always start the unsigned phase. + >::put(Phase::Unsigned((true, now))); + Self::deposit_event(RawEvent::UnsignedPhaseStarted(Self::round())); + + additional_weight + } + /// Creates the snapshot. Writes new data to: /// /// 1. [`SnapshotMetadata`] @@ -890,39 +873,32 @@ where .map(|i| target_at(i).ok_or(FeasibilityError::InvalidWinner)) .collect::, FeasibilityError>>()?; - // Then convert compact -> Assignment. + // Then convert compact -> Assignment. This will fail if any of the indices are gibberish. let assignments = compact .into_assignment(voter_at, target_at) .map_err::(Into::into)?; - // Ensure that assignments is correct. We perform two checks: 1. local match against the - // given snapshot, and check with the `ElectionDataProvider`. + // Ensure that assignments is correct. let _ = assignments .iter() .map(|ref assignment| { - // TODO: better to rewrite this more with ? - snapshot_voters + // check that assignment.who is actually a voter. + let (_voter, _stake, targets) = snapshot_voters .iter() .find(|(v, _, _)| v == &assignment.who) - .map_or( - Err(FeasibilityError::InvalidVoter), - |(_voter, _stake, targets)| { - if assignment - .distribution - .iter() - .map(|(d, _)| d) - .all(|d| targets.contains(d)) - && T::DataProvider::feasibility_check_assignment::< - CompactAccuracyOf, - >(assignment) - .is_ok() - { - Ok(()) - } else { - Err(FeasibilityError::InvalidVote) - } - }, - ) + .ok_or(FeasibilityError::InvalidVoter)?; + // check that all of the targets are valid based on the snapshot. + if !assignment + .distribution + .iter() + .all(|(d, _)| targets.contains(d)) + { + return Err(FeasibilityError::InvalidVote); + } + // check the feasibility based on the data provider + T::DataProvider::feasibility_check_assignment::>(assignment) + .map_err(|r| FeasibilityError::DataProvider(r))?; + Ok(()) }) .collect::>()?; diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 3e88809944649..35036cc8915de 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -98,8 +98,11 @@ where voters: voters.len() as u32, targets: targets.len() as u32, }; - let maximum_allowed_voters = - Self::maximum_compact_len::(desired_targets, witness, T::MinerMaxWeight::get()); + let maximum_allowed_voters = Self::maximum_voter_for_weight::( + desired_targets, + witness, + T::MinerMaxWeight::get(), + ); let compact = Self::trim_compact(maximum_allowed_voters, compact, &voter_index)?; // re-calc score. @@ -191,7 +194,7 @@ where /// Find the maximum `len` that a compact can have in order to fit into the block weight. /// /// This only returns a value between zero and `size.nominators`. - pub fn maximum_compact_len( + pub fn maximum_voter_for_weight( desired_winners: u32, witness: WitnessData, max_weight: Weight, @@ -403,152 +406,211 @@ fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { InvalidTransaction::Custom(error_number) } -// #[cfg(test)] -// mod test { -// #![allow(unused_variables)] -// use super::*; -// use crate::ElectionSize; - -// struct Staking; - -// impl crate::WeightInfo for Staking { -// fn bond() -> Weight { -// unimplemented!() -// } -// fn bond_extra() -> Weight { -// unimplemented!() -// } -// fn unbond() -> Weight { -// unimplemented!() -// } -// fn withdraw_unbonded_update(s: u32) -> Weight { -// unimplemented!() -// } -// fn withdraw_unbonded_kill(s: u32) -> Weight { -// unimplemented!() -// } -// fn validate() -> Weight { -// unimplemented!() -// } -// fn nominate(n: u32) -> Weight { -// unimplemented!() -// } -// fn chill() -> Weight { -// unimplemented!() -// } -// fn set_payee() -> Weight { -// unimplemented!() -// } -// fn set_controller() -> Weight { -// unimplemented!() -// } -// fn set_validator_count() -> Weight { -// unimplemented!() -// } -// fn force_no_eras() -> Weight { -// unimplemented!() -// } -// fn force_new_era() -> Weight { -// unimplemented!() -// } -// fn force_new_era_always() -> Weight { -// unimplemented!() -// } -// fn set_invulnerables(v: u32) -> Weight { -// unimplemented!() -// } -// fn force_unstake(s: u32) -> Weight { -// unimplemented!() -// } -// fn cancel_deferred_slash(s: u32) -> Weight { -// unimplemented!() -// } -// fn payout_stakers_dead_controller(n: u32) -> Weight { -// unimplemented!() -// } -// fn payout_stakers_alive_staked(n: u32) -> Weight { -// unimplemented!() -// } -// fn rebond(l: u32) -> Weight { -// unimplemented!() -// } -// fn set_history_depth(e: u32) -> Weight { -// unimplemented!() -// } -// fn reap_stash(s: u32) -> Weight { -// unimplemented!() -// } -// fn new_era(v: u32, n: u32) -> Weight { -// unimplemented!() -// } -// fn submit_solution_better(v: u32, n: u32, a: u32, w: u32) -> Weight { -// (0 * v + 0 * n + 1000 * a + 0 * w) as Weight -// } -// } - -// #[test] -// fn find_max_voter_binary_search_works() { -// let size = ElectionSize { -// validators: 0, -// nominators: 10, -// }; - -// assert_eq!(maximum_compact_len::(0, size, 0), 0); -// assert_eq!(maximum_compact_len::(0, size, 1), 0); -// assert_eq!(maximum_compact_len::(0, size, 999), 0); -// assert_eq!(maximum_compact_len::(0, size, 1000), 1); -// assert_eq!(maximum_compact_len::(0, size, 1001), 1); -// assert_eq!(maximum_compact_len::(0, size, 1990), 1); -// assert_eq!(maximum_compact_len::(0, size, 1999), 1); -// assert_eq!(maximum_compact_len::(0, size, 2000), 2); -// assert_eq!(maximum_compact_len::(0, size, 2001), 2); -// assert_eq!(maximum_compact_len::(0, size, 2010), 2); -// assert_eq!(maximum_compact_len::(0, size, 2990), 2); -// assert_eq!(maximum_compact_len::(0, size, 2999), 2); -// assert_eq!(maximum_compact_len::(0, size, 3000), 3); -// assert_eq!(maximum_compact_len::(0, size, 3333), 3); -// assert_eq!(maximum_compact_len::(0, size, 5500), 5); -// assert_eq!(maximum_compact_len::(0, size, 7777), 7); -// assert_eq!(maximum_compact_len::(0, size, 9999), 9); -// assert_eq!(maximum_compact_len::(0, size, 10_000), 10); -// assert_eq!(maximum_compact_len::(0, size, 10_999), 10); -// assert_eq!(maximum_compact_len::(0, size, 11_000), 10); -// assert_eq!(maximum_compact_len::(0, size, 22_000), 10); - -// let size = ElectionSize { -// validators: 0, -// nominators: 1, -// }; - -// assert_eq!(maximum_compact_len::(0, size, 0), 0); -// assert_eq!(maximum_compact_len::(0, size, 1), 0); -// assert_eq!(maximum_compact_len::(0, size, 999), 0); -// assert_eq!(maximum_compact_len::(0, size, 1000), 1); -// assert_eq!(maximum_compact_len::(0, size, 1001), 1); -// assert_eq!(maximum_compact_len::(0, size, 1990), 1); -// assert_eq!(maximum_compact_len::(0, size, 1999), 1); -// assert_eq!(maximum_compact_len::(0, size, 2000), 1); -// assert_eq!(maximum_compact_len::(0, size, 2001), 1); -// assert_eq!(maximum_compact_len::(0, size, 2010), 1); -// assert_eq!(maximum_compact_len::(0, size, 3333), 1); - -// let size = ElectionSize { -// validators: 0, -// nominators: 2, -// }; - -// assert_eq!(maximum_compact_len::(0, size, 0), 0); -// assert_eq!(maximum_compact_len::(0, size, 1), 0); -// assert_eq!(maximum_compact_len::(0, size, 999), 0); -// assert_eq!(maximum_compact_len::(0, size, 1000), 1); -// assert_eq!(maximum_compact_len::(0, size, 1001), 1); -// assert_eq!(maximum_compact_len::(0, size, 1999), 1); -// assert_eq!(maximum_compact_len::(0, size, 2000), 2); -// assert_eq!(maximum_compact_len::(0, size, 2001), 2); -// assert_eq!(maximum_compact_len::(0, size, 2010), 2); -// assert_eq!(maximum_compact_len::(0, size, 3333), 2); -// } -// } +#[cfg(test)] +mod max_weight { + #![allow(unused_variables)] + use super::*; + use mock::*; + + struct TestWeight; + impl crate::two_phase::weights::WeightInfo for TestWeight { + fn on_initialize_nothing() -> Weight { + unreachable!() + } + fn on_initialize_open_signed() -> Weight { + unreachable!() + } + fn on_initialize_open_unsigned() -> Weight { + unreachable!() + } + fn finalize_signed_phase_accept_solution() -> Weight { + unreachable!() + } + fn finalize_signed_phase_reject_solution() -> Weight { + unreachable!() + } + fn submit(c: u32) -> Weight { + unreachable!() + } + fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight { + (0 * v + 0 * t + 1000 * a + 0 * d) as Weight + } + fn feasibility_check(v: u32, _t: u32, a: u32, d: u32) -> Weight { + unreachable!() + } + } + + #[test] + fn find_max_voter_binary_search_works() { + let w = WitnessData { + voters: 10, + targets: 0, + }; + + assert_eq!(TwoPhase::maximum_voter_for_weight::(0, w, 0), 0); + assert_eq!(TwoPhase::maximum_voter_for_weight::(0, w, 1), 0); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 999), + 0 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 1000), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 1001), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 1990), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 1999), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 2000), + 2 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 2001), + 2 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 2010), + 2 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 2990), + 2 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 2999), + 2 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 3000), + 3 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 3333), + 3 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 5500), + 5 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 7777), + 7 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 9999), + 9 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 10_000), + 10 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 10_999), + 10 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 11_000), + 10 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 22_000), + 10 + ); + + let w = WitnessData { + voters: 1, + targets: 0, + }; + + assert_eq!(TwoPhase::maximum_voter_for_weight::(0, w, 0), 0); + assert_eq!(TwoPhase::maximum_voter_for_weight::(0, w, 1), 0); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 999), + 0 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 1000), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 1001), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 1990), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 1999), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 2000), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 2001), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 2010), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 3333), + 1 + ); + + let w = WitnessData { + voters: 2, + targets: 0, + }; + + assert_eq!(TwoPhase::maximum_voter_for_weight::(0, w, 0), 0); + assert_eq!(TwoPhase::maximum_voter_for_weight::(0, w, 1), 0); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 999), + 0 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 1000), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 1001), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 1999), + 1 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 2000), + 2 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 2001), + 2 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 2010), + 2 + ); + assert_eq!( + TwoPhase::maximum_voter_for_weight::(0, w, 3333), + 2 + ); + } +} #[cfg(test)] mod tests { diff --git a/frame/election-providers/src/two_phase/weights.rs b/frame/election-providers/src/two_phase/weights.rs new file mode 100644 index 0000000000000..58c9aa1d0aa2e --- /dev/null +++ b/frame/election-providers/src/two_phase/weights.rs @@ -0,0 +1,183 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_two_phase_election_provider +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 +//! DATE: 2020-12-29, STEPS: [10, ], REPEAT: 5, LOW RANGE: [], HIGH RANGE: [] +//! EXECUTION: Some(Native), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// target/release/substrate +// benchmark +// --chain +// dev +// --steps +// 10 +// --repeat +// 5 +// --extrinsic +// * +// --execution=native +// --wasm-execution=compiled +// --output +// . +// --header +// ./HEADER +// --pallet +// pallet_two_phase_election_provider +// --template=./.maintain/frame-weight-template.hbs + +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_two_phase_election_provider. +pub trait WeightInfo { + fn on_initialize_nothing() -> Weight; + fn on_initialize_open_signed() -> Weight; + fn on_initialize_open_unsigned() -> Weight; + fn finalize_signed_phase_accept_solution() -> Weight; + fn finalize_signed_phase_reject_solution() -> Weight; + fn submit(c: u32) -> Weight; + fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight; + fn feasibility_check(v: u32, t: u32, a: u32, d: u32) -> Weight; +} + +/// Weights for pallet_two_phase_election_provider using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn on_initialize_nothing() -> Weight { + (32_000_000 as Weight).saturating_add(T::DbWeight::get().reads(7 as Weight)) + } + fn on_initialize_open_signed() -> Weight { + (103_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + fn on_initialize_open_unsigned() -> Weight { + (107_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(8 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) + } + fn finalize_signed_phase_accept_solution() -> Weight { + (38_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + } + fn finalize_signed_phase_reject_solution() -> Weight { + (16_000_000 as Weight) + .saturating_add(T::DbWeight::get().reads(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + fn submit(c: u32) -> Weight { + (57_926_000 as Weight) + // Standard Error: 153_000 + .saturating_add((1_267_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32) -> Weight { + (260_195_000 as Weight) + // Standard Error: 1_138_000 + .saturating_add((872_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 1_138_000 + .saturating_add((37_162_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 5_690_000 + .saturating_add((18_018_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(d as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + } + fn feasibility_check(v: u32, _t: u32, a: u32, d: u32) -> Weight { + (1_819_529_000 as Weight) + // Standard Error: 1_260_000 + .saturating_add((1_051_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 2_100_000 + .saturating_add((21_722_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 4_201_000 + .saturating_add((10_227_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(T::DbWeight::get().reads(2 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(d as Weight))) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn on_initialize_nothing() -> Weight { + (32_000_000 as Weight).saturating_add(RocksDbWeight::get().reads(7 as Weight)) + } + fn on_initialize_open_signed() -> Weight { + (103_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + fn on_initialize_open_unsigned() -> Weight { + (107_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(8 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + } + fn finalize_signed_phase_accept_solution() -> Weight { + (38_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + } + fn finalize_signed_phase_reject_solution() -> Weight { + (16_000_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + fn submit(c: u32) -> Weight { + (57_926_000 as Weight) + // Standard Error: 153_000 + .saturating_add((1_267_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32) -> Weight { + (260_195_000 as Weight) + // Standard Error: 1_138_000 + .saturating_add((872_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 1_138_000 + .saturating_add((37_162_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 5_690_000 + .saturating_add((18_018_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(d as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + } + fn feasibility_check(v: u32, _t: u32, a: u32, d: u32) -> Weight { + (1_819_529_000 as Weight) + // Standard Error: 1_260_000 + .saturating_add((1_051_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 2_100_000 + .saturating_add((21_722_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 4_201_000 + .saturating_add((10_227_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(RocksDbWeight::get().reads(2 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(d as Weight))) + } +} diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 0df6240b27826..eefdf66dd70f5 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -164,12 +164,15 @@ impl< + PartialOrd + Saturating + Clone - + From // TODO: remove these + sp_std::fmt::Debug, Period: Get, Offset: Get, > EstimateNextSessionRotation for PeriodicSessions { + fn average_session_length() -> BlockNumber { + Period::get() + } + fn estimate_next_session_rotation(now: BlockNumber) -> Option { let offset = Offset::get(); let period = Period::get(); @@ -180,7 +183,11 @@ impl< period.saturating_sub(block_after_last_session) ) } else { - now + // this branch happens when the session is already rotated or will rotate in this + // block (depending on being called before or after `session::on_initialize`). Here, + // we assume the latter, namely that this is called after `session::on_initialize`, + // and thus we add period to it as well. + now + period } } else { offset @@ -859,6 +866,10 @@ impl EstimateNextNewSession for Module { T::NextSessionRotation::estimate_next_session_rotation(now) } + fn average_session_length() -> T::BlockNumber { + T::NextSessionRotation::average_session_length() + } + fn weight(now: T::BlockNumber) -> Weight { T::NextSessionRotation::weight(now) } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 7ade07dfc4fa3..2523696cabccf 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -43,6 +43,7 @@ frame-election-providers = { version = "2.0.0", path = "../election-providers" } pallet-staking-reward-curve = { version = "2.0.0", path = "../staking/reward-curve" } substrate-test-utils = { version = "2.0.0", path = "../../test-utils" } frame-benchmarking = { version = "2.0.0", path = "../benchmarking" } +sp-election-providers = { version = "2.0.0", features = ["runtime-benchmarks"], path = "../../primitives/election-providers" } rand_chacha = { version = "0.2" } parking_lot = "0.10.2" hex = "0.4" @@ -66,5 +67,6 @@ std = [ ] runtime-benchmarks = [ "frame-benchmarking", + "sp-election-providers/runtime-benchmarks", "rand_chacha", ] diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 4525675f9a1bd..25602c5d93bbc 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -683,8 +683,6 @@ pub trait SessionInterface: frame_system::Config { fn validators() -> Vec; /// Prune historical session tries up to but not including the given index. fn prune_historical_up_to(up_to: SessionIndex); - /// The current session index. - fn current_index() -> SessionIndex; } impl SessionInterface<::AccountId> for T @@ -709,10 +707,6 @@ where >::validators() } - fn current_index() -> SessionIndex { - >::current_index() - } - fn prune_historical_up_to(up_to: SessionIndex) { >::prune_up_to(up_to); } @@ -945,6 +939,12 @@ decl_storage! { /// The earliest era for which we have a pending, unapplied slash. EarliestUnappliedSlash: Option; + /// The last planned session scheduled by the session pallet. + /// + /// This is basically in sync with the call to [`SessionManager::new_session`]. + /// TODO: needs care to set the initial value upon migration. + pub CurrentPlannedSession get(fn current_planned_session): SessionIndex; + // TODO: removed storage items: // IsCurrentSessionFinal // EraElectionStatus @@ -2255,10 +2255,16 @@ impl Module { /// /// This will also process the election, as noted in [`process_election`]. fn enact_election(current_era: EraIndex) -> Option> { - // TODO: Worthy to denote how exactly the accuracy is playing a role here. We could at this - // point remove this generic as well, maybe it will also simplify some other stuff. T::ElectionProvider::elect() - .map_err(|_| ()) + .map_err(|err| { + log!( + error, + "enacting new validator set at the end of era {} failed due to {:?}", + current_era, + err, + ); + () + }) .and_then(|flat_supports| Self::process_election(flat_supports, current_era)) .ok() } @@ -2426,33 +2432,80 @@ impl ElectionDataProvider for Module fn next_election_prediction(now: T::BlockNumber) -> T::BlockNumber { let current_era = Self::current_era().unwrap_or(0); - // Note: this happens after the on_initialize of the session module, therefore, this is the - // updated session index in the border cases. - let session_index = T::SessionInterface::current_index(); + let current_session = Self::current_planned_session(); let current_era_start_session_index = Self::eras_start_session_index(current_era).unwrap_or(0); - let era_length = session_index + let era_length = current_session .saturating_sub(current_era_start_session_index) .min(T::SessionsPerEra::get()); - // TODO: this is probably an ugly hack here and can be re-done. - // TODO: cases to consider: session length = 1, session length > 1, - let session_length = T::NextNewSession::estimate_next_new_session(1u32.into()) - .unwrap_or(0u32.into()) - .max(1u32.into()); - - let this_session_end = T::NextNewSession::estimate_next_new_session(now) - .unwrap_or_default(); + + let session_length = T::NextNewSession::average_session_length(); + + // TODO: consider removing the `now` here, does not serve much. + let until_this_session_end = T::NextNewSession::estimate_next_new_session(now) + .unwrap_or_default() + .saturating_sub(now); + let sessions_left: T::BlockNumber = T::SessionsPerEra::get() .saturating_sub(era_length) - .saturating_sub(1) // one session is computed in this_session_end. + // one session is computed in this_session_end. + .saturating_sub(1) .into(); - this_session_end.saturating_add(sessions_left.saturating_mul(session_length)) + now.saturating_add( + until_this_session_end.saturating_add(sessions_left.saturating_mul(session_length)), + ) } - fn feasibility_check_assignment(_: &Assignment) -> Result<(), &'static str> { - // TODO - Ok(()) + fn feasibility_check_assignment( + assignment: &Assignment, + ) -> Result<(), &'static str> { + if let Some(nomination) = Self::nominators(&assignment.who) { + if assignment.distribution.iter().all(|(t, _)| { + Self::slashing_spans(t).map_or(true, |spans| { + nomination.submitted_in >= spans.last_nonzero_slash() + }) + }) { + Ok(()) + } else { + Err("Slashed distribution.") + } + } else if >::contains_key(&assignment.who) { + // validators can self-vote in any case if they want to. NOTE: self vote itself is + // checked by the election provider module, because we inject the self vote. + Ok(()) + } else { + sp_std::if_std! { + dbg!(assignment); + } + Err("Unknown assignment") + } + } + + #[cfg(any(feature = "runtime-benchmarks", test))] + fn put_npos_snapshot( + voters: Vec<(T::AccountId, VoteWeight, Vec)>, + targets: Vec, + ) { + targets.into_iter().for_each(|v| { + >::insert( + v, + ValidatorPrefs { + commission: Perbill::zero(), + }, + ); + }); + + voters.into_iter().for_each(|(v, _s, t)| { + >::insert( + v, + Nominations { + targets: t, + submitted_in: 0, + suppressed: false, + }, + ); + }); } } @@ -2469,6 +2522,7 @@ impl pallet_session::SessionManager for Module { >::block_number(), new_index ); + CurrentPlannedSession::put(new_index); Self::new_session(new_index) } fn start_session(start_index: SessionIndex) { diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index a57bb0a47f07b..fc3985d5e3a98 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -769,7 +769,7 @@ pub(crate) fn add_slash(who: &AccountId) { on_offence_now( &[ OffenceDetails { - offender: (who.clone(), Staking::eras_stakers(Staking::active_era().unwrap().index, who.clone())), + offender: (who.clone(), Staking::eras_stakers(active_era(), who.clone())), reporters: vec![], }, ], diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 7fc58f1d4922f..077654c9bdc9c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -4680,39 +4680,6 @@ fn offences_weight_calculated_correctly() { }); } -// #[test] -// fn on_initialize_weight_is_correct() { -// ExtBuilder::default().has_stakers(false).build_and_execute(|| { -// assert_eq!(Validators::::iter().count(), 0); -// assert_eq!(Nominators::::iter().count(), 0); -// // When this pallet has nothing, we do 4 reads each block -// let base_weight = ::DbWeight::get().reads(4); -// assert_eq!(base_weight, Staking::on_initialize(0)); -// }); - -// ExtBuilder::default() -// .offchain_election_ext() -// .validator_count(4) -// .has_stakers(false) -// .build() -// .execute_with(|| { -// crate::tests::offchain_election::build_offchain_election_test_ext(); -// run_to_block(11); -// Staking::on_finalize(System::block_number()); -// System::set_block_number((System::block_number() + 1).into()); -// Timestamp::set_timestamp(System::block_number() * 1000 + INIT_TIMESTAMP); -// Session::on_initialize(System::block_number()); - -// assert_eq!(Validators::::iter().count(), 4); -// assert_eq!(Nominators::::iter().count(), 5); -// // With 4 validators and 5 nominator, we should increase weight by: -// // - (4 + 5) reads -// // - 3 Writes -// let final_weight = ::DbWeight::get().reads_writes(4 + 9, 3); -// assert_eq!(final_weight, Staking::on_initialize(System::block_number())); -// }); -// } - #[test] fn payout_creates_controller() { ExtBuilder::default() @@ -4958,67 +4925,106 @@ fn cannot_bond_extra_to_lower_than_ed() { }) } -// TODO: uncomment once https://github.com/paritytech/substrate/pull/7719 is merged. -// mod election_provider { -// use super::*; - -// #[test] -// fn estimate_next_election_works() { -// ExtBuilder::default() -// .session_per_era(5) -// .session_length(5) -// .build() -// .execute_with(|| { -// // TODO: prediction for the first session is incorrect. correct is 20 because of -// // first session having zero length -// assert_session_era!(0, 0); -// assert_eq!( -// Staking::next_election_prediction(System::block_number()), -// 25 -// ); - -// run_to_block(4); -// assert_session_era!(0, 0); -// assert_eq!( -// Staking::next_election_prediction(System::block_number()), -// 25 -// ); - -// run_to_block(19); -// assert_session_era!(3, 0); -// assert_eq!( -// Staking::next_election_prediction(System::block_number()), -// 25 -// ); - -// run_to_block(20); -// assert_session_era!(4, 1); -// assert_eq!( -// Staking::next_election_prediction(System::block_number()), -// 45 -// ); - -// run_to_block(21); -// assert_session_era!(4, 1); -// assert_eq!( -// Staking::next_election_prediction(System::block_number()), -// 45 -// ); - -// run_to_block(25); -// assert_eq!(System::block_number(), 25); -// assert_session_era!(5, 1); -// assert_eq!( -// Staking::next_election_prediction(System::block_number()), -// 45 -// ); - -// run_to_block(32); -// assert_session_era!(6, 1); -// assert_eq!( -// Staking::next_election_prediction(System::block_number()), -// 45 -// ); -// }) -// } -// } +mod election_data_provider { + use super::*; + use sp_election_providers::ElectionDataProvider; + + #[test] + fn voters_include_self_vote() { + ExtBuilder::default() + .nominate(false) + .build() + .execute_with(|| { + assert!(>::iter() + .map(|(x, _)| x) + .all(|v| Staking::voters() + .into_iter() + .find(|(w, _, t)| { v == *w && t[0] == *w }) + .is_some())) + }) + } + + #[test] + fn voters_exclude_slashed() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); + assert_eq!( + >::voters() + .iter() + .find(|x| x.0 == 101) + .unwrap() + .2, + vec![11, 21] + ); + + start_active_era(1); + add_slash(&11); + + // 11 is gone. + start_active_era(2); + assert_eq!( + >::voters() + .iter() + .find(|x| x.0 == 101) + .unwrap() + .2, + vec![21] + ); + + // resubmit and it is back + assert_ok!(Staking::nominate(Origin::signed(100), vec![11, 21])); + assert_eq!( + >::voters() + .iter() + .find(|x| x.0 == 101) + .unwrap() + .2, + vec![11, 21] + ); + }) + } + + #[test] + fn estimate_next_election_works() { + ExtBuilder::default() + .session_per_era(5) + .period(5) + .build() + .execute_with(|| { + // first session is always length 0. + for b in 1..20 { + run_to_block(b); + assert_eq!( + Staking::next_election_prediction(System::block_number()), + 20 + ); + } + + // election + run_to_block(20); + assert_eq!( + Staking::next_election_prediction(System::block_number()), + 45 + ); + assert_eq!(staking_events().len(), 1); + assert_eq!(*staking_events().last().unwrap(), RawEvent::StakingElection); + + for b in 21..45 { + run_to_block(b); + assert_eq!( + Staking::next_election_prediction(System::block_number()), + 45 + ); + } + + // election + run_to_block(45); + assert_eq!( + Staking::next_election_prediction(System::block_number()), + 70 + ); + assert_eq!(staking_events().len(), 3); + assert_eq!(*staking_events().last().unwrap(), RawEvent::StakingElection); + }) + } +} diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 1802c30246685..779c5bf0c0e10 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -347,22 +347,23 @@ impl Happened for () { /// be the default value), or where the account is being removed or reset back to the default value /// where previously it did exist (though may have been in a default state). This works well with /// system module's `CallOnCreatedAccount` and `CallKillAccount`. -pub struct StorageMapShim< - S, - Created, - Removed, - K, - T ->(sp_std::marker::PhantomData<(S, Created, Removed, K, T)>); +pub struct StorageMapShim( + sp_std::marker::PhantomData<(S, Created, Removed, K, T)>, +); impl< - S: StorageMap, - Created: Happened, - Removed: Happened, - K: FullCodec, - T: FullCodec, -> StoredMap for StorageMapShim { - fn get(k: &K) -> T { S::get(k) } - fn is_explicit(k: &K) -> bool { S::contains_key(k) } + S: StorageMap, + Created: Happened, + Removed: Happened, + K: FullCodec, + T: FullCodec, + > StoredMap for StorageMapShim +{ + fn get(k: &K) -> T { + S::get(k) + } + fn is_explicit(k: &K) -> bool { + S::contains_key(k) + } fn insert(k: &K, t: T) { let existed = S::contains_key(&k); S::insert(k, t); @@ -413,10 +414,16 @@ impl< } } -/// Something that can estimate at which block the next session rotation will happen. This should -/// be the same logical unit that dictates `ShouldEndSession` to the session module. No Assumptions -/// are made about the scheduling of the sessions. +/// Something that can estimate at which block the next session rotation will happen. +/// +/// This should be the same logical unit that dictates `ShouldEndSession` to the session module. No +/// Assumptions are made about the scheduling of the sessions. pub trait EstimateNextSessionRotation { + /// Return the average length of a session. + /// + /// This may or may not be accurate. + fn average_session_length() -> BlockNumber; + /// Return the block number at which the next session rotation is estimated to happen. /// /// None should be returned if the estimation fails to come to an answer @@ -426,7 +433,11 @@ pub trait EstimateNextSessionRotation { fn weight(now: BlockNumber) -> Weight; } -impl EstimateNextSessionRotation for () { +impl EstimateNextSessionRotation for () { + fn average_session_length() -> BlockNumber { + Default::default() + } + fn estimate_next_session_rotation(_: BlockNumber) -> Option { Default::default() } @@ -436,9 +447,15 @@ impl EstimateNextSessionRotation for () { } } -/// Something that can estimate at which block the next `new_session` will be triggered. This must -/// always be implemented by the session module. +/// Something that can estimate at which block the next `new_session` will be triggered. +/// +/// This must always be implemented by the session module. pub trait EstimateNextNewSession { + /// Return the average length of a session. + /// + /// This may or may not be accurate. + fn average_session_length() -> BlockNumber; + /// Return the block number at which the next new session is estimated to happen. fn estimate_next_new_session(now: BlockNumber) -> Option; @@ -446,7 +463,11 @@ pub trait EstimateNextNewSession { fn weight(now: BlockNumber) -> Weight; } -impl EstimateNextNewSession for () { +impl EstimateNextNewSession for () { + fn average_session_length() -> BlockNumber { + Default::default() + } + fn estimate_next_new_session(_: BlockNumber) -> Option { Default::default() } diff --git a/primitives/election-providers/Cargo.toml b/primitives/election-providers/Cargo.toml index bd889360776fa..c4a7c659f8e0c 100644 --- a/primitives/election-providers/Cargo.toml +++ b/primitives/election-providers/Cargo.toml @@ -20,6 +20,7 @@ sp-npos-elections = { version = "2.0.0-rc6", default-features = false, path = ". [features] default = ["std"] +runtime-benchmarks = [] std = [ "codec/std", "sp-std/std", diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index 5d6f9334c38bf..93c739d84e9fe 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -191,8 +191,8 @@ pub trait ElectionDataProvider { /// This might be called by the [`ElectionProvider`] upon processing election solutions. /// /// Note that each this must only contain checks that the [`ElectionProvider`] cannot know - /// about. Basics checks that can be known from [`Self::voters`] and [`Self::targets`] should - /// typically be done by [`ElectionProvider`]. + /// about. Basics checks that can be known from [`Self::npos_voters`] and [`Self::npos_targets`] + /// should typically be done by [`ElectionProvider`]. /// /// For example, if a pallet contains some *private* knowledge that could potentially invalidate /// an `assignment`, it should be checked here, as [`ElectionProvider`] has no way of knowing @@ -208,6 +208,15 @@ pub trait ElectionDataProvider { /// /// This is only useful for stateful election providers. fn next_election_prediction(now: BlockNumber) -> BlockNumber; + + /// Utility function only to be used in benchmarking scenarios, to be implemented optionally, + /// else a noop. + #[cfg(any(feature = "runtime-benchmarks", test))] + fn put_npos_snapshot( + _voters: Vec<(AccountId, VoteWeight, Vec)>, + _targets: Vec, + ) { + } } /// Something that can compute the result of an election and pass it back to the caller. @@ -217,7 +226,7 @@ pub trait ElectionDataProvider { /// implemented of this trait through [`ElectionProvider::DataProvider`]. pub trait ElectionProvider { /// The error type that is returned by the provider. - type Error; + type Error: sp_std::fmt::Debug; /// The data provider of the election. type DataProvider: ElectionDataProvider; From 7f4f5b7bc2c4f6984649ec642cecffa05b39f7d4 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Mon, 4 Jan 2021 20:12:10 +0000 Subject: [PATCH 31/62] Almost done with conversion --- frame/election-providers/src/two_phase/mod.rs | 518 +++++++++++------- .../src/two_phase/signed.rs | 13 +- .../src/two_phase/unsigned.rs | 109 +--- frame/staking/src/lib.rs | 1 - 4 files changed, 364 insertions(+), 277 deletions(-) diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index fe38dd8f73e8f..c8d5ac63eb989 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -159,7 +159,6 @@ use crate::onchain::OnChainSequentialPhragmen; use codec::{Decode, Encode, HasCompact}; use frame_support::{ - decl_event, decl_module, decl_storage, dispatch::DispatchResultWithPostInfo, ensure, traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, @@ -172,10 +171,14 @@ use sp_npos_elections::{ EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, }; use sp_runtime::{ - traits::Zero, transaction_validity::TransactionPriority, InnerOf, PerThing, Perbill, - RuntimeDebug, + traits::Zero, + transaction_validity::{ + InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, + TransactionValidityError, ValidTransaction, + }, + DispatchError, InnerOf, PerThing, Perbill, RuntimeDebug, SaturatedConversion, }; -use sp_std::prelude::*; +use sp_std::{convert::TryInto, prelude::*}; #[cfg(any(feature = "runtime-benchmarks", test))] mod benchmarking; @@ -388,11 +391,11 @@ pub struct RoundSnapshotMetadata { targets_len: u32, } -/// The crate errors. +/// Internal errors of the pallet. /// -/// Note that this is different from the [`PalletError`]. +/// Note that this is different from [`pallet::Error`]. #[derive(RuntimeDebug, Eq, PartialEq)] -pub enum Error { +pub enum InternalError { /// A feasibility error. Feasibility(FeasibilityError), /// An error in the on-chain fallback. @@ -407,21 +410,21 @@ pub enum Error { PoolSubmissionFailed, } -impl From for Error { +impl From for InternalError { fn from(e: crate::onchain::Error) -> Self { - Error::OnChainFallback(e) + InternalError::OnChainFallback(e) } } -impl From for Error { +impl From for InternalError { fn from(e: sp_npos_elections::Error) -> Self { - Error::NposElections(e) + InternalError::NposElections(e) } } -impl From for Error { +impl From for InternalError { fn from(e: FeasibilityError) -> Self { - Error::Feasibility(e) + InternalError::Feasibility(e) } } @@ -454,161 +457,99 @@ impl From for FeasibilityError { } } -pub trait Config: frame_system::Config + SendTransactionTypes> -where - ExtendedBalance: From>>, - ExtendedBalance: From>>, -{ - /// Event type. - type Event: From> + Into<::Event>; - - /// Currency type. - type Currency: ReservableCurrency + Currency; - - /// Duration of the signed phase. - type SignedPhase: Get; - /// Duration of the unsigned phase. - type UnsignedPhase: Get; - /// Maximum number of singed submissions that can be queued. - type MaxSignedSubmissions: Get; - - type SignedRewardBase: Get>; - type SignedRewardFactor: Get; - type SignedRewardMax: Get>>; - - type SignedDepositBase: Get>; - type SignedDepositByte: Get>; - type SignedDepositWeight: Get>; - - /// The minimum amount of improvement to the solution score that defines a solution as "better". - type SolutionImprovementThreshold: Get; - - /// The priority of the unsigned transaction submitted in the unsigned-phase - type UnsignedPriority: Get; - /// Maximum number of iteration of balancing that will be executed in the embedded miner of the - /// pallet. - type MinerMaxIterations: Get; - /// Maximum weight that the miner should consume. - type MinerMaxWeight: Get; - - /// Handler for the slashed deposits. - type SlashHandler: OnUnbalanced>; - /// Handler for the rewards. - type RewardHandler: OnUnbalanced>; - - /// Something that will provide the election data. - type DataProvider: ElectionDataProvider; - - /// The compact solution type - type CompactSolution: codec::Codec - + Default - + PartialEq - + Eq - + Clone - + sp_std::fmt::Debug - + CompactSolution; - - /// Accuracy used for fallback on-chain election. - type OnChainAccuracy: PerThing128; - - /// The weight of the pallet. - type WeightInfo: WeightInfo; -} +pub use pallet::*; +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; -decl_storage! { - trait Store for Module as TwoPhaseElectionProvider + #[pallet::config] + pub trait Config: frame_system::Config + SendTransactionTypes> where - ExtendedBalance: From>>, - ExtendedBalance: From>> + ExtendedBalance: From>>, + ExtendedBalance: From>>, { - /// Internal counter for the number of rounds. - /// - /// This is useful for de-duplication of transactions submitted to the pool, and general - /// diagnostics of the module. - /// - /// This is merely incremented once per every time that an upstream `elect` is called. - pub Round get(fn round): u32 = 1; - /// Current phase. - pub CurrentPhase get(fn current_phase): Phase = Phase::Off; - - /// Sorted (worse -> best) list of unchecked, signed solutions. - pub SignedSubmissions get(fn signed_submissions): Vec, CompactOf>>; - - /// Current best solution, signed or unsigned. - pub QueuedSolution get(fn queued_solution): Option>; - - /// Snapshot data of the round. - /// - /// This is created at the beginning of the signed phase and cleared upon calling `elect`. - pub Snapshot get(fn snapshot): Option>; - - /// Desired number of targets to elect for this round. - /// - /// Only exists when [`Snapshot`] is present. - pub DesiredTargets get(fn desired_targets): Option; - - /// The metadata of the [`RoundSnapshot`] - /// - /// Only exists when [`Snapshot`] is present. - pub SnapshotMetadata get(fn snapshot_metadata): Option; + type Event: From> + + Into<::Event> + + IsType<::Event>; + + /// Currency type. + type Currency: ReservableCurrency + Currency; + + /// Duration of the signed phase. + #[pallet::constant] + type SignedPhase: Get; + /// Duration of the unsigned phase. + #[pallet::constant] + type UnsignedPhase: Get; + /// Maximum number of singed submissions that can be queued. + #[pallet::constant] + type MaxSignedSubmissions: Get; + + #[pallet::constant] + type SignedRewardBase: Get>; + #[pallet::constant] + type SignedRewardFactor: Get; + #[pallet::constant] + type SignedRewardMax: Get>>; + + #[pallet::constant] + type SignedDepositBase: Get>; + #[pallet::constant] + type SignedDepositByte: Get>; + #[pallet::constant] + type SignedDepositWeight: Get>; + + /// The minimum amount of improvement to the solution score that defines a solution as + /// "better". + #[pallet::constant] + type SolutionImprovementThreshold: Get; + + /// The priority of the unsigned transaction submitted in the unsigned-phase + type UnsignedPriority: Get; + /// Maximum number of iteration of balancing that will be executed in the embedded miner of + /// the pallet. + type MinerMaxIterations: Get; + /// Maximum weight that the miner should consume. + type MinerMaxWeight: Get; + + /// Handler for the slashed deposits. + type SlashHandler: OnUnbalanced>; + /// Handler for the rewards. + type RewardHandler: OnUnbalanced>; + + /// Something that will provide the election data. + type DataProvider: ElectionDataProvider; + + /// The compact solution type + type CompactSolution: codec::Codec + + Default + + PartialEq + + Eq + + Clone + + sp_std::fmt::Debug + + CompactSolution; + + /// Accuracy used for fallback on-chain election. + type OnChainAccuracy: PerThing128; + + /// The weight of the pallet. + type WeightInfo: WeightInfo; } -} -decl_event!( - pub enum Event where ::AccountId { - /// A solution was stored with the given compute. - /// - /// If the solution is signed, this means that it hasn't yet been processed. If the solution - /// is unsigned, this means that it has also been processed. - SolutionStored(ElectionCompute), - /// The election has been finalized, with `Some` of the given computation, or else if the - /// election failed, `None`. - ElectionFinalized(Option), - /// An account has been rewarded for their signed submission being finalized. - Rewarded(AccountId), - /// An account has been slashed for submitting an invalid signed submission. - Slashed(AccountId), - /// The signed phase of the given round has started. - SignedPhaseStarted(u32), - /// The unsigned phase of the given round has started. - UnsignedPhaseStarted(u32), - } -); + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData); -frame_support::decl_error! { - pub enum PalletError for Module + #[pallet::hooks] + impl Hooks> for Pallet where ExtendedBalance: From>>, - ExtendedBalance: From>> + ExtendedBalance: From>>, { - /// Submission was too early. - EarlySubmission, - /// Submission was too weak, score-wise. - WeakSubmission, - /// The queue was full, and the solution was not better than any of the existing ones. - QueueFull, - /// The origin failed to pay the deposit. - CannotPayDeposit, - /// WitnessData is invalid. - InvalidWitness, - /// Round number is invalid. - InvalidRound, - } -} - -decl_module! { - pub struct Module for enum Call - where - origin: T::Origin, - ExtendedBalance: From>>, - ExtendedBalance: From>> - { - type Error = PalletError; - fn deposit_event() = default; - fn on_initialize(now: T::BlockNumber) -> Weight { - let next_election = T::DataProvider::next_election_prediction(now); - let next_election = next_election.max(now); + let next_election = T::DataProvider::next_election_prediction(now).max(now); let signed_deadline = T::SignedPhase::get() + T::UnsignedPhase::get(); let unsigned_deadline = T::UnsignedPhase::get(); @@ -644,7 +585,14 @@ decl_module! { }); } } + } + #[pallet::call] + impl Pallet + where + ExtendedBalance: From>>, + ExtendedBalance: From>>, + { /// Submit a solution for the signed phase. /// /// The dispatch origin fo this call must be __signed__. @@ -658,18 +606,28 @@ decl_module! { /// # /// Queue size must be provided as witness data. /// # - #[weight = T::WeightInfo::submit(*witness_data)] - fn submit(origin, solution: RawSolution>, witness_data: u32) -> DispatchResultWithPostInfo { + #[pallet::weight(T::WeightInfo::submit(*witness_data))] + fn submit( + origin: OriginFor, + solution: RawSolution>, + witness_data: u32, + ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; // ensure witness data is correct. - ensure!(witness_data == >::decode_len().unwrap_or_default() as u32, PalletError::::InvalidWitness); + ensure!( + witness_data == >::decode_len().unwrap_or_default() as u32, + Error::::InvalidWitness + ); // ensure solution is timely. - ensure!(Self::current_phase().is_signed(), PalletError::::EarlySubmission); + ensure!( + Self::current_phase().is_signed(), + Error::::EarlySubmission + ); // ensure round is correct. - ensure!(Self::round() == solution.round, PalletError::::InvalidRound); + ensure!(Self::round() == solution.round, Error::::InvalidRound); // NOTE: this is the only case where having separate snapshot would have been better // because could do just decode_len. But we can create abstractions to do this. @@ -680,14 +638,18 @@ decl_module! { // ensure solution claims is better. let mut signed_submissions = Self::signed_submissions(); - let maybe_index = Self::insert_submission(&who, &mut signed_submissions, solution, witness); - ensure!(maybe_index.is_some(), PalletError::::QueueFull); + let maybe_index = + Self::insert_submission(&who, &mut signed_submissions, solution, witness); + ensure!(maybe_index.is_some(), Error::::QueueFull); let index = maybe_index.expect("Option checked to be `Some`; qed."); // collect deposit. Thereafter, the function cannot fail. // Defensive -- index is valid. - let deposit = signed_submissions.get(index).map(|s| s.deposit).unwrap_or_default(); - T::Currency::reserve(&who, deposit).map_err(|_| PalletError::::CannotPayDeposit)?; + let deposit = signed_submissions + .get(index) + .map(|s| s.deposit) + .unwrap_or_default(); + T::Currency::reserve(&who, deposit).map_err(|_| Error::::CannotPayDeposit)?; // store the new signed submission. debug_assert!(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()); @@ -711,13 +673,17 @@ decl_module! { /// authoring reward at risk. /// /// No deposit or reward is associated with this. - #[weight = T::WeightInfo::submit_unsigned( + #[pallet::weight(T::WeightInfo::submit_unsigned( witness.voters, witness.targets, solution.compact.voters_count() as u32, solution.compact.unique_targets().len() as u32 - )] - fn submit_unsigned(origin, solution: RawSolution>, witness: WitnessData) { + ))] + fn submit_unsigned( + origin: OriginFor, + solution: RawSolution>, + witness: WitnessData, + ) -> DispatchResultWithPostInfo { ensure_none(origin)?; // check phase and score. @@ -725,9 +691,18 @@ decl_module! { let _ = Self::unsigned_pre_dispatch_checks(&solution)?; // ensure witness was correct. - let RoundSnapshotMetadata { voters_len, targets_len } = Self::snapshot_metadata().unwrap_or_default(); - ensure!(voters_len as u32 == witness.voters, PalletError::::InvalidWitness); - ensure!(targets_len as u32 == witness.targets, PalletError::::InvalidWitness); + let RoundSnapshotMetadata { + voters_len, + targets_len, + } = Self::snapshot_metadata().unwrap_or_default(); + ensure!( + voters_len as u32 == witness.voters, + Error::::InvalidWitness + ); + ensure!( + targets_len as u32 == witness.targets, + Error::::InvalidWitness + ); let ready = Self::feasibility_check(solution, ElectionCompute::Unsigned) @@ -739,11 +714,178 @@ decl_module! { // store the newly received solution. >::put(ready); Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); + + Ok(None.into()) } } + + #[pallet::event] + #[pallet::metadata(::AccountId = "AccountId")] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event + where + ExtendedBalance: From>>, + ExtendedBalance: From>>, + { + /// A solution was stored with the given compute. + /// + /// If the solution is signed, this means that it hasn't yet been processed. If the solution + /// is unsigned, this means that it has also been processed. + SolutionStored(ElectionCompute), + /// The election has been finalized, with `Some` of the given computation, or else if the + /// election failed, `None`. + ElectionFinalized(Option), + /// An account has been rewarded for their signed submission being finalized. + Rewarded(::AccountId), + /// An account has been slashed for submitting an invalid signed submission. + Slashed(::AccountId), + /// The signed phase of the given round has started. + SignedPhaseStarted(u32), + /// The unsigned phase of the given round has started. + UnsignedPhaseStarted(u32), + } + + /// Old name generated by `decl_event`. + #[deprecated(note = "use `Event` instead")] + pub type RawEvent = Event; + + #[pallet::error] + pub enum Error { + /// Submission was too early. + EarlySubmission, + /// Submission was too weak, score-wise. + WeakSubmission, + /// The queue was full, and the solution was not better than any of the existing ones. + QueueFull, + /// The origin failed to pay the deposit. + CannotPayDeposit, + /// WitnessData is invalid. + InvalidWitness, + /// Round number is invalid. + InvalidRound, + } + + #[pallet::origin] + pub struct Origin(PhantomData); + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet + where + ExtendedBalance: From>>, + ExtendedBalance: From>>, + { + type Call = Call; + fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { + if let Call::submit_unsigned(solution, _) = call { + // discard solution not coming from the local OCW. + match source { + TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } + _ => { + return InvalidTransaction::Call.into(); + } + } + + let _ = Self::unsigned_pre_dispatch_checks(solution) + .map_err(dispatch_error_to_invalid) + .map(Into::into)?; + + ValidTransaction::with_tag_prefix("OffchainElection") + // The higher the score[0], the better a solution is. + .priority( + T::UnsignedPriority::get() + .saturating_add(solution.score[0].saturated_into()), + ) + // used to deduplicate unsigned solutions: each validator should produce one + // solution per round at most, and solutions are not propagate. + .and_provides(solution.round) + // transaction should stay in the pool for the duration of the unsigned phase. + .longevity( + TryInto::::try_into(T::UnsignedPhase::get()) + .unwrap_or(crate::two_phase::unsigned::DEFAULT_LONGEVITY), + ) + // We don't propagate this. This can never the validated at a remote node. + .propagate(false) + .build() + } else { + InvalidTransaction::Call.into() + } + } + + fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { + if let Call::submit_unsigned(solution, _) = call { + Self::unsigned_pre_dispatch_checks(solution) + .map_err(dispatch_error_to_invalid) + .map_err(Into::into) + } else { + Err(InvalidTransaction::Call.into()) + } + } + } + + #[pallet::type_value] + pub fn DefaultForRound() -> u32 { + 1 + } + + /// Internal counter for the number of rounds. + /// + /// This is useful for de-duplication of transactions submitted to the pool, and general + /// diagnostics of the module. + /// + /// This is merely incremented once per every time that an upstream `elect` is called. + #[pallet::storage] + #[pallet::getter(fn round)] + pub type Round = StorageValue<_, u32, ValueQuery, DefaultForRound>; + + #[pallet::type_value] + pub fn DefaultForCurrentPhase() -> Phase { + Phase::Off + } + + /// Current phase. + #[pallet::storage] + #[pallet::getter(fn current_phase)] + pub type CurrentPhase = + StorageValue<_, Phase, ValueQuery, DefaultForCurrentPhase>; + + /// Sorted (worse -> best) list of unchecked, signed solutions. + #[pallet::storage] + #[pallet::getter(fn signed_submissions)] + pub type SignedSubmissions = StorageValue< + _, + Vec, CompactOf>>, + ValueQuery, + >; + + /// Current best solution, signed or unsigned. + #[pallet::storage] + #[pallet::getter(fn queued_solution)] + pub type QueuedSolution = StorageValue<_, ReadySolution>; + + /// Snapshot data of the round. + /// + /// This is created at the beginning of the signed phase and cleared upon calling `elect`. + #[pallet::storage] + #[pallet::getter(fn snapshot)] + pub type Snapshot = StorageValue<_, RoundSnapshot>; + + /// Desired number of targets to elect for this round. + /// + /// Only exists when [`Snapshot`] is present. + #[pallet::storage] + #[pallet::getter(fn desired_targets)] + // TODO: remove the generic here, neh? + pub type DesiredTargets = StorageValue<_, u32>; + + /// The metadata of the [`RoundSnapshot`] + /// + /// Only exists when [`Snapshot`] is present. + #[pallet::storage] + #[pallet::getter(fn snapshot_metadata)] + pub type SnapshotMetadata = StorageValue<_, RoundSnapshotMetadata>; } -impl Module +impl Pallet where ExtendedBalance: From>>, ExtendedBalance: From>>, @@ -796,11 +938,11 @@ where let voters = T::DataProvider::voters(); let desired_targets = T::DataProvider::desired_targets(); - SnapshotMetadata::put(RoundSnapshotMetadata { + >::put(RoundSnapshotMetadata { voters_len: voters.len() as u32, targets_len: targets.len() as u32, }); - DesiredTargets::put(desired_targets); + >::put(desired_targets); >::put(RoundSnapshot { voters, targets }); } @@ -811,15 +953,15 @@ where /// 3. Clear all snapshot data. fn post_elect() { // inc round - Round::mutate(|r| *r = *r + 1); + >::mutate(|r| *r = *r + 1); // change phase >::put(Phase::Off); // kill snapshots >::kill(); - SnapshotMetadata::kill(); - DesiredTargets::kill(); + >::kill(); + >::kill(); } /// Build the witness data from the snapshot metadata, if it exists. Else, returns `None`. @@ -905,7 +1047,7 @@ where // ----- Start building support. First, we need some more closures. let stake_of = stake_of_fn!(snapshot_voters, T::AccountId); - // This might fail if the normalization fails. Very unlikely. + // // This might fail if the normalization fails. Very unlikely. let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) .map_err::(Into::into)?; // This might fail if one of the voter edges is pointing to a non-winner. @@ -925,7 +1067,7 @@ where } /// On-chain fallback of election. - fn onchain_fallback() -> Result, Error> + fn onchain_fallback() -> Result, InternalError> where ExtendedBalance: From<::Inner>, { @@ -937,12 +1079,12 @@ where } } -impl ElectionProvider for Module +impl ElectionProvider for Pallet where ExtendedBalance: From>>, ExtendedBalance: From>>, { - type Error = Error; + type Error = InternalError; // TODO: rename to ELectionError type DataProvider = T::DataProvider; fn elect() -> Result, Self::Error> { @@ -974,6 +1116,16 @@ where } } +/// convert a DispatchError to a custom InvalidTransaction with the inner code being the error +/// number. +fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { + let error_number = match error { + DispatchError::Module { error, .. } => error, + _ => 0, + }; + InvalidTransaction::Custom(error_number) +} + #[cfg(test)] mod tests { use super::{mock::*, *}; diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index b92f047942a89..5cc58a5dee454 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -16,15 +16,16 @@ // limitations under the License. //! The signed phase implementation. +//! +//! THis is asda asdasda asd asdasdasd use crate::two_phase::*; use codec::Encode; use sp_arithmetic::traits::SaturatedConversion; -use sp_npos_elections::is_score_better; +use sp_npos_elections::{is_score_better, CompactSolution}; use sp_runtime::Perbill; -use sp_npos_elections::CompactSolution; -impl Module +impl Pallet where ExtendedBalance: From>>, ExtendedBalance: From>>, @@ -280,7 +281,7 @@ mod tests { assert_noop!( submit_with_witness(Origin::signed(10), solution), - PalletError::::EarlySubmission, + Error::::EarlySubmission, ); }) } @@ -434,7 +435,7 @@ mod tests { assert_noop!( submit_with_witness(Origin::signed(99), solution), - PalletError::::QueueFull, + Error::::QueueFull, ); }) } @@ -590,7 +591,7 @@ mod tests { }; assert_noop!( submit_with_witness(Origin::signed(99), solution), - PalletError::::QueueFull, + Error::::QueueFull, ); }) } diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 35036cc8915de..5aa4a93870511 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -22,13 +22,8 @@ use frame_support::{dispatch::DispatchResult, unsigned::ValidateUnsigned}; use frame_system::offchain::SubmitTransaction; use sp_npos_elections::{seq_phragmen, CompactSolution, ElectionResult}; use sp_runtime::{ - offchain::storage::StorageValueRef, - traits::TrailingZeroInput, - transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, - ValidTransaction, - }, - DispatchError, SaturatedConversion, + offchain::storage::StorageValueRef, traits::TrailingZeroInput, DispatchError, + SaturatedConversion, }; use sp_std::{cmp::Ordering, convert::TryInto}; @@ -40,15 +35,18 @@ pub(crate) const OFFCHAIN_REPEAT: u32 = 5; /// Default number of blocks for which the unsigned transaction should stay in the pool pub(crate) const DEFAULT_LONGEVITY: u64 = 25; -impl Module +impl Pallet where - ExtendedBalance: From>> + From>>, + ExtendedBalance: From>>, + ExtendedBalance: From>>, { /// Min a new npos solution. - pub fn mine_solution(iters: usize) -> Result<(RawSolution>, WitnessData), Error> { + pub fn mine_solution( + iters: usize, + ) -> Result<(RawSolution>, WitnessData), InternalError> { let RoundSnapshot { voters, targets } = - Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; - let desired_targets = Self::desired_targets().ok_or(Error::SnapshotUnAvailable)?; + Self::snapshot().ok_or(InternalError::SnapshotUnAvailable)?; + let desired_targets = Self::desired_targets().ok_or(InternalError::SnapshotUnAvailable)?; seq_phragmen::<_, CompactAccuracyOf>( desired_targets as usize, @@ -66,11 +64,11 @@ where /// Will always reduce the solution as well. pub fn prepare_election_result( election_result: ElectionResult>, - ) -> Result<(RawSolution>, WitnessData), Error> { + ) -> Result<(RawSolution>, WitnessData), InternalError> { // storage items. Note: we have already read this from storage, they must be in cache. let RoundSnapshot { voters, targets } = - Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; - let desired_targets = Self::desired_targets().ok_or(Error::SnapshotUnAvailable)?; + Self::snapshot().ok_or(InternalError::SnapshotUnAvailable)?; + let desired_targets = Self::desired_targets().ok_or(InternalError::SnapshotUnAvailable)?; // closures. let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); @@ -87,7 +85,7 @@ where // convert to staked and reduce. let mut staked = sp_npos_elections::assignment_ratio_to_staked_normalized(assignments, &stake_of) - .map_err::(Into::into)?; + .map_err::(Into::into)?; sp_npos_elections::reduce(&mut staked); // convert back to ration and make compact. @@ -151,14 +149,14 @@ where maximum_allowed_voters: u32, mut compact: CompactOf, nominator_index: FN, - ) -> Result, Error> + ) -> Result, InternalError> where for<'r> FN: Fn(&'r T::AccountId) -> Option>, { match compact.voters_count().checked_sub(maximum_allowed_voters as usize) { Some(to_remove) if to_remove > 0 => { // grab all voters and sort them by least stake. - let RoundSnapshot { voters, .. } = Self::snapshot().ok_or(Error::SnapshotUnAvailable)?; + let RoundSnapshot { voters, .. } = Self::snapshot().ok_or(InternalError::SnapshotUnAvailable)?; let mut voters_sorted = voters .into_iter() .map(|(who, stake, _)| (who.clone(), stake)) @@ -172,7 +170,7 @@ where .iter() .map(|(who, stake)| (nominator_index(&who), stake)) { - let index = maybe_index.ok_or(Error::SnapshotUnAvailable)?; + let index = maybe_index.ok_or(InternalError::SnapshotUnAvailable)?; if compact.remove_voter(index) { removed += 1 } @@ -309,7 +307,7 @@ where } /// Mine a new solution, and submit it back to the chian as an unsigned transaction. - pub(crate) fn mine_and_submit() -> Result<(), Error> { + pub(crate) fn mine_and_submit() -> Result<(), InternalError> { let balancing = Self::get_balancing_iters(); let (raw_solution, witness) = Self::mine_solution(balancing)?; @@ -317,7 +315,7 @@ where let call = Call::submit_unsigned(raw_solution, witness).into(); SubmitTransaction::>::submit_unsigned_transaction(call) - .map_err(|_| Error::PoolSubmissionFailed) + .map_err(|_| InternalError::PoolSubmissionFailed) } pub(crate) fn unsigned_pre_dispatch_checks( @@ -326,7 +324,7 @@ where // ensure solution is timely. Don't panic yet. This is a cheap check. ensure!( Self::current_phase().is_unsigned_open(), - PalletError::::EarlySubmission + Error::::EarlySubmission ); // ensure score is being improved. Panic henceforth. @@ -336,76 +334,13 @@ where q.score, T::SolutionImprovementThreshold::get() )), - PalletError::::WeakSubmission + Error::::WeakSubmission ); Ok(()) } } -#[allow(deprecated)] -impl ValidateUnsigned for Module -where - ExtendedBalance: From>>, - ExtendedBalance: From>> -{ - type Call = Call; - fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { - if let Call::submit_unsigned(solution, _) = call { - // discard solution not coming from the local OCW. - match source { - TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } - _ => { - return InvalidTransaction::Call.into(); - } - } - - - let _ = Self::unsigned_pre_dispatch_checks(solution) - .map_err(dispatch_error_to_invalid) - .map(Into::into)?; - - ValidTransaction::with_tag_prefix("OffchainElection") - // The higher the score[0], the better a solution is. - .priority( - T::UnsignedPriority::get().saturating_add(solution.score[0].saturated_into()), - ) - // used to deduplicate unsigned solutions: each validator should produce one - // solution per round at most, and solutions are not propagate. - .and_provides(solution.round) - // transaction should stay in the pool for the duration of the unsigned phase. - .longevity(TryInto::::try_into( - T::UnsignedPhase::get()).unwrap_or(DEFAULT_LONGEVITY) - ) - // We don't propagate this. This can never the validated at a remote node. - .propagate(false) - .build() - } else { - InvalidTransaction::Call.into() - } - } - - fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { - if let Call::submit_unsigned(solution, _) = call { - Self::unsigned_pre_dispatch_checks(solution) - .map_err(dispatch_error_to_invalid) - .map_err(Into::into) - } else { - Err(InvalidTransaction::Call.into()) - } - } -} - -/// convert a DispatchError to a custom InvalidTransaction with the inner code being the error -/// number. -fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { - let error_number = match error { - DispatchError::Module { error, .. } => error, - _ => 0, - }; - InvalidTransaction::Custom(error_number) -} - #[cfg(test)] mod max_weight { #![allow(unused_variables)] @@ -831,7 +766,7 @@ mod tests { assert_noop!( TwoPhase::submit_unsigned(Origin::none(), solution, witness), - PalletError::::WeakSubmission, + Error::::WeakSubmission, ); // trial 2: a solution who's score is only 7, i.e. 70% better in the first element. diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 25602c5d93bbc..b1b97d1d9b801 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -2441,7 +2441,6 @@ impl ElectionDataProvider for Module let session_length = T::NextNewSession::average_session_length(); - // TODO: consider removing the `now` here, does not serve much. let until_this_session_end = T::NextNewSession::estimate_next_new_session(now) .unwrap_or_default() .saturating_sub(now); From 8fb11f1a06f487804f1e6e9f54022a92b6da9be1 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 5 Jan 2021 09:59:44 +0000 Subject: [PATCH 32/62] Move to pallet V2 + construct_runtime --- .../src/two_phase/benchmarking.rs | 6 +- .../election-providers/src/two_phase/mock.rs | 67 +++++++------------ frame/election-providers/src/two_phase/mod.rs | 43 +++++------- .../src/two_phase/signed.rs | 5 +- .../src/two_phase/unsigned.rs | 20 +++--- 5 files changed, 61 insertions(+), 80 deletions(-) diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index 9979dae6ba301..ca03f88fa3972 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -106,11 +106,11 @@ where assert_eq!(all_voters.len() as u32, witness.voters); assert_eq!(winners.len() as u32, winners_count); - SnapshotMetadata::put(RoundSnapshotMetadata { + >::put(RoundSnapshotMetadata { voters_len: all_voters.len() as u32, targets_len: targets.len() as u32, }); - DesiredTargets::put(winners_count); + >::put(winners_count); >::put(RoundSnapshot { voters: all_voters.clone(), targets: targets.clone(), @@ -236,7 +236,7 @@ benchmarks! { let solution = RawSolution { score: [(1000_0000u128 - 1).into(), 0, 0], ..Default::default() }; >::put(Phase::Signed); - ::put(1); + >::put(1); for i in 0..c { >::mutate(|queue| { diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index aa0ac5d315674..8e368f2a9d948 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -1,4 +1,6 @@ use super::*; +use crate::two_phase; +pub use frame_support::{assert_noop, assert_ok}; use frame_support::{parameter_types, traits::OnInitialize, weights::Weight}; use parking_lot::RwLock; use sp_core::{ @@ -15,18 +17,26 @@ use sp_npos_elections::{ }; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, Block as BlockT, IdentityLookup}, PerU16, }; use std::sync::Arc; -pub use frame_support::{assert_noop, assert_ok}; +pub type Block = sp_runtime::generic::Block; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; + +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system::{Module, Call, Event}, + Balances: pallet_balances::{Module, Call, Event, Config}, + TwoPhase: two_phase::{Module, Call, Event}, + } +); -#[derive(Eq, PartialEq, Clone)] -pub struct Runtime; -pub(crate) type Balances = pallet_balances::Module; -pub(crate) type System = frame_system::Module; -pub(crate) type TwoPhase = super::Module; pub(crate) type Balance = u64; pub(crate) type AccountId = u64; @@ -36,12 +46,12 @@ sp_npos_elections::generate_solution_type!( ); /// All events of this pallet. -pub(crate) fn two_phase_events() -> Vec> { +pub(crate) fn two_phase_events() -> Vec> { System::events() .into_iter() .map(|r| r.event) .filter_map(|e| { - if let MetaEvent::two_phase(inner) = e { + if let Event::two_phase(inner) = e { Some(inner) } else { None @@ -112,43 +122,18 @@ pub fn witness() -> WitnessData { .unwrap_or_default() } -frame_support::impl_outer_dispatch! { - pub enum OuterCall for Runtime where origin: Origin { - two_phase::TwoPhase, - } -} - -frame_support::impl_outer_origin! { - pub enum Origin for Runtime where system = frame_system {} -} - -mod two_phase { - // Re-export needed for `impl_outer_event!`. - pub use super::super::*; -} -use frame_system as system; -use pallet_balances as balances; - -frame_support::impl_outer_event! { - pub enum MetaEvent for Runtime { - system, - balances, - two_phase, - } -} - impl frame_system::Config for Runtime { type BaseCallFilter = (); type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = OuterCall; + type Call = Call; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; - type Event = MetaEvent; + type Event = Event; type BlockHashCount = (); type DbWeight = (); type BlockLength = (); @@ -170,7 +155,7 @@ parameter_types! { impl pallet_balances::Config for Runtime { type Balance = Balance; - type Event = MetaEvent; + type Event = Event; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -209,7 +194,7 @@ parameter_types! { } impl crate::two_phase::Config for Runtime { - type Event = MetaEvent; + type Event = Event; type Currency = Balances; type SignedPhase = SignedPhase; type UnsignedPhase = UnsignedPhase; @@ -234,13 +219,13 @@ impl crate::two_phase::Config for Runtime { impl frame_system::offchain::SendTransactionTypes for Runtime where - OuterCall: From, + Call: From, { - type OverarchingCall = OuterCall; + type OverarchingCall = Call; type Extrinsic = Extrinsic; } -pub type Extrinsic = sp_runtime::testing::TestXt; +pub type Extrinsic = sp_runtime::testing::TestXt; #[derive(Default)] pub struct ExtBuilder {} diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index c8d5ac63eb989..31bd97d857d22 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -607,7 +607,7 @@ pub mod pallet { /// Queue size must be provided as witness data. /// # #[pallet::weight(T::WeightInfo::submit(*witness_data))] - fn submit( + pub fn submit( origin: OriginFor, solution: RawSolution>, witness_data: u32, @@ -655,7 +655,7 @@ pub mod pallet { debug_assert!(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()); >::put(signed_submissions); - Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Signed)); + Self::deposit_event(Event::SolutionStored(ElectionCompute::Signed)); Ok(None.into()) } @@ -679,7 +679,7 @@ pub mod pallet { solution.compact.voters_count() as u32, solution.compact.unique_targets().len() as u32 ))] - fn submit_unsigned( + pub fn submit_unsigned( origin: OriginFor, solution: RawSolution>, witness: WitnessData, @@ -713,7 +713,7 @@ pub mod pallet { // store the newly received solution. >::put(ready); - Self::deposit_event(RawEvent::SolutionStored(ElectionCompute::Unsigned)); + Self::deposit_event(Event::SolutionStored(ElectionCompute::Unsigned)); Ok(None.into()) } @@ -746,8 +746,8 @@ pub mod pallet { } /// Old name generated by `decl_event`. - #[deprecated(note = "use `Event` instead")] - pub type RawEvent = Event; + // #[deprecated(note = "use `Event` instead")] + // pub type RawEvent = Event; #[pallet::error] pub enum Error { @@ -837,16 +837,10 @@ pub mod pallet { #[pallet::getter(fn round)] pub type Round = StorageValue<_, u32, ValueQuery, DefaultForRound>; - #[pallet::type_value] - pub fn DefaultForCurrentPhase() -> Phase { - Phase::Off - } - /// Current phase. #[pallet::storage] #[pallet::getter(fn current_phase)] - pub type CurrentPhase = - StorageValue<_, Phase, ValueQuery, DefaultForCurrentPhase>; + pub type CurrentPhase = StorageValue<_, Phase, ValueQuery>; /// Sorted (worse -> best) list of unchecked, signed solutions. #[pallet::storage] @@ -874,8 +868,7 @@ pub mod pallet { /// Only exists when [`Snapshot`] is present. #[pallet::storage] #[pallet::getter(fn desired_targets)] - // TODO: remove the generic here, neh? - pub type DesiredTargets = StorageValue<_, u32>; + pub type DesiredTargets = StorageValue<_, u32>; /// The metadata of the [`RoundSnapshot`] /// @@ -896,7 +889,7 @@ where pub fn on_initialize_open_signed() { >::put(Phase::Signed); Self::create_snapshot(); - Self::deposit_event(RawEvent::SignedPhaseStarted(Self::round())); + Self::deposit_event(Event::SignedPhaseStarted(Self::round())); } /// Logic for [`Module::on_initialize`] when unsigned phase is being opened. @@ -922,7 +915,7 @@ where // for now always start the unsigned phase. >::put(Phase::Unsigned((true, now))); - Self::deposit_event(RawEvent::UnsignedPhaseStarted(Self::round())); + Self::deposit_event(Event::UnsignedPhaseStarted(Self::round())); additional_weight } @@ -1100,12 +1093,12 @@ where ) .map(|(supports, compute)| { Self::post_elect(); - Self::deposit_event(RawEvent::ElectionFinalized(Some(compute))); + Self::deposit_event(Event::ElectionFinalized(Some(compute))); log!(info, "Finalized election round with compute {:?}.", compute); supports }) .map_err(|err| { - Self::deposit_event(RawEvent::ElectionFinalized(None)); + Self::deposit_event(Event::ElectionFinalized(None)); log!(error, "Failed to finalize election round. Error = {:?}", err); err }) @@ -1128,7 +1121,7 @@ fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { #[cfg(test)] mod tests { - use super::{mock::*, *}; + use super::{mock::*, Event, *}; use sp_election_providers::ElectionProvider; use sp_npos_elections::Support; @@ -1150,7 +1143,7 @@ mod tests { roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Signed); - assert_eq!(two_phase_events(), vec![RawEvent::SignedPhaseStarted(1)]); + assert_eq!(two_phase_events(), vec![Event::SignedPhaseStarted(1)]); assert!(TwoPhase::snapshot().is_some()); assert_eq!(TwoPhase::round(), 1); @@ -1161,7 +1154,7 @@ mod tests { roll_to(25); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); - assert_eq!(two_phase_events(), vec![RawEvent::SignedPhaseStarted(1), RawEvent::UnsignedPhaseStarted(1)]); + assert_eq!(two_phase_events(), vec![Event::SignedPhaseStarted(1), Event::UnsignedPhaseStarted(1)]); assert!(TwoPhase::snapshot().is_some()); roll_to(29); @@ -1305,7 +1298,7 @@ mod tests { assert_eq!(TwoPhase::current_phase(), Phase::Off); roll_to(15); - assert_eq!(two_phase_events(), vec![RawEvent::SignedPhaseStarted(1)]); + assert_eq!(two_phase_events(), vec![Event::SignedPhaseStarted(1)]); assert_eq!(TwoPhase::current_phase(), Phase::Signed); assert_eq!(TwoPhase::round(), 1); @@ -1317,8 +1310,8 @@ mod tests { assert_eq!( two_phase_events(), vec![ - RawEvent::SignedPhaseStarted(1), - RawEvent::ElectionFinalized(Some(ElectionCompute::OnChain)) + Event::SignedPhaseStarted(1), + Event::ElectionFinalized(Some(ElectionCompute::OnChain)) ], ); // all storage items must be cleared. diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index 5cc58a5dee454..c026133a96500 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -255,7 +255,10 @@ where #[cfg(test)] mod tests { - use super::{mock::*, *}; + use super::{ + mock::{Origin, *}, + Error, Phase, *, + }; use frame_support::dispatch::DispatchResultWithPostInfo; fn submit_with_witness( diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 5aa4a93870511..9c0161e081fc2 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -18,14 +18,11 @@ //! The unsigned phase implementation. use crate::two_phase::*; -use frame_support::{dispatch::DispatchResult, unsigned::ValidateUnsigned}; +use frame_support::dispatch::DispatchResult; use frame_system::offchain::SubmitTransaction; use sp_npos_elections::{seq_phragmen, CompactSolution, ElectionResult}; -use sp_runtime::{ - offchain::storage::StorageValueRef, traits::TrailingZeroInput, DispatchError, - SaturatedConversion, -}; -use sp_std::{cmp::Ordering, convert::TryInto}; +use sp_runtime::{offchain::storage::StorageValueRef, traits::TrailingZeroInput}; +use sp_std::cmp::Ordering; /// Storage key used to store the persistent offchain worker status. pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; @@ -344,8 +341,7 @@ where #[cfg(test)] mod max_weight { #![allow(unused_variables)] - use super::*; - use mock::*; + use super::{mock::*, *}; struct TestWeight; impl crate::two_phase::weights::WeightInfo for TestWeight { @@ -549,10 +545,14 @@ mod max_weight { #[cfg(test)] mod tests { - use super::{mock::*, *}; + use super::{ + mock::{Origin, *}, + Call, *, + }; use frame_support::{dispatch::Dispatchable, traits::OffchainWorker}; + use mock::Call as OuterCall; use sp_election_providers::Assignment; - use sp_runtime::PerU16; + use sp_runtime::{traits::ValidateUnsigned, PerU16}; #[test] fn validate_unsigned_retracts_wrong_phase() { From 65f5ac1f5bb73fcd892255ef9d562619daafb886 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 5 Jan 2021 14:02:00 +0000 Subject: [PATCH 33/62] Revert staking changes; --- bin/node/runtime/src/lib.rs | 87 +- .../runtime/src/weights/pallet_staking.rs | 160 --- frame/babe/src/lib.rs | 8 +- .../election-providers/src/two_phase/mock.rs | 1 + frame/offences/benchmarking/src/lib.rs | 33 +- frame/session/benchmarking/src/lib.rs | 14 +- frame/staking/Cargo.toml | 2 +- frame/staking/src/benchmarking.rs | 34 +- frame/staking/src/lib.rs | 1243 +++++++++++++++-- frame/staking/src/mock.rs | 394 +++--- frame/staking/src/offchain_election.rs | 16 +- frame/staking/src/testing_utils.rs | 9 +- frame/staking/src/tests.rs | 97 +- 13 files changed, 1478 insertions(+), 620 deletions(-) delete mode 100644 bin/node/runtime/src/weights/pallet_staking.rs diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index bfb68c74e814c..807136eb55cd7 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -22,59 +22,56 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit = "256"] -use codec::{Decode, Encode}; +use sp_std::prelude::*; use frame_support::{ - construct_runtime, debug, parameter_types, - traits::{ - Currency, Imbalance, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, OnUnbalanced, - Randomness, U128CurrencyToVote, - }, + construct_runtime, parameter_types, debug, RuntimeDebug, weights::{ + Weight, IdentityFee, constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, - DispatchClass, IdentityFee, Weight, + DispatchClass, + }, + traits::{ + Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness, LockIdentifier, + U128CurrencyToVote, }, - RuntimeDebug, }; use frame_system::{ - limits::{BlockLength, BlockWeights}, - EnsureOneOf, EnsureRoot, -}; -pub use node_primitives::{AccountId, Signature}; -use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment}; -use pallet_grandpa::{ - fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, + EnsureRoot, EnsureOneOf, + limits::{BlockWeights, BlockLength}, }; -use pallet_im_online::sr25519::AuthorityId as ImOnlineId; -use pallet_session::historical as pallet_session_historical; -pub use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment}; -use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; -use sp_api::impl_runtime_apis; -use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; +use frame_support::traits::InstanceFilter; +use codec::{Encode, Decode}; use sp_core::{ crypto::KeyTypeId, u32_trait::{_1, _2, _3, _4, _5}, OpaqueMetadata, }; -use sp_inherents::{CheckInherentsResult, InherentData}; -use sp_npos_elections::CompactSolution; +pub use node_primitives::{AccountId, Signature}; +use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Index, Moment}; +use sp_api::impl_runtime_apis; use sp_runtime::{ - create_runtime_str, - curve::PiecewiseLinear, - generic, impl_opaque_keys, - traits::{ - self, BlakeTwo256, Block as BlockT, ConvertInto, NumberFor, OpaqueKeys, - SaturatedConversion, StaticLookup, - }, - transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedPointNumber, ModuleId, Perbill, Percent, Permill, Perquintill, + Permill, Perbill, Perquintill, Percent, ApplyExtrinsicResult, impl_opaque_keys, generic, + create_runtime_str, ModuleId, FixedPointNumber, }; -use sp_std::prelude::*; +use sp_runtime::curve::PiecewiseLinear; +use sp_runtime::transaction_validity::{TransactionValidity, TransactionSource, TransactionPriority}; +use sp_runtime::traits::{ + self, BlakeTwo256, Block as BlockT, StaticLookup, SaturatedConversion, ConvertInto, OpaqueKeys, + NumberFor, +}; +use sp_version::RuntimeVersion; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; -use sp_version::RuntimeVersion; +use pallet_grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; +use pallet_grandpa::fg_primitives; +use pallet_im_online::sr25519::AuthorityId as ImOnlineId; +use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; +use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; +pub use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment, CurrencyAdapter}; +use pallet_session::{historical as pallet_session_historical}; +use sp_inherents::{InherentData, CheckInherentsResult}; use static_assertions::const_assert; use pallet_contracts::WeightInfo; - use frame_election_providers::two_phase as pallet_two_phase_election_provider; #[cfg(any(feature = "std", test))] @@ -456,13 +453,7 @@ pallet_staking_reward_curve::build! { ); } -sp_npos_elections::generate_solution_type!( - #[compact] - pub struct CompactU16Solution::(16) -); - parameter_types! { - pub const MaxNominations: u32 = CompactU16Solution::LIMIT as u32; pub const SessionsPerEra: sp_staking::SessionIndex = 6; pub const BondingDuration: pallet_staking::EraIndex = 24 * 28; pub const SlashDeferDuration: pallet_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. @@ -483,7 +474,6 @@ impl pallet_staking::Config for Runtime { type UnixTime = Timestamp; type CurrencyToVote = U128CurrencyToVote; type RewardRemainder = Treasury; - type MaxNominations = MaxNominations; type Event = Event; type Slash = Treasury; // send the slashed funds to the treasury. type Reward = (); // rewards are minted from the void @@ -500,6 +490,14 @@ impl pallet_staking::Config for Runtime { type RewardCurve = RewardCurve; type NextNewSession = Session; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type ElectionLookahead = ElectionLookahead; + type Call = Call; + type MaxIterations = MaxIterations; + type MinSolutionScoreBump = MinSolutionScoreBump; + type UnsignedPriority = StakingUnsignedPriority; + // The unsigned solution weight targeted by the OCW. We set it to the maximum possible value of + // a single extrinsic. + type OffchainSolutionWeightLimit = OffchainSolutionWeightLimit; type ElectionProvider = TwoPhaseElectionProvider; type WeightInfo = pallet_staking::weights::SubstrateWeight; } @@ -513,6 +511,7 @@ parameter_types! { pub const MaxUnsignedIterations: u32 = 10; } + impl pallet_two_phase_election_provider::Config for Runtime { type Event = Event; type Currency = Balances; @@ -532,8 +531,8 @@ impl pallet_two_phase_election_provider::Config for Runtime { type MinerMaxWeight = (); type UnsignedPriority = (); type DataProvider = Staking; - type CompactSolution = CompactU16Solution; type OnChainAccuracy = Perbill; + type CompactSolution = pallet_staking::CompactAssignments; type WeightInfo = (); } @@ -1020,7 +1019,7 @@ construct_runtime!( Balances: pallet_balances::{Module, Call, Storage, Config, Event}, TransactionPayment: pallet_transaction_payment::{Module, Storage}, TwoPhaseElectionProvider: pallet_two_phase_election_provider::{Module, Call, Storage, Event, ValidateUnsigned}, - Staking: pallet_staking::{Module, Call, Config, Storage, Event}, + Staking: pallet_staking::{Module, Call, Config, Storage, Event, ValidateUnsigned}, Session: pallet_session::{Module, Call, Storage, Event, Config}, Democracy: pallet_democracy::{Module, Call, Storage, Config, Event}, Council: pallet_collective::::{Module, Call, Storage, Origin, Event, Config}, diff --git a/bin/node/runtime/src/weights/pallet_staking.rs b/bin/node/runtime/src/weights/pallet_staking.rs deleted file mode 100644 index 2793a941af79a..0000000000000 --- a/bin/node/runtime/src/weights/pallet_staking.rs +++ /dev/null @@ -1,160 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2020 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 -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Default weights of pallet-staking. -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0-rc6 - -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; - -pub struct WeightInfo(PhantomData); -impl pallet_staking::WeightInfo for WeightInfo { - fn bond() -> Weight { - (144278000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) - } - fn bond_extra() -> Weight { - (110715000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - } - fn unbond() -> Weight { - (99840000 as Weight) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - } - fn withdraw_unbonded_update(s: u32, ) -> Weight { - (100728000 as Weight) - .saturating_add((63000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - } - fn withdraw_unbonded_kill(s: u32, ) -> Weight { - (168879000 as Weight) - .saturating_add((6666000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(7 as Weight)) - .saturating_add(T::DbWeight::get().writes(8 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) - } - fn validate() -> Weight { - (35539000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - } - fn nominate(n: u32, ) -> Weight { - (48596000 as Weight) - .saturating_add((308000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - } - fn chill() -> Weight { - (35144000 as Weight) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) - } - fn set_payee() -> Weight { - (24255000 as Weight) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn set_controller() -> Weight { - (52294000 as Weight) - .saturating_add(T::DbWeight::get().reads(3 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - } - fn set_validator_count() -> Weight { - (5185000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn force_no_eras() -> Weight { - (5907000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn force_new_era() -> Weight { - (5917000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn force_new_era_always() -> Weight { - (5952000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn set_invulnerables(v: u32, ) -> Weight { - (6324000 as Weight) - .saturating_add((9000 as Weight).saturating_mul(v as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn force_unstake(s: u32, ) -> Weight { - (119691000 as Weight) - .saturating_add((6681000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(8 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) - } - fn cancel_deferred_slash(s: u32, ) -> Weight { - (5820201000 as Weight) - .saturating_add((34672000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(1 as Weight)) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } - fn payout_stakers_dead_controller(n: u32, ) -> Weight { - (0 as Weight) - .saturating_add((92486000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(n as Weight))) - } - fn payout_stakers_alive_staked(n: u32, ) -> Weight { - (0 as Weight) - .saturating_add((117324000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(n as Weight))) - } - fn rebond(l: u32, ) -> Weight { - (71316000 as Weight) - .saturating_add((142000 as Weight).saturating_mul(l as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(3 as Weight)) - } - fn set_history_depth(e: u32, ) -> Weight { - (0 as Weight) - .saturating_add((51901000 as Weight).saturating_mul(e as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) - .saturating_add(T::DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight))) - } - fn reap_stash(s: u32, ) -> Weight { - (147166000 as Weight) - .saturating_add((6661000 as Weight).saturating_mul(s as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(8 as Weight)) - .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight))) - } - fn new_era(v: u32, n: u32, ) -> Weight { - (0 as Weight) - .saturating_add((1440459000 as Weight).saturating_mul(v as Weight)) - .saturating_add((182580000 as Weight).saturating_mul(n as Weight)) - .saturating_add(T::DbWeight::get().reads(10 as Weight)) - .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(v as Weight))) - .saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight))) - .saturating_add(T::DbWeight::get().writes(8 as Weight)) - .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight))) - } -} diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 177c6b8677062..49efbc885f501 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -407,9 +407,11 @@ impl Module { /// In other word, this is only accurate if no slots are missed. Given missed slots, the slot /// number will grow while the block number will not. Hence, the result can be interpreted as an /// upper bound. - // -------------- IMPORTANT NOTE -------------- This implementation is linked to how - // [`should_epoch_change`] is working. This might need to be updated accordingly, if the - // underlying mechanics of slot and epochs change. + // + // ## IMPORTANT NOTE + // + // This implementation is linked to how [`should_epoch_change`] is working. This might need to + // be updated accordingly, if the underlying mechanics of slot and epochs change. // // WEIGHT NOTE: This function is tied to the weight of `EstimateNextSessionRotation`. If you // update this function, you must also update the corresponding weight. diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 8e368f2a9d948..6527fa88203b0 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -123,6 +123,7 @@ pub fn witness() -> WitnessData { } impl frame_system::Config for Runtime { + type SS58Prefix = (); type BaseCallFilter = (); type Origin = Origin; type Index = u64; diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 85ba395335538..09ac820cf5c4d 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -24,28 +24,23 @@ mod mock; use sp_std::prelude::*; use sp_std::vec; -use frame_benchmarking::{account, benchmarks}; -use frame_support::traits::{Currency, Get, OnInitialize}; -use frame_system::{Config as SystemConfig, Module as System, RawOrigin}; +use frame_system::{RawOrigin, Module as System, Config as SystemConfig}; +use frame_benchmarking::{benchmarks, account}; +use frame_support::traits::{Currency, OnInitialize}; -use sp_runtime::{ - traits::{Convert, Saturating, StaticLookup, UniqueSaturatedInto}, - Perbill, -}; -use sp_staking::offence::{Offence, OffenceDetails, ReportOffence}; +use sp_runtime::{Perbill, traits::{Convert, StaticLookup, Saturating, UniqueSaturatedInto}}; +use sp_staking::offence::{ReportOffence, Offence, OffenceDetails}; +use pallet_balances::{Config as BalancesConfig}; use pallet_babe::BabeEquivocationOffence; -use pallet_balances::Config as BalancesConfig; use pallet_grandpa::{GrandpaEquivocationOffence, GrandpaTimeSlot}; use pallet_im_online::{Config as ImOnlineConfig, Module as ImOnline, UnresponsivenessOffence}; use pallet_offences::{Config as OffencesConfig, Module as Offences}; -use pallet_session::{ - historical::{Config as HistoricalConfig, IdentificationTuple}, - Config as SessionConfig, SessionManager, -}; +use pallet_session::historical::{Config as HistoricalConfig, IdentificationTuple}; +use pallet_session::{Config as SessionConfig, SessionManager}; use pallet_staking::{ - Config as StakingConfig, Event as StakingEvent, Exposure, IndividualExposure, - Module as Staking, RewardDestination, ValidatorPrefs, + Module as Staking, Config as StakingConfig, RewardDestination, ValidatorPrefs, + Exposure, IndividualExposure, ElectionStatus, MAX_NOMINATIONS, Event as StakingEvent }; const SEED: u32 = 0; @@ -214,7 +209,7 @@ benchmarks! { let r in 1 .. MAX_REPORTERS; // we skip 1 offender, because in such case there is no slashing let o in 2 .. MAX_OFFENDERS; - let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); + let n in 0 .. MAX_NOMINATORS.min(MAX_NOMINATIONS as u32); // Make r reporters let mut reporters = vec![]; @@ -288,7 +283,7 @@ benchmarks! { } report_offence_grandpa { - let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); + let n in 0 .. MAX_NOMINATORS.min(MAX_NOMINATIONS as u32); // for grandpa equivocation reports the number of reporters // and offenders is always 1 @@ -324,7 +319,7 @@ benchmarks! { } report_offence_babe { - let n in 0 .. MAX_NOMINATORS.min(::MaxNominations::get()); + let n in 0 .. MAX_NOMINATORS.min(MAX_NOMINATIONS as u32); // for babe equivocation reports the number of reporters // and offenders is always 1 @@ -364,7 +359,7 @@ benchmarks! { let o = 10; let n = 100; - // Staking::::put_election_status(ElectionStatus::Closed); + Staking::::put_election_status(ElectionStatus::Closed); let mut deferred_offences = vec![]; let offenders = make_offenders::(o, n)?.0; diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index f3d3a16de8ead..89afc73b6b442 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -28,14 +28,14 @@ use sp_std::vec; use frame_benchmarking::benchmarks; use frame_support::{ codec::Decode, - storage::{StorageMap, StorageValue}, - traits::{Get, KeyOwnerProofSystem, OnInitialize}, + storage::{StorageValue, StorageMap}, + traits::{KeyOwnerProofSystem, OnInitialize}, }; use frame_system::RawOrigin; use pallet_session::{historical::Module as Historical, Module as Session, *}; use pallet_staking::{ benchmarking::create_validator_with_nominators, testing_utils::create_validators, - RewardDestination, + MAX_NOMINATIONS, RewardDestination, }; use sp_runtime::traits::{One, StaticLookup}; @@ -54,10 +54,10 @@ benchmarks! { _ { } set_keys { - let n = ::MaxNominations::get(); + let n = MAX_NOMINATIONS as u32; let (v_stash, _) = create_validator_with_nominators::( n, - ::MaxNominations::get(), + MAX_NOMINATIONS as u32, false, RewardDestination::Staked, )?; @@ -70,10 +70,10 @@ benchmarks! { }: _(RawOrigin::Signed(v_controller), keys, proof) purge_keys { - let n = ::MaxNominations::get(); + let n = MAX_NOMINATIONS as u32; let (v_stash, _) = create_validator_with_nominators::( n, - ::MaxNominations::get(), + MAX_NOMINATIONS as u32, false, RewardDestination::Staked )?; diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 2523696cabccf..c279fee3a48b5 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -17,7 +17,7 @@ static_assertions = "1.1.0" serde = { version = "1.0.101", optional = true } codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] } sp-std = { version = "2.0.0", default-features = false, path = "../../primitives/std" } -# TODO: ideally we should be able to get rid of this by the end of this PR. +# TODO: TWO_PHASE:: ideally we should be able to get rid of this. sp-npos-elections = { version = "2.0.0", default-features = false, path = "../../primitives/npos-elections" } sp-io ={ version = "2.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "2.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 772103930d354..0ebe1eab788cf 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -199,9 +199,9 @@ benchmarks! { assert!(Validators::::contains_key(stash)); } - // Worst case scenario, T::MaxNominations::get() + // Worst case scenario, MAX_NOMINATIONS nominate { - let n in 1 .. T::MaxNominations::get() as u32; + let n in 1 .. MAX_NOMINATIONS as u32; let (stash, controller) = create_stash_controller::(n + 1, 100, Default::default())?; let validators = create_validators::(n, 100)?; whitelist_account!(controller); @@ -410,7 +410,7 @@ benchmarks! { let v in 1 .. 10; let n in 1 .. 100; - create_validators_with_nominators_for_era::(v, n, T::MaxNominations::get() as usize, false, None)?; + create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None)?; let session_index = SessionIndex::one(); }: { let validators = Staking::::new_era(session_index).ok_or("`new_era` failed")?; @@ -421,7 +421,7 @@ benchmarks! { payout_all { let v in 1 .. 10; let n in 1 .. 100; - create_validators_with_nominators_for_era::(v, n, T::MaxNominations::get() as usize, false, None)?; + create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None)?; // Start a new Era let new_validators = Staking::::new_era(SessionIndex::one()).unwrap(); assert!(new_validators.len() == v as usize); @@ -483,7 +483,6 @@ benchmarks! { assert!(balance_before > balance_after); } - /* // This benchmark create `v` validators intent, `n` nominators intent, in total creating `e` // edges. #[extra] @@ -498,12 +497,12 @@ benchmarks! { // number of winners, also ValidatorCount. This will be equal to `winner.len()`. let w in 16 .. 100; - ensure!(w >= T::MaxNominations::get(), "doesn't support lower value"); + ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); let winners = create_validators_with_nominators_for_era::( v, n, - T::MaxNominations::get(), + MAX_NOMINATIONS, false, Some(w), )?; @@ -569,12 +568,12 @@ benchmarks! { // number of winners, also ValidatorCount. let w in 16 .. 100; - ensure!(w as usize >= T::MaxNominations::get(), "doesn't support lower value"); + ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value"); let winners = create_validators_with_nominators_for_era::( v, n, - T::MaxNominations::get(), + MAX_NOMINATIONS, false, Some(w), )?; @@ -659,7 +658,7 @@ benchmarks! { // number of nominator intention. let n in 500 .. 1000; - create_validators_with_nominators_for_era::(v, n, T::MaxNominations::get(), false, None)?; + create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None)?; // needed for the solution to be generates. assert!(>::create_stakers_snapshot().0); @@ -708,7 +707,6 @@ benchmarks! { ).is_err() ); } - */ } #[cfg(test)] @@ -723,7 +721,7 @@ mod tests { let v = 10; let n = 100; - create_validators_with_nominators_for_era::(v, n, ::MaxNominations::get() as usize, false, None) + create_validators_with_nominators_for_era::(v, n, MAX_NOMINATIONS, false, None) .unwrap(); let count_validators = Validators::::iter().count(); @@ -836,6 +834,18 @@ mod tests { assert_ok!(test_benchmark_new_era::()); assert_ok!(test_benchmark_do_slash::()); assert_ok!(test_benchmark_payout_all::()); + // only run one of them to same time on the CI. ignore the other two. + assert_ok!(test_benchmark_submit_solution_initial::()); }); } + + #[test] + #[ignore] + fn test_benchmarks_offchain() { + ExtBuilder::default().has_stakers(false).build().execute_with(|| { + assert_ok!(test_benchmark_submit_solution_better::()); + assert_ok!(test_benchmark_submit_solution_weaker::()); + }); + } + } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 3fbe697c16b77..fe3f76ecf66df 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -276,45 +276,61 @@ pub mod testing_utils; #[cfg(any(feature = "runtime-benchmarks", test))] pub mod benchmarking; -pub mod inflation; pub mod slashing; +pub mod offchain_election; +pub mod inflation; pub mod weights; -use codec::{Decode, Encode, HasCompact}; +use sp_std::{ + result, + prelude::*, + collections::btree_map::BTreeMap, + convert::{TryInto, From}, + mem::size_of, +}; +use codec::{HasCompact, Encode, Decode}; use frame_support::{ - decl_error, decl_event, decl_module, decl_storage, - dispatch::{DispatchResult, DispatchResultWithPostInfo}, - ensure, + decl_module, decl_event, decl_storage, ensure, decl_error, + weights::{Weight, constants::{WEIGHT_PER_MICROS, WEIGHT_PER_NANOS}}, storage::IterableStorageMap, - traits::{ - Currency, CurrencyToVote, EnsureOrigin, EstimateNextNewSession, Get, Imbalance, - LockIdentifier, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, - }, - weights::{ - constants::{WEIGHT_PER_MICROS, WEIGHT_PER_NANOS}, - Weight, + dispatch::{ + DispatchResult, DispatchResultWithPostInfo, DispatchErrorWithPostInfo, + WithPostDispatchInfo, }, + traits::{ + Currency, LockIdentifier, LockableCurrency, WithdrawReasons, OnUnbalanced, Imbalance, Get, + UnixTime, EstimateNextNewSession, EnsureOrigin, CurrencyToVote, IsSubType, + } }; -use frame_system::{self as system, ensure_root, ensure_signed, offchain::SendTransactionTypes}; use pallet_session::historical; -use sp_election_providers::{ElectionDataProvider, ElectionProvider, Supports, Assignment}; -use sp_npos_elections::{ExtendedBalance, VoteWeight}; use sp_runtime::{ + Percent, Perbill, PerU16, PerThing, InnerOf, RuntimeDebug, DispatchError, curve::PiecewiseLinear, traits::{ - AtLeast32BitUnsigned, CheckedSub, Convert, SaturatedConversion, Saturating, StaticLookup, - Zero, + Convert, Zero, StaticLookup, CheckedSub, Saturating, SaturatedConversion, + AtLeast32BitUnsigned, Dispatchable, + }, + transaction_validity::{ + TransactionValidityError, TransactionValidity, ValidTransaction, InvalidTransaction, + TransactionSource, TransactionPriority, }, - PerThing, PerU16, Perbill, Percent, RuntimeDebug, }; -#[cfg(feature = "std")] -use sp_runtime::{Deserialize, Serialize}; use sp_staking::{ - offence::{Offence, OffenceDetails, OffenceError, OnOffenceHandler, ReportOffence}, SessionIndex, + offence::{OnOffenceHandler, OffenceDetails, Offence, ReportOffence, OffenceError}, +}; +#[cfg(feature = "std")] +use sp_runtime::{Serialize, Deserialize}; +use frame_system::{ + self as system, ensure_signed, ensure_root, ensure_none, + offchain::SendTransactionTypes, +}; +use sp_npos_elections::{ + ExtendedBalance, Assignment, ElectionScore, ElectionResult as PrimitiveElectionResult, + to_support_map, EvaluateSupport, seq_phragmen, generate_solution_type, + is_score_better, SupportMap, VoteWeight, CompactSolution, PerThing128, }; -use sp_std::{collections::btree_map::BTreeMap, convert::From, mem::size_of, prelude::*, result}; -use weights::WeightInfo; +pub use weights::WeightInfo; const STAKING_ID: LockIdentifier = *b"staking "; pub const MAX_UNLOCKING_CHUNKS: usize = 32; @@ -343,12 +359,23 @@ static_assertions::const_assert!(size_of::() <= size_of:: static_assertions::const_assert!(size_of::() <= size_of::()); static_assertions::const_assert!(size_of::() <= size_of::()); +/// Maximum number of stakers that can be stored in a snapshot. +pub(crate) const MAX_VALIDATORS: usize = ValidatorIndex::max_value() as usize; +pub(crate) const MAX_NOMINATORS: usize = NominatorIndex::max_value() as usize; +pub const MAX_NOMINATIONS: usize = ::LIMIT; + /// Counter for the number of eras that have passed. pub type EraIndex = u32; /// Counter for the number of "reward" points earned by a given validator. pub type RewardPoint = u32; +// Note: Maximum nomination limit is set here -- 16. +generate_solution_type!( + #[compact] + pub struct CompactAssignments::(16) +); + /// Accuracy used for on-chain election. pub type ChainAccuracy = Perbill; @@ -632,40 +659,75 @@ pub struct UnappliedSlash { payout: Balance, } -/// Mode of era-forcing. -#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub enum Forcing { - /// Not forcing anything - just let whatever happen. - NotForcing, - /// Force a new era, then reset to `NotForcing` as soon as it is done. - ForceNew, - /// Avoid a new era indefinitely. - ForceNone, - /// Force a new era at the end of all sessions indefinitely. - ForceAlways, +/// Indicate how an election round was computed. +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] +pub enum ElectionCompute { + /// Result was forcefully computed on chain at the end of the session. + OnChain, + /// Result was submitted and accepted to the chain via a signed transaction. + Signed, + /// Result was submitted and accepted to the chain via an unsigned transaction (by an + /// authority). + Unsigned, } -impl Default for Forcing { - fn default() -> Self { - Forcing::NotForcing - } +/// The result of an election round. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub struct ElectionResult { + /// Flat list of validators who have been elected. + elected_stashes: Vec, + /// Flat list of new exposures, to be updated in the [`Exposure`] storage. + exposures: Vec<(AccountId, Exposure)>, + /// Type of the result. This is kept on chain only to track and report the best score's + /// submission type. An optimisation could remove this. + compute: ElectionCompute, } -// A value placed in storage that represents the current version of the Staking storage. This value -// is used by the `on_runtime_upgrade` logic to determine whether we run storage migration logic. -// This should match directly with the semantic versions of the Rust crate. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)] -enum Releases { - V1_0_0Ancient, - V2_0_0, - V3_0_0, - V4_0_0, +/// The status of the upcoming (offchain) election. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +pub enum ElectionStatus { + /// Nothing has and will happen for now. submission window is not open. + Closed, + /// The submission window has been open since the contained block number. + Open(BlockNumber), } -impl Default for Releases { +/// Some indications about the size of the election. This must be submitted with the solution. +/// +/// Note that these values must reflect the __total__ number, not only those that are present in the +/// solution. In short, these should be the same size as the size of the values dumped in +/// `SnapshotValidators` and `SnapshotNominators`. +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, Default)] +pub struct ElectionSize { + /// Number of validators in the snapshot of the current election round. + #[codec(compact)] + pub validators: ValidatorIndex, + /// Number of nominators in the snapshot of the current election round. + #[codec(compact)] + pub nominators: NominatorIndex, +} + + +impl ElectionStatus { + pub fn is_open_at(&self, n: BlockNumber) -> bool { + *self == Self::Open(n) + } + + pub fn is_closed(&self) -> bool { + match self { + Self::Closed => true, + _ => false + } + } + + pub fn is_open(&self) -> bool { + !self.is_closed() + } +} + +impl Default for ElectionStatus { fn default() -> Self { - Releases::V4_0_0 + Self::Closed } } @@ -730,7 +792,7 @@ pub trait Config: frame_system::Config + SendTransactionTypes> { type CurrencyToVote: CurrencyToVote>; /// Something that provides the election functionality. - type ElectionProvider: ElectionProvider>; + type ElectionProvider: sp_election_providers::ElectionProvider>; /// Tokens have been minted and are unused for validator-reward. /// See [Era payout](./index.html#era-payout). @@ -770,17 +832,84 @@ pub trait Config: frame_system::Config + SendTransactionTypes> { /// Something that can estimate the next session change, accurately or as a best effort guess. type NextNewSession: EstimateNextNewSession; + /// The number of blocks before the end of the era from which election submissions are allowed. + /// + /// Setting this to zero will disable the offchain compute and only on-chain seq-phragmen will + /// be used. + /// + /// This is bounded by being within the last session. Hence, setting it to a value more than the + /// length of a session will be pointless. + type ElectionLookahead: Get; + + /// The overarching call type. + type Call: Dispatchable + From> + IsSubType> + Clone; + + /// Maximum number of balancing iterations to run in the offchain submission. + /// + /// If set to 0, balance_solution will not be executed at all. + type MaxIterations: Get; + + /// The threshold of improvement that should be provided for a new solution to be accepted. + type MinSolutionScoreBump: Get; + /// The maximum number of nominators rewarded for each validator. /// /// For each validator only the `$MaxNominatorRewardedPerValidator` biggest stakers can claim /// their reward. This used to limit the i/o cost for the nominator payout. type MaxNominatorRewardedPerValidator: Get; + /// A configuration for base priority of unsigned transactions. + /// + /// This is exposed so that it can be tuned for particular runtime, when + /// multiple pallets send unsigned transactions. + type UnsignedPriority: Get; + + /// Maximum weight that the unsigned transaction can have. + /// + /// Chose this value with care. On one hand, it should be as high as possible, so the solution + /// can contain as many nominators/validators as possible. On the other hand, it should be small + /// enough to fit in the block. + type OffchainSolutionWeightLimit: Get; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; +} + +/// Mode of era-forcing. +#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum Forcing { + /// Not forcing anything - just let whatever happen. + NotForcing, + /// Force a new era, then reset to `NotForcing` as soon as it is done. + ForceNew, + /// Avoid a new era indefinitely. + ForceNone, + /// Force a new era at the end of all sessions indefinitely. + ForceAlways, +} + +impl Default for Forcing { + fn default() -> Self { + Forcing::NotForcing + } +} + +// A value placed in storage that represents the current version of the Staking storage. This value +// is used by the `on_runtime_upgrade` logic to determine whether we run storage migration logic. +// This should match directly with the semantic versions of the Rust crate. +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)] +enum Releases { + V1_0_0Ancient, + V2_0_0, + V3_0_0, + V4_0_0, +} - /// Maximum number of nominations allowed per nominator. - type MaxNominations: Get; +impl Default for Releases { + fn default() -> Self { + Releases::V4_0_0 + } } decl_storage! { @@ -942,16 +1071,44 @@ decl_storage! { /// The last planned session scheduled by the session pallet. /// /// This is basically in sync with the call to [`SessionManager::new_session`]. - /// TODO: needs care to set the initial value upon migration. + /// TODO: TWO_PHASE: needs care to set the initial value upon migration. pub CurrentPlannedSession get(fn current_planned_session): SessionIndex; - // TODO: removed storage items: - // IsCurrentSessionFinal - // EraElectionStatus - // QueuedScore - // QueuedElected - // SnapshotNominators - // SnapshotValidators + /// Snapshot of validators at the beginning of the current election window. This should only + /// have a value when [`EraElectionStatus`] == `ElectionStatus::Open(_)`. + /// + /// DEPRECATED. + pub SnapshotValidators get(fn snapshot_validators): Option>; + + /// Snapshot of nominators at the beginning of the current election window. This should only + /// have a value when [`EraElectionStatus`] == `ElectionStatus::Open(_)`. + /// + /// DEPRECATED. + pub SnapshotNominators get(fn snapshot_nominators): Option>; + + /// The next validator set. At the end of an era, if this is available (potentially from the + /// result of an offchain worker), it is immediately used. Otherwise, the on-chain election + /// is executed. + /// + /// DEPRECATED. + pub QueuedElected get(fn queued_elected): Option>>; + + /// The score of the current [`QueuedElected`]. + /// + /// DEPRECATED. + pub QueuedScore get(fn queued_score): Option; + + /// Flag to control the execution of the offchain election. When `Open(_)`, we accept + /// solutions to be submitted. + /// + /// DEPRECATED. + pub EraElectionStatus get(fn era_election_status): ElectionStatus; + + /// True if the current **planned** session is final. Note that this does not take era + /// forcing into account. + /// + /// DEPRECATED. + pub IsCurrentSessionFinal get(fn is_current_session_final): bool = false; /// True if network has been upgraded to this version. /// Storage version of the pallet. @@ -1008,7 +1165,9 @@ decl_event!( /// not be processed. \[session_index\] OldSlashingReportDiscarded(SessionIndex), /// A new set of stakers was elected with the given \[compute\]. - StakingElection, + StakingElection(ElectionCompute), + /// A new solution for the upcoming election has been stored. \[compute\] + SolutionStored(ElectionCompute), /// An account has bonded this amount. \[stash, amount\] /// /// NOTE: This event is only emitted when funds are bonded via a dispatchable. Notably, @@ -1108,6 +1267,23 @@ decl_module! { /// intervention. const SlashDeferDuration: EraIndex = T::SlashDeferDuration::get(); + /// The number of blocks before the end of the era from which election submissions are allowed. + /// + /// Setting this to zero will disable the offchain compute and only on-chain seq-phragmen will + /// be used. + /// + /// This is bounded by being within the last session. Hence, setting it to a value more than the + /// length of a session will be pointless. + const ElectionLookahead: T::BlockNumber = T::ElectionLookahead::get(); + + /// Maximum number of balancing iterations to run in the offchain submission. + /// + /// If set to 0, balance_solution will not be executed at all. + const MaxIterations: u32 = T::MaxIterations::get(); + + /// The threshold of improvement that should be provided for a new solution to be accepted. + const MinSolutionScoreBump: Perbill = T::MinSolutionScoreBump::get(); + /// The maximum number of nominators rewarded for each validator. /// /// For each validator only the `$MaxNominatorRewardedPerValidator` biggest stakers can claim @@ -1118,6 +1294,74 @@ decl_module! { fn deposit_event() = default; + /// sets `ElectionStatus` to `Open(now)` where `now` is the block number at which the + /// election window has opened, if we are at the last session and less blocks than + /// `T::ElectionLookahead` is remaining until the next new session schedule. The offchain + /// worker, if applicable, will execute at the end of the current block, and solutions may + /// be submitted. + fn on_initialize(now: T::BlockNumber) -> Weight { + let mut consumed_weight = 0; + let mut add_weight = |reads, writes, weight| { + consumed_weight += T::DbWeight::get().reads_writes(reads, writes); + consumed_weight += weight; + }; + + if + // if we don't have any ongoing offchain compute. + Self::era_election_status().is_closed() && + // either current session final based on the plan, or we're forcing. + (Self::is_current_session_final() || Self::will_era_be_forced()) + { + if let Some(next_session_change) = T::NextNewSession::estimate_next_new_session(now) { + if let Some(remaining) = next_session_change.checked_sub(&now) { + if remaining <= T::ElectionLookahead::get() && !remaining.is_zero() { + // create snapshot. + let (did_snapshot, snapshot_weight) = Self::create_stakers_snapshot(); + add_weight(0, 0, snapshot_weight); + if did_snapshot { + // Set the flag to make sure we don't waste any compute here in the same era + // after we have triggered the offline compute. + >::put( + ElectionStatus::::Open(now) + ); + add_weight(0, 1, 0); + log!(info, "💸 Election window is Open({:?}). Snapshot created", now); + } else { + log!(warn, "💸 Failed to create snapshot at {:?}.", now); + } + } + } + } else { + log!(warn, "💸 Estimating next session change failed."); + } + add_weight(0, 0, T::NextNewSession::weight(now)) + } + // For `era_election_status`, `is_current_session_final`, `will_era_be_forced` + add_weight(3, 0, 0); + // Additional read from `on_finalize` + add_weight(1, 0, 0); + consumed_weight + } + + /// Check if the current block number is the one at which the election window has been set + /// to open. If so, it runs the offchain worker code. + fn offchain_worker(now: T::BlockNumber) { + use offchain_election::{set_check_offchain_execution_status, compute_offchain_election}; + + if Self::era_election_status().is_open_at(now) { + let offchain_status = set_check_offchain_execution_status::(now); + if let Err(why) = offchain_status { + log!(warn, "💸 skipping offchain worker in open election window due to [{}]", why); + } else { + if let Err(e) = compute_offchain_election::() { + log!(error, "💸 Error in election offchain worker: {:?}", e); + } else { + log!(debug, "💸 Executed offchain worker thread without errors."); + } + } + } + } + fn on_finalize() { // Set the start of the first era. if let Some(mut active_era) = Self::active_era() { @@ -1141,25 +1385,24 @@ decl_module! { ) ); - // use sp_runtime::UpperOf; + use sp_runtime::UpperOf; // see the documentation of `Assignment::try_normalize`. Now we can ensure that this // will always return `Ok`. // 1. Maximum sum of Vec must fit into `UpperOf`. - // TODO: these must go elsewhere - // assert!( - // >>::try_into(MAX_NOMINATIONS) - // .unwrap() - // .checked_mul(::one().deconstruct().try_into().unwrap()) - // .is_some() - // ); - - // // 2. Maximum sum of Vec must fit into `UpperOf`. - // assert!( - // >>::try_into(MAX_NOMINATIONS) - // .unwrap() - // .checked_mul(::one().deconstruct().try_into().unwrap()) - // .is_some() - // ); + assert!( + >>::try_into(MAX_NOMINATIONS) + .unwrap() + .checked_mul(::one().deconstruct().try_into().unwrap()) + .is_some() + ); + + // 2. Maximum sum of Vec must fit into `UpperOf`. + assert!( + >>::try_into(MAX_NOMINATIONS) + .unwrap() + .checked_mul(::one().deconstruct().try_into().unwrap()) + .is_some() + ); } /// Take the origin account as a stash and lock up `value` of its balance. `controller` will @@ -1254,6 +1497,7 @@ decl_module! { /// # #[weight = T::WeightInfo::bond_extra()] fn bond_extra(origin, #[compact] max_additional: BalanceOf) { + ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let stash = ensure_signed(origin)?; let controller = Self::bonded(&stash).ok_or(Error::::NotStash)?; @@ -1306,6 +1550,7 @@ decl_module! { /// #[weight = T::WeightInfo::unbond()] fn unbond(origin, #[compact] value: BalanceOf) { + ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; ensure!( @@ -1365,6 +1610,7 @@ decl_module! { /// # #[weight = T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans)] fn withdraw_unbonded(origin, num_slashing_spans: u32) -> DispatchResultWithPostInfo { + ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let (stash, old_total) = (ledger.stash.clone(), ledger.total); @@ -1419,6 +1665,7 @@ decl_module! { /// # #[weight = T::WeightInfo::validate()] pub fn validate(origin, prefs: ValidatorPrefs) { + ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let stash = &ledger.stash; @@ -1436,7 +1683,7 @@ decl_module! { /// /// # /// - The transaction's complexity is proportional to the size of `targets` (N) - /// which is capped at T::MaxNominations. + /// which is capped at CompactAssignments::LIMIT (MAX_NOMINATIONS). /// - Both the reads and writes follow a similar pattern. /// --------- /// Weight: O(N) @@ -1447,12 +1694,13 @@ decl_module! { /// # #[weight = T::WeightInfo::nominate(targets.len() as u32)] pub fn nominate(origin, targets: Vec<::Source>) { + ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let stash = &ledger.stash; ensure!(!targets.is_empty(), Error::::EmptyTargets); let targets = targets.into_iter() - .take(T::MaxNominations::get() as usize) + .take(MAX_NOMINATIONS) .map(|t| T::Lookup::lookup(t)) .collect::, _>>()?; @@ -1486,6 +1734,7 @@ decl_module! { /// # #[weight = T::WeightInfo::chill()] fn chill(origin) { + ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; Self::chill_stash(&ledger.stash); @@ -1729,6 +1978,7 @@ decl_module! { /// # #[weight = T::WeightInfo::payout_stakers_alive_staked(T::MaxNominatorRewardedPerValidator::get())] fn payout_stakers(origin, validator_stash: T::AccountId, era: EraIndex) -> DispatchResult { + ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); ensure_signed(origin)?; Self::do_payout_stakers(validator_stash, era) } @@ -1749,6 +1999,7 @@ decl_module! { /// # #[weight = T::WeightInfo::rebond(MAX_UNLOCKING_CHUNKS as u32)] fn rebond(origin, #[compact] value: BalanceOf) -> DispatchResultWithPostInfo { + ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; ensure!(!ledger.unlocking.is_empty(), Error::::NoUnlockChunk); @@ -1826,7 +2077,120 @@ decl_module! { T::Currency::remove_lock(STAKING_ID, &stash); } - // TODO: removal of calls, bump tx version. + /// Submit an election result to the chain. If the solution: + /// + /// 1. is valid. + /// 2. has a better score than a potentially existing solution on chain. + /// + /// then, it will be _put_ on chain. + /// + /// A solution consists of two pieces of data: + /// + /// 1. `winners`: a flat vector of all the winners of the round. + /// 2. `assignments`: the compact version of an assignment vector that encodes the edge + /// weights. + /// + /// Both of which may be computed using _phragmen_, or any other algorithm. + /// + /// Additionally, the submitter must provide: + /// + /// - The `score` that they claim their solution has. + /// + /// Both validators and nominators will be represented by indices in the solution. The + /// indices should respect the corresponding types ([`ValidatorIndex`] and + /// [`NominatorIndex`]). Moreover, they should be valid when used to index into + /// [`SnapshotValidators`] and [`SnapshotNominators`]. Any invalid index will cause the + /// solution to be rejected. These two storage items are set during the election window and + /// may be used to determine the indices. + /// + /// A solution is valid if: + /// + /// 0. It is submitted when [`EraElectionStatus`] is `Open`. + /// 1. Its claimed score is equal to the score computed on-chain. + /// 2. Presents the correct number of winners. + /// 3. All indexes must be value according to the snapshot vectors. All edge values must + /// also be correct and should not overflow the granularity of the ratio type (i.e. 256 + /// or billion). + /// 4. For each edge, all targets are actually nominated by the voter. + /// 5. Has correct self-votes. + /// + /// A solutions score is consisted of 3 parameters: + /// + /// 1. `min { support.total }` for each support of a winner. This value should be maximized. + /// 2. `sum { support.total }` for each support of a winner. This value should be minimized. + /// 3. `sum { support.total^2 }` for each support of a winner. This value should be + /// minimized (to ensure less variance) + /// + /// # + /// The transaction is assumed to be the longest path, a better solution. + /// - Initial solution is almost the same. + /// - Worse solution is retraced in pre-dispatch-checks which sets its own weight. + /// # + #[weight = T::WeightInfo::submit_solution_better( + size.validators.into(), + size.nominators.into(), + compact.voters_count() as u32, + winners.len() as u32, + )] + pub fn submit_election_solution( + origin, + winners: Vec, + compact: CompactAssignments, + score: ElectionScore, + era: EraIndex, + size: ElectionSize, + ) -> DispatchResultWithPostInfo { + let _who = ensure_signed(origin)?; + Self::check_and_replace_solution( + winners, + compact, + ElectionCompute::Signed, + score, + era, + size, + ) + } + + /// Unsigned version of `submit_election_solution`. + /// + /// Note that this must pass the [`ValidateUnsigned`] check which only allows transactions + /// from the local node to be included. In other words, only the block author can include a + /// transaction in the block. + /// + /// # + /// See [`submit_election_solution`]. + /// # + #[weight = T::WeightInfo::submit_solution_better( + size.validators.into(), + size.nominators.into(), + compact.voters_count() as u32, + winners.len() as u32, + )] + pub fn submit_election_solution_unsigned( + origin, + winners: Vec, + compact: CompactAssignments, + score: ElectionScore, + era: EraIndex, + size: ElectionSize, + ) -> DispatchResultWithPostInfo { + ensure_none(origin)?; + let adjustments = Self::check_and_replace_solution( + winners, + compact, + ElectionCompute::Unsigned, + score, + era, + size, + ).expect( + "An unsigned solution can only be submitted by validators; A validator should \ + always produce correct solutions, else this block should not be imported, thus \ + effectively depriving the validators from their authoring reward. Hence, this panic + is expected." + ); + + Ok(adjustments) + } } } @@ -1858,6 +2222,52 @@ impl Module { }) } + /// Dump the list of validators and nominators into vectors and keep them on-chain. + /// + /// This data is used to efficiently evaluate election results. returns `true` if the operation + /// is successful. + pub fn create_stakers_snapshot() -> (bool, Weight) { + let mut consumed_weight = 0; + let mut add_db_reads_writes = |reads, writes| { + consumed_weight += T::DbWeight::get().reads_writes(reads, writes); + }; + let validators = >::iter().map(|(v, _)| v).collect::>(); + let mut nominators = >::iter().map(|(n, _)| n).collect::>(); + + let num_validators = validators.len(); + let num_nominators = nominators.len(); + add_db_reads_writes((num_validators + num_nominators) as Weight, 0); + + if + num_validators > MAX_VALIDATORS || + num_nominators.saturating_add(num_validators) > MAX_NOMINATORS + { + log!( + warn, + "💸 Snapshot size too big [{} <> {}][{} <> {}].", + num_validators, + MAX_VALIDATORS, + num_nominators, + MAX_NOMINATORS, + ); + (false, consumed_weight) + } else { + // all validators nominate themselves; + nominators.extend(validators.clone()); + + >::put(validators); + >::put(nominators); + add_db_reads_writes(0, 2); + (true, consumed_weight) + } + } + + /// Clears both snapshots of stakers. + fn kill_stakers_snapshot() { + >::kill(); + >::kill(); + } + fn do_payout_stakers(validator_stash: T::AccountId, era: EraIndex) -> DispatchResult { // Validate input data let current_era = CurrentEra::get().ok_or(Error::::InvalidEraToReward)?; @@ -2017,7 +2427,14 @@ impl Module { Forcing::ForceAlways => (), Forcing::NotForcing if era_length >= T::SessionsPerEra::get() => (), _ => { - // TODO: double check this. + // Either `ForceNone`, or `NotForcing && era_length < T::SessionsPerEra::get()`. + if era_length + 1 == T::SessionsPerEra::get() { + IsCurrentSessionFinal::put(true); + } else if era_length >= T::SessionsPerEra::get() { + // Should only happen when we are ready to trigger an era but we have ForceNone, + // otherwise previous arm would short circuit. + Self::close_election_window(); + } return None }, } @@ -2030,6 +2447,216 @@ impl Module { } } + /// Basic and cheap checks that we perform in validate unsigned, and in the execution. + /// + /// State reads: ElectionState, CurrentEr, QueuedScore. + /// + /// This function does weight refund in case of errors, which is based upon the fact that it is + /// called at the very beginning of the call site's function. + pub fn pre_dispatch_checks(score: ElectionScore, era: EraIndex) -> DispatchResultWithPostInfo { + // discard solutions that are not in-time + // check window open + ensure!( + Self::era_election_status().is_open(), + Error::::OffchainElectionEarlySubmission.with_weight(T::DbWeight::get().reads(1)), + ); + + // check current era. + if let Some(current_era) = Self::current_era() { + ensure!( + current_era == era, + Error::::OffchainElectionEarlySubmission.with_weight(T::DbWeight::get().reads(2)), + ) + } + + // assume the given score is valid. Is it better than what we have on-chain, if we have any? + if let Some(queued_score) = Self::queued_score() { + ensure!( + is_score_better(score, queued_score, T::MinSolutionScoreBump::get()), + Error::::OffchainElectionWeakSubmission.with_weight(T::DbWeight::get().reads(3)), + ) + } + + Ok(None.into()) + } + + /// Checks a given solution and if correct and improved, writes it on chain as the queued result + /// of the next round. This may be called by both a signed and an unsigned transaction. + pub fn check_and_replace_solution( + winners: Vec, + compact_assignments: CompactAssignments, + compute: ElectionCompute, + claimed_score: ElectionScore, + era: EraIndex, + election_size: ElectionSize, + ) -> DispatchResultWithPostInfo { + // Do the basic checks. era, claimed score and window open. + let _ = Self::pre_dispatch_checks(claimed_score, era)?; + + // before we read any further state, we check that the unique targets in compact is same as + // compact. is a all in-memory check and easy to do. Moreover, it ensures that the solution + // is not full of bogus edges that can cause lots of reads to SlashingSpans. Thus, we can + // assume that the storage access of this function is always O(|winners|), not + // O(|compact.edge_count()|). + ensure!( + compact_assignments.unique_targets().len() == winners.len(), + Error::::OffchainElectionBogusWinnerCount, + ); + + // Check that the number of presented winners is sane. Most often we have more candidates + // than we need. Then it should be `Self::validator_count()`. Else it should be all the + // candidates. + let snapshot_validators_length = >::decode_len() + .map(|l| l as u32) + .ok_or_else(|| Error::::SnapshotUnavailable)?; + + // size of the solution must be correct. + ensure!( + snapshot_validators_length == u32::from(election_size.validators), + Error::::OffchainElectionBogusElectionSize, + ); + + // check the winner length only here and when we know the length of the snapshot validators + // length. + let desired_winners = Self::validator_count().min(snapshot_validators_length); + ensure!(winners.len() as u32 == desired_winners, Error::::OffchainElectionBogusWinnerCount); + + let snapshot_nominators_len = >::decode_len() + .map(|l| l as u32) + .ok_or_else(|| Error::::SnapshotUnavailable)?; + + // rest of the size of the solution must be correct. + ensure!( + snapshot_nominators_len == election_size.nominators, + Error::::OffchainElectionBogusElectionSize, + ); + + // decode snapshot validators. + let snapshot_validators = Self::snapshot_validators() + .ok_or(Error::::SnapshotUnavailable)?; + + // check if all winners were legit; this is rather cheap. Replace with accountId. + let winners = winners.into_iter().map(|widx| { + // NOTE: at the moment, since staking is explicitly blocking any offence until election + // is closed, we don't check here if the account id at `snapshot_validators[widx]` is + // actually a validator. If this ever changes, this loop needs to also check this. + snapshot_validators.get(widx as usize).cloned().ok_or(Error::::OffchainElectionBogusWinner) + }).collect::, Error>>()?; + + // decode the rest of the snapshot. + let snapshot_nominators = Self::snapshot_nominators() + .ok_or(Error::::SnapshotUnavailable)?; + + // helpers + let nominator_at = |i: NominatorIndex| -> Option { + snapshot_nominators.get(i as usize).cloned() + }; + let validator_at = |i: ValidatorIndex| -> Option { + snapshot_validators.get(i as usize).cloned() + }; + + // un-compact. + let assignments = compact_assignments.into_assignment( + nominator_at, + validator_at, + ).map_err(|e| { + // log the error since it is not propagated into the runtime error. + log!(warn, "💸 un-compacting solution failed due to {:?}", e); + Error::::OffchainElectionBogusCompact + })?; + + // check all nominators actually including the claimed vote. Also check correct self votes. + // Note that we assume all validators and nominators in `assignments` are properly bonded, + // because they are coming from the snapshot via a given index. + for Assignment { who, distribution } in assignments.iter() { + let is_validator = >::contains_key(&who); + let maybe_nomination = Self::nominators(&who); + + if !(maybe_nomination.is_some() ^ is_validator) { + // all of the indices must map to either a validator or a nominator. If this is ever + // not the case, then the locking system of staking is most likely faulty, or we + // have bigger problems. + log!(error, "💸 detected an error in the staking locking and snapshot."); + // abort. + return Err(Error::::OffchainElectionBogusNominator.into()); + } + + if !is_validator { + // a normal vote + let nomination = maybe_nomination.expect( + "exactly one of `maybe_validator` and `maybe_nomination.is_some` is true. \ + is_validator is false; maybe_nomination is some; qed" + ); + + // NOTE: we don't really have to check here if the sum of all edges are the + // nominator correct. Un-compacting assures this by definition. + + for (t, _) in distribution { + // each target in the provided distribution must be actually nominated by the + // nominator after the last non-zero slash. + if nomination.targets.iter().find(|&tt| tt == t).is_none() { + return Err(Error::::OffchainElectionBogusNomination.into()); + } + + if ::SlashingSpans::get(&t).map_or( + false, + |spans| nomination.submitted_in < spans.last_nonzero_slash(), + ) { + return Err(Error::::OffchainElectionSlashedNomination.into()); + } + } + } else { + // a self vote + ensure!(distribution.len() == 1, Error::::OffchainElectionBogusSelfVote); + ensure!(distribution[0].0 == *who, Error::::OffchainElectionBogusSelfVote); + // defensive only. A compact assignment of length one does NOT encode the weight and + // it is always created to be 100%. + ensure!( + distribution[0].1 == OffchainAccuracy::one(), + Error::::OffchainElectionBogusSelfVote, + ); + } + } + + // convert into staked assignments. + let staked_assignments = sp_npos_elections::assignment_ratio_to_staked( + assignments, + Self::slashable_balance_of_fn(), + ); + + // build the support map thereof in order to evaluate. + let supports = to_support_map::( + &winners, + &staked_assignments, + ).map_err(|_| Error::::OffchainElectionBogusEdge)?; + + // Check if the score is the same as the claimed one. + let submitted_score = supports.evaluate(); + ensure!(submitted_score == claimed_score, Error::::OffchainElectionBogusScore); + + // At last, alles Ok. Exposures and store the result. + let exposures = Self::collect_exposure(supports); + log!( + info, + "💸 A better solution (with compute {:?} and score {:?}) has been validated and stored on chain.", + compute, + submitted_score, + ); + + // write new results. + >::put(ElectionResult { + elected_stashes: winners, + compute, + exposures, + }); + QueuedScore::put(submitted_score); + + // emit event. + Self::deposit_event(RawEvent::SolutionStored(compute)); + + Ok(None.into()) + } + /// Start a session potentially starting an era. fn start_session(start_session: SessionIndex) { let next_active_era = Self::active_era().map(|e| e.index + 1).unwrap_or(0); @@ -2143,48 +2770,291 @@ impl Module { } // Set staking information for new era. - let maybe_new_validators = Self::enact_election(current_era); + let maybe_new_validators = Self::select_and_update_validators(current_era); + // TODO: TWO_PHASE:: later on, switch to enact_election which uses `T::ElectionProvider`. + // let maybe_new_validators = Self::enact_election(current_era); maybe_new_validators } - /// Consume a vectors of [`Supports`] ([`Supports`]) and collect them into a [`Exposure`]. + /// Remove all the storage items associated with the election. + fn close_election_window() { + // Close window. + >::put(ElectionStatus::Closed); + // Kill snapshots. + Self::kill_stakers_snapshot(); + // Don't track final session. + IsCurrentSessionFinal::put(false); + } + + /// Select the new validator set at the end of the era. + /// + /// Runs [`try_do_phragmen`] and updates the following storage items: + /// - [`EraElectionStatus`]: with `None`. + /// - [`ErasStakers`]: with the new staker set. + /// - [`ErasStakersClipped`]. + /// - [`ErasValidatorPrefs`]. + /// - [`ErasTotalStake`]: with the new total stake. + /// - [`SnapshotValidators`] and [`SnapshotNominators`] are both removed. + /// + /// Internally, [`QueuedElected`], snapshots and [`QueuedScore`] are also consumed. + /// + /// If the election has been successful, It passes the new set upwards. + /// + /// This should only be called at the end of an era. + fn select_and_update_validators(current_era: EraIndex) -> Option> { + if let Some(ElectionResult::> { + elected_stashes, + exposures, + compute, + }) = Self::try_do_election() { + // Totally close the election round and data. + Self::close_election_window(); + + // Populate Stakers and write slot stake. + let mut total_stake: BalanceOf = Zero::zero(); + exposures.into_iter().for_each(|(stash, exposure)| { + total_stake = total_stake.saturating_add(exposure.total); + >::insert(current_era, &stash, &exposure); + + let mut exposure_clipped = exposure; + let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize; + if exposure_clipped.others.len() > clipped_max_len { + exposure_clipped.others.sort_by(|a, b| a.value.cmp(&b.value).reverse()); + exposure_clipped.others.truncate(clipped_max_len); + } + >::insert(¤t_era, &stash, exposure_clipped); + }); + + // Insert current era staking information + >::insert(¤t_era, total_stake); + + // collect the pref of all winners + for stash in &elected_stashes { + let pref = Self::validators(stash); + >::insert(¤t_era, stash, pref); + } + + // emit event + Self::deposit_event(RawEvent::StakingElection(compute)); + + log!( + info, + "💸 new validator set of size {:?} has been elected via {:?} for era {:?}", + elected_stashes.len(), + compute, + current_era, + ); + + Some(elected_stashes) + } else { + None + } + } + + /// Select a new validator set from the assembled stakers and their role preferences. It tries + /// first to peek into [`QueuedElected`]. Otherwise, it runs a new on-chain phragmen election. + /// + /// If [`QueuedElected`] and [`QueuedScore`] exists, they are both removed. No further storage + /// is updated. + fn try_do_election() -> Option>> { + // an election result from either a stored submission or locally executed one. + let next_result = >::take().or_else(|| + Self::do_on_chain_phragmen() + ); + + // either way, kill this. We remove it here to make sure it always has the exact same + // lifetime as `QueuedElected`. + QueuedScore::kill(); + + next_result + } + + /// Execute election and return the new results. The edge weights are processed into support + /// values. + /// + /// This is basically a wrapper around [`Self::do_phragmen`] which translates + /// `PrimitiveElectionResult` into `ElectionResult`. + /// + /// No storage item is updated. + pub fn do_on_chain_phragmen() -> Option>> { + if let Some(phragmen_result) = Self::do_phragmen::(0) { + let elected_stashes = phragmen_result.winners.iter() + .map(|(s, _)| s.clone()) + .collect::>(); + let assignments = phragmen_result.assignments; + + let staked_assignments = sp_npos_elections::assignment_ratio_to_staked( + assignments, + Self::slashable_balance_of_fn(), + ); + + let supports = to_support_map::( + &elected_stashes, + &staked_assignments, + ) + .map_err(|_| + log!( + error, + "💸 on-chain phragmen is failing due to a problem in the result. This must be a bug." + ) + ) + .ok()?; + + // collect exposures + let exposures = Self::collect_exposure(supports); + + // In order to keep the property required by `on_session_ending` that we must return the + // new validator set even if it's the same as the old, as long as any underlying + // economic conditions have changed, we don't attempt to do any optimization where we + // compare against the prior set. + Some(ElectionResult::> { + elected_stashes, + exposures, + compute: ElectionCompute::OnChain, + }) + } else { + // There were not enough candidates for even our minimal level of functionality. This is + // bad. We should probably disable all functionality except for block production and let + // the chain keep producing blocks until we can decide on a sufficiently substantial + // set. TODO: #2494 + None + } + } + + /// Execute phragmen election and return the new results. No post-processing is applied and the + /// raw edge weights are returned. + /// + /// Self votes are added and nominations before the most recent slashing span are ignored. + /// + /// No storage item is updated. + pub fn do_phragmen( + iterations: usize, + ) -> Option> + where + ExtendedBalance: From>, + { + let weight_of = Self::slashable_balance_of_fn(); + let mut all_nominators: Vec<(T::AccountId, VoteWeight, Vec)> = Vec::new(); + let mut all_validators = Vec::new(); + for (validator, _) in >::iter() { + // append self vote + let self_vote = (validator.clone(), weight_of(&validator), vec![validator.clone()]); + all_nominators.push(self_vote); + all_validators.push(validator); + } + + let nominator_votes = >::iter().map(|(nominator, nominations)| { + let Nominations { submitted_in, mut targets, suppressed: _ } = nominations; + + // Filter out nomination targets which were nominated before the most recent + // slashing span. + targets.retain(|stash| { + ::SlashingSpans::get(&stash).map_or( + true, + |spans| submitted_in >= spans.last_nonzero_slash(), + ) + }); + + (nominator, targets) + }); + all_nominators.extend(nominator_votes.map(|(n, ns)| { + let s = weight_of(&n); + (n, s, ns) + })); + + if all_validators.len() < Self::minimum_validator_count().max(1) as usize { + // If we don't have enough candidates, nothing to do. + log!( + warn, + "💸 Chain does not have enough staking candidates to operate. Era {:?}.", + Self::current_era() + ); + None + } else { + seq_phragmen::<_, Accuracy>( + Self::validator_count() as usize, + all_validators, + all_nominators, + Some((iterations, 0)), // exactly run `iterations` rounds. + ) + .map_err(|err| log!(error, "Call to seq-phragmen failed due to {:?}", err)) + .ok() + } + } + + /// Consume a set of [`SupportMap`] from [`sp_npos_elections`] and collect them into a + /// [`Exposure`]. fn collect_exposure( - supports: Supports, + supports: SupportMap, ) -> Vec<(T::AccountId, Exposure>)> { let total_issuance = T::Currency::total_issuance(); let to_currency = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); - supports - .into_iter() - .map(|(validator, support)| { - // build `struct exposure` from `support` - let mut others = Vec::with_capacity(support.voters.len()); - let mut own: BalanceOf = Zero::zero(); - let mut total: BalanceOf = Zero::zero(); - support - .voters - .into_iter() - .map(|(nominator, weight)| (nominator, to_currency(weight))) - .for_each(|(nominator, stake)| { - if nominator == validator { - own = own.saturating_add(stake); - } else { - others.push(IndividualExposure { - who: nominator, - value: stake, - }); - } - total = total.saturating_add(stake); - }); + supports.into_iter().map(|(validator, support)| { + // build `struct exposure` from `support` + let mut others = Vec::with_capacity(support.voters.len()); + let mut own: BalanceOf = Zero::zero(); + let mut total: BalanceOf = Zero::zero(); + support.voters + .into_iter() + .map(|(nominator, weight)| (nominator, to_currency(weight))) + .for_each(|(nominator, stake)| { + if nominator == validator { + own = own.saturating_add(stake); + } else { + others.push(IndividualExposure { who: nominator, value: stake }); + } + total = total.saturating_add(stake); + }); - let exposure = Exposure { own, others, total }; + let exposure = Exposure { + own, + others, + total, + }; - (validator, exposure) - }) - .collect::)>>() + (validator, exposure) + }).collect::)>>() } + + /// Consume a set of [`Supports`] from [`sp_npos_elections`] and collect them into a + /// [`Exposure`]. + fn collect_exposure_flat( + supports: sp_npos_elections::Supports, + ) -> Vec<(T::AccountId, Exposure>)> { + let total_issuance = T::Currency::total_issuance(); + let to_currency = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); + + supports.into_iter().map(|(validator, support)| { + // build `struct exposure` from `support` + let mut others = Vec::with_capacity(support.voters.len()); + let mut own: BalanceOf = Zero::zero(); + let mut total: BalanceOf = Zero::zero(); + support.voters + .into_iter() + .map(|(nominator, weight)| (nominator, to_currency(weight))) + .for_each(|(nominator, stake)| { + if nominator == validator { + own = own.saturating_add(stake); + } else { + others.push(IndividualExposure { who: nominator, value: stake }); + } + total = total.saturating_add(stake); + }); + + let exposure = Exposure { + own, + others, + total, + }; + + (validator, exposure) + }).collect::)>>() + } + + /// Process the output of the election. /// /// This ensures enough validators have been elected, converts all supports to exposures and @@ -2193,10 +3063,10 @@ impl Module { /// Returns `Err(())` if less than [`MinimumValidatorCount`] validators have been elected, `Ok` /// otherwise. pub fn process_election( - flat_supports: Supports, + flat_supports: sp_npos_elections::Supports, current_era: EraIndex, ) -> Result, ()> { - let exposures = Self::collect_exposure(flat_supports); + let exposures = Self::collect_exposure_flat(flat_supports); let elected_stashes = exposures .iter() .cloned() @@ -2239,7 +3109,8 @@ impl Module { } // emit event - Self::deposit_event(RawEvent::StakingElection); + // TODO: TWO_PHASE: remove the inner value. + Self::deposit_event(RawEvent::StakingElection(ElectionCompute::Signed)); log!( info, @@ -2254,7 +3125,9 @@ impl Module { /// Enact and process the election using the `ElectionProvider` type. /// /// This will also process the election, as noted in [`process_election`]. + #[allow(dead_code)] // TODO: TWO_PHASE fn enact_election(current_era: EraIndex) -> Option> { + use sp_election_providers::ElectionProvider; T::ElectionProvider::elect() .map_err(|err| { log!( @@ -2353,6 +3226,32 @@ impl Module { } } + fn will_era_be_forced() -> bool { + match ForceEra::get() { + Forcing::ForceAlways | Forcing::ForceNew => true, + Forcing::ForceNone | Forcing::NotForcing => false, + } + } + + #[cfg(feature = "runtime-benchmarks")] + pub fn add_era_stakers( + current_era: EraIndex, + controller: T::AccountId, + exposure: Exposure>, + ) { + >::insert(¤t_era, &controller, &exposure); + } + + #[cfg(feature = "runtime-benchmarks")] + pub fn put_election_status(status: ElectionStatus::) { + >::put(status); + } + + #[cfg(feature = "runtime-benchmarks")] + pub fn set_slash_reward_fraction(fraction: Perbill) { + SlashRewardFraction::put(fraction); + } + /// Get all of the voters that are eligible for the npos election. /// /// This will use all on-chain nominators, and all the validators will inject a self vote. @@ -2401,23 +3300,9 @@ impl Module { pub fn get_npos_targets() -> Vec { >::iter().map(|(v, _)| v).collect::>() } - - #[cfg(feature = "runtime-benchmarks")] - pub fn add_era_stakers( - current_era: EraIndex, - controller: T::AccountId, - exposure: Exposure>, - ) { - >::insert(¤t_era, &controller, &exposure); - } - - #[cfg(feature = "runtime-benchmarks")] - pub fn set_slash_reward_fraction(fraction: Perbill) { - SlashRewardFraction::put(fraction); - } } -impl ElectionDataProvider for Module { +impl sp_election_providers::ElectionDataProvider for Module { fn desired_targets() -> u32 { Self::validator_count() } @@ -2474,9 +3359,6 @@ impl ElectionDataProvider for Module // checked by the election provider module, because we inject the self vote. Ok(()) } else { - sp_std::if_std! { - dbg!(assignment); - } Err("Unknown assignment") } } @@ -2754,8 +3636,8 @@ where } fn can_report() -> bool { - // TODO: now we can get rid of this API, remove it. - true + // TODO: TWO_PHASE: we can get rid of this API + Self::era_election_status().is_closed() } } @@ -2791,7 +3673,100 @@ where } } +#[allow(deprecated)] +impl frame_support::unsigned::ValidateUnsigned for Module { + type Call = Call; + fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { + if let Call::submit_election_solution_unsigned( + _, + _, + score, + era, + _, + ) = call { + use offchain_election::DEFAULT_LONGEVITY; + + // discard solution not coming from the local OCW. + match source { + TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } + _ => { + log!(debug, "rejecting unsigned transaction because it is not local/in-block."); + return InvalidTransaction::Call.into(); + } + } + + if let Err(error_with_post_info) = Self::pre_dispatch_checks(*score, *era) { + let invalid = to_invalid(error_with_post_info); + log!( + debug, + "💸 validate unsigned pre dispatch checks failed due to error #{:?}.", + invalid, + ); + return invalid.into(); + } + + log!(debug, "💸 validateUnsigned succeeded for a solution at era {}.", era); + + ValidTransaction::with_tag_prefix("StakingOffchain") + // The higher the score[0], the better a solution is. + .priority(T::UnsignedPriority::get().saturating_add(score[0].saturated_into())) + // Defensive only. A single solution can exist in the pool per era. Each validator + // will run OCW at most once per era, hence there should never exist more than one + // transaction anyhow. + .and_provides(era) + // Note: this can be more accurate in the future. We do something like + // `era_end_block - current_block` but that is not needed now as we eagerly run + // offchain workers now and the above should be same as `T::ElectionLookahead` + // without the need to query more storage in the validation phase. If we randomize + // offchain worker, then we might re-consider this. + .longevity(TryInto::::try_into( + T::ElectionLookahead::get()).unwrap_or(DEFAULT_LONGEVITY) + ) + // We don't propagate this. This can never the validated at a remote node. + .propagate(false) + .build() + } else { + InvalidTransaction::Call.into() + } + } + + fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { + if let Call::submit_election_solution_unsigned( + _, + _, + score, + era, + _, + ) = call { + // IMPORTANT NOTE: These checks are performed in the dispatch call itself, yet we need + // to duplicate them here to prevent a block producer from putting a previously + // validated, yet no longer valid solution on chain. + // OPTIMISATION NOTE: we could skip this in the `submit_election_solution_unsigned` + // since we already do it here. The signed version needs it though. Yer for now we keep + // this duplicate check here so both signed and unsigned can use a singular + // `check_and_replace_solution`. + Self::pre_dispatch_checks(*score, *era) + .map(|_| ()) + .map_err(to_invalid) + .map_err(Into::into) + } else { + Err(InvalidTransaction::Call.into()) + } + } +} + /// Check that list is sorted and has no duplicates. fn is_sorted_and_unique(list: &[u32]) -> bool { list.windows(2).all(|w| w[0] < w[1]) } + +/// convert a DispatchErrorWithPostInfo to a custom InvalidTransaction with the inner code being the +/// error number. +fn to_invalid(error_with_post_info: DispatchErrorWithPostInfo) -> InvalidTransaction { + let error = error_with_post_info.error; + let error_number = match error { + DispatchError::Module { error, ..} => error, + _ => 0, + }; + InvalidTransaction::Custom(error_number) +} diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index a59212a1dc5de..a47868fc80a47 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -26,10 +26,13 @@ use frame_support::{ }; use sp_core::H256; use sp_io; +use sp_npos_elections::{ + to_support_map, reduce, ExtendedBalance, StakedAssignment, ElectionScore, EvaluateSupport, +}; use sp_runtime::{ curve::PiecewiseLinear, testing::{Header, TestXt, UintAuthorityId}, - traits::IdentityLookup, + traits::{IdentityLookup, Zero}, }; use sp_staking::offence::{OffenceDetails, OnOffenceHandler}; use std::{cell::RefCell, collections::HashSet}; @@ -227,7 +230,6 @@ pallet_staking_reward_curve::build! { ); } parameter_types! { - pub const MaxNominations: u32 = 16; pub const BondingDuration: EraIndex = 3; pub const RewardCurve: &'static PiecewiseLinear<'static> = &I_NPOS; pub const MaxNominatorRewardedPerValidator: u32 = 64; @@ -261,7 +263,6 @@ impl Config for Test { type Currency = Balances; type UnixTime = Timestamp; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; - type MaxNominations = MaxNominations; type RewardRemainder = RewardRemainderMock; type Event = MetaEvent; type Slash = (); @@ -273,7 +274,13 @@ impl Config for Test { type SessionInterface = Self; type RewardCurve = RewardCurve; type NextNewSession = Session; + type ElectionLookahead = ElectionLookahead; + type Call = Call; + type MaxIterations = MaxIterations; + type MinSolutionScoreBump = MinSolutionScoreBump; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type UnsignedPriority = UnsignedPriority; + type OffchainSolutionWeightLimit = OffchainSolutionWeightLimit; type ElectionProvider = onchain::OnChainSequentialPhragmen; type WeightInfo = (); } @@ -778,198 +785,197 @@ pub(crate) fn add_slash(who: &AccountId) { ); } +// winners will be chosen by simply their unweighted total backing stake. Nominator stake is +// distributed evenly. +pub(crate) fn horrible_npos_solution( + do_reduce: bool, +) -> (CompactAssignments, Vec, ElectionScore) { + let mut backing_stake_of: BTreeMap = BTreeMap::new(); + + // self stake + >::iter().for_each(|(who, _p)| { + *backing_stake_of.entry(who).or_insert(Zero::zero()) += Staking::slashable_balance_of(&who) + }); + + // add nominator stuff + >::iter().for_each(|(who, nomination)| { + nomination.targets.iter().for_each(|v| { + *backing_stake_of.entry(*v).or_insert(Zero::zero()) += + Staking::slashable_balance_of(&who) + }) + }); + + // elect winners + let mut sorted: Vec = backing_stake_of.keys().cloned().collect(); + sorted.sort_by_key(|x| backing_stake_of.get(x).unwrap()); + let winners: Vec = sorted + .iter() + .cloned() + .take(Staking::validator_count() as usize) + .collect(); + + // create assignments + let mut staked_assignment: Vec> = Vec::new(); + >::iter().for_each(|(who, nomination)| { + let mut dist: Vec<(AccountId, ExtendedBalance)> = Vec::new(); + nomination.targets.iter().for_each(|v| { + if winners.iter().find(|w| *w == v).is_some() { + dist.push((*v, ExtendedBalance::zero())); + } + }); + + if dist.len() == 0 { + return; + } -// // winners will be chosen by simply their unweighted total backing stake. Nominator stake is -// // distributed evenly. -// pub(crate) fn horrible_npos_solution( -// do_reduce: bool, -// ) -> (CompactAssignments, Vec, ElectionScore) { -// let mut backing_stake_of: BTreeMap = BTreeMap::new(); - -// // self stake -// >::iter().for_each(|(who, _p)| { -// *backing_stake_of.entry(who).or_insert(Zero::zero()) += Staking::slashable_balance_of(&who) -// }); - -// // add nominator stuff -// >::iter().for_each(|(who, nomination)| { -// nomination.targets.iter().for_each(|v| { -// *backing_stake_of.entry(*v).or_insert(Zero::zero()) += -// Staking::slashable_balance_of(&who) -// }) -// }); - -// // elect winners -// let mut sorted: Vec = backing_stake_of.keys().cloned().collect(); -// sorted.sort_by_key(|x| backing_stake_of.get(x).unwrap()); -// let winners: Vec = sorted -// .iter() -// .cloned() -// .take(Staking::validator_count() as usize) -// .collect(); - -// // create assignments -// let mut staked_assignment: Vec> = Vec::new(); -// >::iter().for_each(|(who, nomination)| { -// let mut dist: Vec<(AccountId, ExtendedBalance)> = Vec::new(); -// nomination.targets.iter().for_each(|v| { -// if winners.iter().find(|w| *w == v).is_some() { -// dist.push((*v, ExtendedBalance::zero())); -// } -// }); - -// if dist.len() == 0 { -// return; -// } - -// // assign real stakes. just split the stake. -// let stake = Staking::slashable_balance_of(&who) as ExtendedBalance; -// let mut sum: ExtendedBalance = Zero::zero(); -// let dist_len = dist.len(); -// { -// dist.iter_mut().for_each(|(_, w)| { -// let partial = stake / (dist_len as ExtendedBalance); -// *w = partial; -// sum += partial; -// }); -// } - -// // assign the leftover to last. -// { -// let leftover = stake - sum; -// let last = dist.last_mut().unwrap(); -// last.1 += leftover; -// } - -// staked_assignment.push(StakedAssignment { -// who, -// distribution: dist, -// }); -// }); - -// // Ensure that this result is worse than seq-phragmen. Otherwise, it should not have been used -// // for testing. -// let score = { -// let (_, _, better_score) = prepare_submission_with(true, true, 0, |_| {}); - -// let support = build_support_map::(&winners, &staked_assignment).unwrap(); -// let score = evaluate_support(&support); - -// assert!(sp_npos_elections::is_score_better::( -// better_score, -// score, -// MinSolutionScoreBump::get(), -// )); - -// score -// }; - -// if do_reduce { -// reduce(&mut staked_assignment); -// } - -// let snapshot_validators = Staking::snapshot_validators().unwrap(); -// let snapshot_nominators = Staking::snapshot_nominators().unwrap(); -// let nominator_index = |a: &AccountId| -> Option { -// snapshot_nominators.iter().position(|x| x == a).map(|i| i as NominatorIndex) -// }; -// let validator_index = |a: &AccountId| -> Option { -// snapshot_validators.iter().position(|x| x == a).map(|i| i as ValidatorIndex) -// }; - -// // convert back to ratio assignment. This takes less space. -// let assignments_reduced = -// sp_npos_elections::assignment_staked_to_ratio::(staked_assignment); - -// let compact = -// CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index) -// .unwrap(); - -// // winner ids to index -// let winners = winners.into_iter().map(|w| validator_index(&w).unwrap()).collect::>(); - -// (compact, winners, score) -// } - -// /// Note: this should always logically reproduce [`offchain_election::prepare_submission`], yet we -// /// cannot do it since we want to have `tweak` injected into the process. -// /// -// /// If the input is being tweaked in a way that the score cannot be compute accurately, -// /// `compute_real_score` can be set to true. In this case a `Default` score is returned. -// pub(crate) fn prepare_submission_with( -// compute_real_score: bool, -// do_reduce: bool, -// iterations: usize, -// tweak: impl FnOnce(&mut Vec>), -// ) -> (CompactAssignments, Vec, ElectionScore) { -// // run election on the default stuff. -// let sp_npos_elections::ElectionResult { -// winners, -// assignments, -// } = Staking::do_phragmen::(iterations).unwrap(); -// let winners = sp_npos_elections::to_without_backing(winners); - -// let mut staked = sp_npos_elections::assignment_ratio_to_staked( -// assignments, -// Staking::slashable_balance_of_fn(), -// ); - -// // apply custom tweaks. awesome for testing. -// tweak(&mut staked); - -// if do_reduce { -// reduce(&mut staked); -// } - -// // convert back to ratio assignment. This takes less space. -// let snapshot_validators = Staking::snapshot_validators().expect("snapshot not created."); -// let snapshot_nominators = Staking::snapshot_nominators().expect("snapshot not created."); -// let nominator_index = |a: &AccountId| -> Option { -// snapshot_nominators -// .iter() -// .position(|x| x == a) -// .map_or_else( -// || { println!("unable to find nominator index for {:?}", a); None }, -// |i| Some(i as NominatorIndex), -// ) -// }; -// let validator_index = |a: &AccountId| -> Option { -// snapshot_validators -// .iter() -// .position(|x| x == a) -// .map_or_else( -// || { println!("unable to find validator index for {:?}", a); None }, -// |i| Some(i as ValidatorIndex), -// ) -// }; - -// let assignments_reduced = sp_npos_elections::assignment_staked_to_ratio(staked); - -// // re-compute score by converting, yet again, into staked type -// let score = if compute_real_score { -// let staked = sp_npos_elections::assignment_ratio_to_staked( -// assignments_reduced.clone(), -// Staking::slashable_balance_of_fn(), -// ); - -// let support_map = build_support_map::( -// winners.as_slice(), -// staked.as_slice(), -// ).unwrap(); -// evaluate_support::(&support_map) -// } else { -// Default::default() -// }; - -// let compact = -// CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index) -// .expect("Failed to create compact"); - -// // winner ids to index -// let winners = winners.into_iter().map(|w| validator_index(&w).unwrap()).collect::>(); - -// (compact, winners, score) -// } + // assign real stakes. just split the stake. + let stake = Staking::slashable_balance_of(&who) as ExtendedBalance; + let mut sum: ExtendedBalance = Zero::zero(); + let dist_len = dist.len(); + { + dist.iter_mut().for_each(|(_, w)| { + let partial = stake / (dist_len as ExtendedBalance); + *w = partial; + sum += partial; + }); + } + + // assign the leftover to last. + { + let leftover = stake - sum; + let last = dist.last_mut().unwrap(); + last.1 += leftover; + } + + staked_assignment.push(StakedAssignment { + who, + distribution: dist, + }); + }); + + // Ensure that this result is worse than seq-phragmen. Otherwise, it should not have been used + // for testing. + let score = { + let (_, _, better_score) = prepare_submission_with(true, true, 0, |_| {}); + + let support = to_support_map::(&winners, &staked_assignment).unwrap(); + let score = support.evaluate(); + + assert!(sp_npos_elections::is_score_better::( + better_score, + score, + MinSolutionScoreBump::get(), + )); + + score + }; + + if do_reduce { + reduce(&mut staked_assignment); + } + + let snapshot_validators = Staking::snapshot_validators().unwrap(); + let snapshot_nominators = Staking::snapshot_nominators().unwrap(); + let nominator_index = |a: &AccountId| -> Option { + snapshot_nominators.iter().position(|x| x == a).map(|i| i as NominatorIndex) + }; + let validator_index = |a: &AccountId| -> Option { + snapshot_validators.iter().position(|x| x == a).map(|i| i as ValidatorIndex) + }; + + // convert back to ratio assignment. This takes less space. + let assignments_reduced = + sp_npos_elections::assignment_staked_to_ratio::(staked_assignment); + + let compact = + CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index) + .unwrap(); + + // winner ids to index + let winners = winners.into_iter().map(|w| validator_index(&w).unwrap()).collect::>(); + + (compact, winners, score) +} + +/// Note: this should always logically reproduce [`offchain_election::prepare_submission`], yet we +/// cannot do it since we want to have `tweak` injected into the process. +/// +/// If the input is being tweaked in a way that the score cannot be compute accurately, +/// `compute_real_score` can be set to true. In this case a `Default` score is returned. +pub(crate) fn prepare_submission_with( + compute_real_score: bool, + do_reduce: bool, + iterations: usize, + tweak: impl FnOnce(&mut Vec>), +) -> (CompactAssignments, Vec, ElectionScore) { + // run election on the default stuff. + let sp_npos_elections::ElectionResult { + winners, + assignments, + } = Staking::do_phragmen::(iterations).unwrap(); + let winners = sp_npos_elections::to_without_backing(winners); + + let mut staked = sp_npos_elections::assignment_ratio_to_staked( + assignments, + Staking::slashable_balance_of_fn(), + ); + + // apply custom tweaks. awesome for testing. + tweak(&mut staked); + + if do_reduce { + reduce(&mut staked); + } + + // convert back to ratio assignment. This takes less space. + let snapshot_validators = Staking::snapshot_validators().expect("snapshot not created."); + let snapshot_nominators = Staking::snapshot_nominators().expect("snapshot not created."); + let nominator_index = |a: &AccountId| -> Option { + snapshot_nominators + .iter() + .position(|x| x == a) + .map_or_else( + || { println!("unable to find nominator index for {:?}", a); None }, + |i| Some(i as NominatorIndex), + ) + }; + let validator_index = |a: &AccountId| -> Option { + snapshot_validators + .iter() + .position(|x| x == a) + .map_or_else( + || { println!("unable to find validator index for {:?}", a); None }, + |i| Some(i as ValidatorIndex), + ) + }; + + let assignments_reduced = sp_npos_elections::assignment_staked_to_ratio(staked); + + // re-compute score by converting, yet again, into staked type + let score = if compute_real_score { + let staked = sp_npos_elections::assignment_ratio_to_staked( + assignments_reduced.clone(), + Staking::slashable_balance_of_fn(), + ); + + let support_map = to_support_map( + winners.as_slice(), + staked.as_slice(), + ).unwrap(); + support_map.evaluate() + } else { + Default::default() + }; + + let compact = + CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index) + .expect("Failed to create compact"); + + // winner ids to index + let winners = winners.into_iter().map(|w| validator_index(&w).unwrap()).collect::>(); + + (compact, winners, score) +} /// Make all validator and nominator request their payment pub(crate) fn make_all_reward_payment(era: EraIndex) { diff --git a/frame/staking/src/offchain_election.rs b/frame/staking/src/offchain_election.rs index 433e02261cc58..c21fcda73762c 100644 --- a/frame/staking/src/offchain_election.rs +++ b/frame/staking/src/offchain_election.rs @@ -25,8 +25,8 @@ use codec::Decode; use frame_support::{traits::Get, weights::Weight, IterableStorageMap}; use frame_system::offchain::SubmitTransaction; use sp_npos_elections::{ - build_support_map, evaluate_support, reduce, Assignment, ElectionResult, ElectionScore, - ExtendedBalance, + to_support_map, EvaluateSupport, reduce, Assignment, ElectionResult, ElectionScore, + ExtendedBalance, CompactSolution, }; use sp_runtime::{ offchain::storage::StorageValueRef, traits::TrailingZeroInput, PerThing, RuntimeDebug, @@ -265,7 +265,7 @@ pub fn trim_to_weight( where for<'r> FN: Fn(&'r T::AccountId) -> Option, { - match compact.len().checked_sub(maximum_allowed_voters as usize) { + match compact.voters_count().checked_sub(maximum_allowed_voters as usize) { Some(to_remove) if to_remove > 0 => { // grab all voters and sort them by least stake. let balance_of = >::slashable_balance_of_fn(); @@ -300,7 +300,7 @@ where warn, "💸 {} nominators out of {} had to be removed from compact solution due to size limits.", removed, - compact.len() + removed, + compact.voters_count() + removed, ); Ok(compact) } @@ -403,11 +403,11 @@ where T::WeightInfo::submit_solution_better( size.validators.into(), size.nominators.into(), - compact.len() as u32, + compact.voters_count() as u32, winners.len() as u32, ), maximum_allowed_voters, - compact.len(), + compact.voters_count(), ); let compact = trim_to_weight::(maximum_allowed_voters, compact, &nominator_index)?; @@ -423,9 +423,9 @@ where >::slashable_balance_of_fn(), ); - let support_map = build_support_map::(&winners, &staked) + let support_map = to_support_map::(&winners, &staked) .map_err(|_| OffchainElectionError::ElectionFailed)?; - evaluate_support::(&support_map) + support_map.evaluate() }; // winners to index. Use a simple for loop for a more expressive early exit in case of error. diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index e608085f94b97..4daed16c88a68 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -24,7 +24,7 @@ use frame_benchmarking::account; use frame_system::RawOrigin; use sp_io::hashing::blake2_256; use rand_chacha::{rand_core::{RngCore, SeedableRng}, ChaChaRng}; -// use sp_npos_elections::*; +use sp_npos_elections::*; const SEED: u32 = 0; @@ -171,7 +171,6 @@ pub fn create_validators_with_nominators_for_era( } -/* /// Build a _really bad_ but acceptable solution for election. This should always yield a solution /// which has a less score than the seq-phragmen. pub fn get_weak_solution( @@ -245,11 +244,11 @@ pub fn get_weak_solution( >::slashable_balance_of_fn(), ); - let support_map = build_support_map::( + let support_map = to_supports::( winners.as_slice(), staked.as_slice(), ).unwrap(); - evaluate_support::(&support_map) + support_map.evaluate() }; // compact encode the assignment. @@ -394,4 +393,4 @@ pub fn create_assignments_for_offchain( Ok((winners, assignments)) } -*/ + diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index c3dd56dd72930..92b24d35ed2c7 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -18,16 +18,16 @@ //! Tests for the module. use super::*; +use mock::*; +use sp_runtime::{ + assert_eq_error_rate, traits::BadOrigin, +}; +use sp_staking::offence::OffenceDetails; use frame_support::{ - assert_noop, assert_ok, - traits::{Currency, OnInitialize, ReservableCurrency}, - StorageMap, + assert_ok, assert_noop, StorageMap, + traits::{Currency, ReservableCurrency, OnInitialize, OnFinalize}, }; -use mock::*; use pallet_balances::Error as BalancesError; -use sp_npos_elections::Support; -use sp_runtime::{assert_eq_error_rate, traits::BadOrigin}; -use sp_staking::offence::OffenceDetails; use substrate_test_utils::assert_eq_uvec; #[test] @@ -1815,17 +1815,16 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election() { assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31])); - // winners should be 21 and 31. Otherwise this election is taking duplicates into - // account. - let election_result = ::ElectionProvider::elect().unwrap(); + // winners should be 21 and 31. Otherwise this election is taking duplicates into account. + let sp_npos_elections::ElectionResult { + winners, + assignments, + } = Staking::do_phragmen::(0).unwrap(); + let winners = sp_npos_elections::to_without_backing(winners); - assert_eq_uvec!( - election_result, - vec![ - (21, Support:: { total: 1800, voters: vec![(21, 1000), (3, 400), (1, 400)] }), - (31, Support:: { total: 2200, voters: vec![(31, 1000), (3, 600), (1, 600)] }), - ] - ); + assert_eq!(winners, vec![31, 21]); + // only distribution to 21 and 31. + assert_eq!(assignments.iter().find(|a| a.who == 1).unwrap().distribution.len(), 2); }); } @@ -1864,15 +1863,15 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election_elected() { assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31])); // winners should be 21 and 31. Otherwise this election is taking duplicates into account. - let election_result = ::ElectionProvider::elect().unwrap(); - - assert_eq_uvec!( - election_result, - vec![ - (21, Support:: { total: 2500, voters: vec![(21, 1000), (3, 1000), (1, 500)] }), - (11, Support:: { total: 1500, voters: vec![(11, 1000), (1, 500)] }), - ] - ); + let sp_npos_elections::ElectionResult { + winners, + assignments, + } = Staking::do_phragmen::(0).unwrap(); + + let winners = sp_npos_elections::to_without_backing(winners); + assert_eq!(winners, vec![21, 11]); + // only distribution to 21 and 31. + assert_eq!(assignments.iter().find(|a| a.who == 1).unwrap().distribution.len(), 2); }); } @@ -2882,7 +2881,6 @@ fn remove_multi_deferred() { }) } -/* mod offchain_election { use crate::*; use codec::Encode; @@ -3026,7 +3024,7 @@ mod offchain_election { assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); run_to_block(40); - assert_session_era!(4, 0); + assert_session_era!(4, 1); assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); assert!(Staking::snapshot_nominators().is_none()); assert!(Staking::snapshot_validators().is_none()); @@ -3044,7 +3042,7 @@ mod offchain_election { assert!(Staking::snapshot_validators().is_some()); run_to_block(90); - assert_session_era!(9, 1); + assert_session_era!(9, 2); assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); assert!(Staking::snapshot_nominators().is_none()); assert!(Staking::snapshot_validators().is_none()); @@ -4170,7 +4168,6 @@ mod offchain_election { }) } } -*/ #[test] fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_validator() { @@ -4235,7 +4232,6 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid }); } - #[test] fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // should check that: @@ -4680,6 +4676,39 @@ fn offences_weight_calculated_correctly() { }); } +#[test] +fn on_initialize_weight_is_correct() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + assert_eq!(Validators::::iter().count(), 0); + assert_eq!(Nominators::::iter().count(), 0); + // When this pallet has nothing, we do 4 reads each block + let base_weight = ::DbWeight::get().reads(4); + assert_eq!(base_weight, Staking::on_initialize(0)); + }); + + ExtBuilder::default() + .offchain_election_ext() + .validator_count(4) + .has_stakers(false) + .build() + .execute_with(|| { + crate::tests::offchain_election::build_offchain_election_test_ext(); + run_to_block(11); + Staking::on_finalize(System::block_number()); + System::set_block_number((System::block_number() + 1).into()); + Timestamp::set_timestamp(System::block_number() * 1000 + INIT_TIMESTAMP); + Session::on_initialize(System::block_number()); + + assert_eq!(Validators::::iter().count(), 4); + assert_eq!(Nominators::::iter().count(), 5); + // With 4 validators and 5 nominator, we should increase weight by: + // - (4 + 5) reads + // - 3 Writes + let final_weight = ::DbWeight::get().reads_writes(4 + 9, 3); + assert_eq!(final_weight, Staking::on_initialize(System::block_number())); + }); +} + #[test] fn payout_creates_controller() { ExtBuilder::default() @@ -5007,7 +5036,8 @@ mod election_data_provider { 45 ); assert_eq!(staking_events().len(), 1); - assert_eq!(*staking_events().last().unwrap(), RawEvent::StakingElection); + // TODO: TWO_PHASE: remove the internal value. + assert_eq!(*staking_events().last().unwrap(), RawEvent::StakingElection(ElectionCompute::OnChain)); for b in 21..45 { run_to_block(b); @@ -5024,7 +5054,8 @@ mod election_data_provider { 70 ); assert_eq!(staking_events().len(), 3); - assert_eq!(*staking_events().last().unwrap(), RawEvent::StakingElection); + // TODO: TWO_PHASE: remove the internal value. + assert_eq!(*staking_events().last().unwrap(), RawEvent::StakingElection(ElectionCompute::OnChain)); }) } } From 386088550c541b60fd2e5bd767819cd30c4d4fb2 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 5 Jan 2021 14:19:03 +0000 Subject: [PATCH 34/62] Revert Staking fuzzer. --- frame/staking/fuzzer/.gitignore | 2 + frame/staking/fuzzer/Cargo.lock | 2294 +++++++++++++++++++ frame/staking/fuzzer/Cargo.toml | 34 + frame/staking/fuzzer/src/mock.rs | 184 ++ frame/staking/fuzzer/src/submit_solution.rs | 182 ++ 5 files changed, 2696 insertions(+) create mode 100644 frame/staking/fuzzer/.gitignore create mode 100644 frame/staking/fuzzer/Cargo.lock create mode 100644 frame/staking/fuzzer/Cargo.toml create mode 100644 frame/staking/fuzzer/src/mock.rs create mode 100644 frame/staking/fuzzer/src/submit_solution.rs diff --git a/frame/staking/fuzzer/.gitignore b/frame/staking/fuzzer/.gitignore new file mode 100644 index 0000000000000..3ebcb104d4a50 --- /dev/null +++ b/frame/staking/fuzzer/.gitignore @@ -0,0 +1,2 @@ +hfuzz_target +hfuzz_workspace diff --git a/frame/staking/fuzzer/Cargo.lock b/frame/staking/fuzzer/Cargo.lock new file mode 100644 index 0000000000000..e451e12d10131 --- /dev/null +++ b/frame/staking/fuzzer/Cargo.lock @@ -0,0 +1,2294 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "ahash" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f33b5018f120946c1dcf279194f238a9f146725593ead1c08fa47ff22b0b5d3" +dependencies = [ + "const-random", +] + +[[package]] +name = "aho-corasick" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +dependencies = [ + "memchr", +] + +[[package]] +name = "alga" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f823d037a7ec6ea2197046bafd4ae150e6bc36f9ca347404f46a46823fa84f2" +dependencies = [ + "approx", + "num-complex", + "num-traits", +] + +[[package]] +name = "approx" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arbitrary" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75153c95fdedd7db9732dfbfc3702324a1627eec91ba56e37cd0ac78314ab2ed" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +dependencies = [ + "nodrop", +] + +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "backtrace" +version = "0.3.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e" +dependencies = [ + "backtrace-sys", + "cfg-if", + "libc", + "rustc-demangle", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "base58" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "bitmask" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da9b3d9f6f585199287a473f4f8dfab6566cf827d15c00c219f53c645687ead" + +[[package]] +name = "bitvec" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium", +] + +[[package]] +name = "blake2-rfc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" +dependencies = [ + "arrayvec 0.4.12", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "bumpalo" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" + +[[package]] +name = "byte-slice-cast" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "cc" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "clear_on_drop" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" +dependencies = [ + "cc", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "const-random" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" +dependencies = [ + "const-random-macro", + "proc-macro-hack", +] + +[[package]] +name = "const-random-macro" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" +dependencies = [ + "getrandom", + "proc-macro-hack", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-mac" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +dependencies = [ + "generic-array", + "subtle 1.0.0", +] + +[[package]] +name = "curve25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26778518a7f6cffa1d25a44b602b62b979bd88adb9e99ffec546998cf3404839" +dependencies = [ + "byteorder", + "digest", + "rand_core 0.5.1", + "subtle 2.2.2", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "0.99.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2323f3f47db9a0e77ce7a300605d8d2098597fc451ed1a97bb1f6411bb550a7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.0-pre.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978710b352437433c97b2bff193f2fb1dfd58a093f863dd95e225a19baa599a2" +dependencies = [ + "clear_on_drop", + "curve25519-dalek", + "rand 0.7.3", + "sha2", +] + +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" + +[[package]] +name = "environmental" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516aa8d7a71cb00a1c4146f0798549b93d083d4f189b3ced8f3de6b8f11ee6c4" + +[[package]] +name = "failure" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fixed-hash" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32529fc42e86ec06e5047092082aab9ad459b070c5d2a76b14f4f5ce70bf2e84" +dependencies = [ + "byteorder", + "rand 0.7.3", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "frame-benchmarking" +version = "2.0.0-alpha.5" +dependencies = [ + "frame-support", + "frame-system", + "linregress", + "parity-scale-codec", + "sp-api", + "sp-io", + "sp-runtime", + "sp-runtime-interface", + "sp-std", +] + +[[package]] +name = "frame-metadata" +version = "11.0.0-alpha.5" +dependencies = [ + "parity-scale-codec", + "serde", + "sp-core", + "sp-std", +] + +[[package]] +name = "frame-support" +version = "2.0.0-alpha.5" +dependencies = [ + "bitmask", + "frame-metadata", + "frame-support-procedural", + "impl-trait-for-tuples", + "log", + "once_cell", + "parity-scale-codec", + "paste", + "serde", + "sp-arithmetic", + "sp-core", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-std", + "tracing", +] + +[[package]] +name = "frame-support-procedural" +version = "2.0.0-alpha.5" +dependencies = [ + "frame-support-procedural-tools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frame-support-procedural-tools" +version = "2.0.0-alpha.5" +dependencies = [ + "frame-support-procedural-tools-derive", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frame-support-procedural-tools-derive" +version = "2.0.0-alpha.5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frame-system" +version = "2.0.0-alpha.5" +dependencies = [ + "frame-support", + "impl-trait-for-tuples", + "parity-scale-codec", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-version", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "futures" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" + +[[package]] +name = "futures-executor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" + +[[package]] +name = "futures-macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" + +[[package]] +name = "futures-task" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" + +[[package]] +name = "futures-util" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +dependencies = [ + "typenum", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hash-db" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" + +[[package]] +name = "hash256-std-hasher" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" +dependencies = [ + "ahash", + "autocfg 0.1.7", +] + +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" + +[[package]] +name = "hmac" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" +dependencies = [ + "crypto-mac", + "digest", +] + +[[package]] +name = "hmac-drbg" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" +dependencies = [ + "digest", + "generic-array", + "hmac", +] + +[[package]] +name = "impl-codec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-serde" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-serde" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bbe9ea9b182f0fb1cabbd61f4ff9b7b7b9197955e95a7e4c27de5055eb29ff8" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef5550a42e3740a0e71f909d4c861056a284060af885ae7aa6242820f920d9d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "integer-sqrt" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65877bf7d44897a473350b1046277941cee20b263397e90869c50b6e766088b" + +[[package]] +name = "js-sys" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a27d435371a2fa5b6d2b028a74bbdb1234f308da363226a2854ca3ff8ba7055" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" + +[[package]] +name = "libfuzzer-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d718794b8e23533b9069bd2c4597d69e41cc7ab1c02700a502971aca0cdcf24" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" + +[[package]] +name = "libsecp256k1" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" +dependencies = [ + "arrayref", + "crunchy", + "digest", + "hmac-drbg", + "rand 0.7.3", + "sha2", + "subtle 2.2.2", + "typenum", +] + +[[package]] +name = "linregress" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9290cf6f928576eeb9c096c6fad9d8d452a0a1a70a2bbffa6e36064eedc0aac9" +dependencies = [ + "failure", + "nalgebra", + "statrs", +] + +[[package]] +name = "lock_api" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matrixmultiply" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4f7ec66360130972f34830bfad9ef05c6610a43938a467bcc9ab9369ab3478f" +dependencies = [ + "rawpointer", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" + +[[package]] +name = "memory-db" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58381b20ebe2c578e75dececd9da411414903415349548ccc46aac3209cdfbc" +dependencies = [ + "ahash", + "hash-db", + "hashbrown", + "parity-util-mem", +] + +[[package]] +name = "memory_units" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" + +[[package]] +name = "merlin" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6feca46f4fa3443a01769d768727f10c10a20fdb65e52dc16a81f0c8269bb78" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.5.1", + "zeroize", +] + +[[package]] +name = "nalgebra" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaa9fddbc34c8c35dd2108515587b8ce0cab396f17977b8c738568e4edb521a2" +dependencies = [ + "alga", + "approx", + "generic-array", + "matrixmultiply", + "num-complex", + "num-rational", + "num-traits", + "rand 0.6.5", + "typenum", +] + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg 1.0.0", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg 1.0.0", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +dependencies = [ + "autocfg 1.0.0", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg 1.0.0", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +dependencies = [ + "autocfg 1.0.0", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" +dependencies = [ + "parking_lot 0.9.0", +] + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "pallet-authorship" +version = "2.0.0-alpha.5" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "parity-scale-codec", + "sp-authorship", + "sp-core", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-balances" +version = "2.0.0-alpha.5" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "serde", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-indices" +version = "2.0.0-alpha.5" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "serde", + "sp-core", + "sp-io", + "sp-keyring", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-session" +version = "2.0.0-alpha.5" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "pallet-timestamp", + "parity-scale-codec", + "serde", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", + "sp-trie", +] + +[[package]] +name = "pallet-staking" +version = "2.0.0-alpha.5" +dependencies = [ + "frame-support", + "frame-system", + "pallet-authorship", + "pallet-indices", + "pallet-session", + "parity-scale-codec", + "rand 0.7.3", + "serde", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-staking", + "sp-std", + "static_assertions", +] + +[[package]] +name = "pallet-staking-fuzz" +version = "0.0.0" +dependencies = [ + "frame-support", + "frame-system", + "libfuzzer-sys", + "pallet-balances", + "pallet-indices", + "pallet-session", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-timestamp", + "parity-scale-codec", + "rand 0.7.3", + "sp-core", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-staking-reward-curve" +version = "2.0.0-alpha.5" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pallet-timestamp" +version = "2.0.0-alpha.5" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "parity-scale-codec", + "serde", + "sp-inherents", + "sp-runtime", + "sp-std", + "sp-timestamp", +] + +[[package]] +name = "parity-scale-codec" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "329c8f7f4244ddb5c37c103641027a76c530e65e8e4b8240b29f81ea40508b17" +dependencies = [ + "arrayvec 0.5.1", + "bitvec", + "byte-slice-cast", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a0ec292e92e8ec7c58e576adacc1e3f399c597c8f263c42f18420abe58e7245" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "parity-util-mem" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e42755f26e5ea21a6a819d9e63cbd70713e9867a2b767ec2cc65ca7659532c5" +dependencies = [ + "cfg-if", + "impl-trait-for-tuples", + "parity-util-mem-derive", + "parking_lot 0.10.0", + "primitive-types", + "winapi", +] + +[[package]] +name = "parity-util-mem-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" +dependencies = [ + "proc-macro2", + "syn", + "synstructure", +] + +[[package]] +name = "parity-wasm" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" + +[[package]] +name = "parking_lot" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" +dependencies = [ + "lock_api", + "parking_lot_core 0.6.2", + "rustc_version", +] + +[[package]] +name = "parking_lot" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" +dependencies = [ + "lock_api", + "parking_lot_core 0.7.0", +] + +[[package]] +name = "parking_lot_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "rustc_version", + "smallvec 0.6.13", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "smallvec 1.2.0", + "winapi", +] + +[[package]] +name = "paste" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092d791bf7847f70bbd49085489fba25fc2c193571752bff9e36e74e72403932" +dependencies = [ + "paste-impl", + "proc-macro-hack", +] + +[[package]] +name = "paste-impl" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406c23fb4c45cc6f68a9bbabb8ec7bd6f8cfcbd17e9e8f72c2460282f8325729" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pbkdf2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" +dependencies = [ + "byteorder", + "crypto-mac", +] + +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" + +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" + +[[package]] +name = "primitive-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5e4b9943a2da369aec5e96f7c10ebc74fcf434d39590d974b0a3460e6f67fbb" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-serde 0.3.0", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420" + +[[package]] +name = "proc-macro-nested" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" + +[[package]] +name = "proc-macro2" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" + +[[package]] +name = "rand" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "winapi", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc 0.1.0", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "regex" +version = "1.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "schnorrkel" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" +dependencies = [ + "arrayref", + "arrayvec 0.5.1", + "curve25519-dalek", + "getrandom", + "merlin", + "rand 0.7.3", + "rand_core 0.5.1", + "sha2", + "subtle 2.2.2", + "zeroize", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "send_wrapper" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4" + +[[package]] +name = "serde" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" +dependencies = [ + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" +dependencies = [ + "maybe-uninit", +] + +[[package]] +name = "smallvec" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" + +[[package]] +name = "sp-api" +version = "2.0.0-alpha.5" +dependencies = [ + "hash-db", + "parity-scale-codec", + "sp-api-proc-macro", + "sp-core", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-version", +] + +[[package]] +name = "sp-api-proc-macro" +version = "2.0.0-alpha.5" +dependencies = [ + "blake2-rfc", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-application-crypto" +version = "2.0.0-alpha.5" +dependencies = [ + "parity-scale-codec", + "serde", + "sp-core", + "sp-io", + "sp-std", +] + +[[package]] +name = "sp-arithmetic" +version = "2.0.0-alpha.5" +dependencies = [ + "integer-sqrt", + "num-traits", + "parity-scale-codec", + "serde", + "sp-debug-derive", + "sp-std", +] + +[[package]] +name = "sp-authorship" +version = "2.0.0-alpha.5" +dependencies = [ + "parity-scale-codec", + "sp-inherents", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "sp-core" +version = "2.0.0-alpha.5" +dependencies = [ + "base58", + "blake2-rfc", + "byteorder", + "ed25519-dalek", + "futures", + "hash-db", + "hash256-std-hasher", + "hex", + "impl-serde 0.3.0", + "lazy_static", + "libsecp256k1", + "log", + "num-traits", + "parity-scale-codec", + "parity-util-mem", + "parking_lot 0.10.0", + "primitive-types", + "rand 0.7.3", + "regex", + "schnorrkel", + "serde", + "sha2", + "sp-debug-derive", + "sp-externalities", + "sp-runtime-interface", + "sp-std", + "sp-storage", + "substrate-bip39", + "tiny-bip39", + "tiny-keccak", + "twox-hash", + "wasmi", + "zeroize", +] + +[[package]] +name = "sp-debug-derive" +version = "2.0.0-alpha.5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-externalities" +version = "0.8.0-alpha.5" +dependencies = [ + "environmental", + "sp-std", + "sp-storage", +] + +[[package]] +name = "sp-inherents" +version = "2.0.0-alpha.5" +dependencies = [ + "derive_more", + "parity-scale-codec", + "parking_lot 0.10.0", + "sp-core", + "sp-std", +] + +[[package]] +name = "sp-io" +version = "2.0.0-alpha.5" +dependencies = [ + "hash-db", + "libsecp256k1", + "log", + "parity-scale-codec", + "sp-core", + "sp-externalities", + "sp-runtime-interface", + "sp-state-machine", + "sp-std", + "sp-trie", + "sp-wasm-interface", +] + +[[package]] +name = "sp-keyring" +version = "2.0.0-alpha.5" +dependencies = [ + "lazy_static", + "sp-core", + "sp-runtime", + "strum", +] + +[[package]] +name = "sp-panic-handler" +version = "2.0.0-alpha.5" +dependencies = [ + "backtrace", + "log", +] + +[[package]] +name = "sp-npos-elections" +version = "2.0.0-alpha.5" +dependencies = [ + "parity-scale-codec", + "serde", + "sp-npos-elections-compact", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "sp-npos-elections-compact" +version = "2.0.0-rc3" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-runtime" +version = "2.0.0-alpha.5" +dependencies = [ + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "parity-util-mem", + "paste", + "rand 0.7.3", + "serde", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", + "sp-inherents", + "sp-io", + "sp-std", +] + +[[package]] +name = "sp-runtime-interface" +version = "2.0.0-alpha.5" +dependencies = [ + "parity-scale-codec", + "primitive-types", + "sp-externalities", + "sp-runtime-interface-proc-macro", + "sp-std", + "sp-wasm-interface", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "2.0.0-alpha.5" +dependencies = [ + "Inflector", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-staking" +version = "2.0.0-alpha.5" +dependencies = [ + "parity-scale-codec", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "sp-state-machine" +version = "0.8.0-alpha.5" +dependencies = [ + "hash-db", + "log", + "num-traits", + "parity-scale-codec", + "parking_lot 0.10.0", + "rand 0.7.3", + "sp-core", + "sp-externalities", + "sp-panic-handler", + "sp-trie", + "trie-db", + "trie-root", +] + +[[package]] +name = "sp-std" +version = "2.0.0-alpha.5" + +[[package]] +name = "sp-storage" +version = "2.0.0-alpha.5" +dependencies = [ + "impl-serde 0.2.3", + "serde", + "sp-debug-derive", + "sp-std", +] + +[[package]] +name = "sp-timestamp" +version = "2.0.0-alpha.5" +dependencies = [ + "impl-trait-for-tuples", + "parity-scale-codec", + "sp-api", + "sp-inherents", + "sp-runtime", + "sp-std", + "wasm-timer", +] + +[[package]] +name = "sp-trie" +version = "2.0.0-alpha.5" +dependencies = [ + "hash-db", + "memory-db", + "parity-scale-codec", + "sp-core", + "sp-std", + "trie-db", + "trie-root", +] + +[[package]] +name = "sp-version" +version = "2.0.0-alpha.5" +dependencies = [ + "impl-serde 0.2.3", + "parity-scale-codec", + "serde", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "sp-wasm-interface" +version = "2.0.0-alpha.5" +dependencies = [ + "impl-trait-for-tuples", + "parity-scale-codec", + "sp-std", + "wasmi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "statrs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10102ac8d55e35db2b3fafc26f81ba8647da2e15879ab686a67e6d19af2685e8" +dependencies = [ + "rand 0.5.6", +] + +[[package]] +name = "strum" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0054a7df764039a6cd8592b9de84be4bec368ff081d203a7d5371cbfa8e65c81" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "substrate-bip39" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c004e8166d6e0aa3a9d5fa673e5b7098ff25f930de1013a21341988151e681bb" +dependencies = [ + "hmac", + "pbkdf2", + "schnorrkel", + "sha2", +] + +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" + +[[package]] +name = "subtle" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" + +[[package]] +name = "syn" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tiny-bip39" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0165e045cc2ae1660270ca65e1676dbaab60feb0f91b10f7d0665e9b47e31f2" +dependencies = [ + "failure", + "hmac", + "once_cell", + "pbkdf2", + "rand 0.7.3", + "rustc-hash", + "sha2", + "unicode-normalization", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2953ca5148619bc99695c1274cb54c5275bbb913c6adad87e72eaf8db9787f69" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +dependencies = [ + "serde", +] + +[[package]] +name = "tracing" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1721cc8cf7d770cc4257872507180f35a4797272f5962f24c806af9e7faf52ab" +dependencies = [ + "cfg-if", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbad39da2f9af1cae3016339ad7f2c7a9e870f12e8fd04c4fd7ef35b30c0d2b" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "trie-db" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9222c50cc325855621271157c973da27a0dcd26fa06f8edf81020bd2333df0" +dependencies = [ + "hash-db", + "hashbrown", + "log", + "rustc-hex", + "smallvec 1.2.0", +] + +[[package]] +name = "trie-root" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "652931506d2c1244d7217a70b99f56718a7b4161b37f04e7cd868072a99f68cd" +dependencies = [ + "hash-db", +] + +[[package]] +name = "twox-hash" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" +dependencies = [ + "rand 0.7.3", +] + +[[package]] +name = "typenum" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" + +[[package]] +name = "uint" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e75a4cdd7b87b28840dba13c483b9a88ee6bbf16ba5c951ee1ecfcf723078e0d" +dependencies = [ + "byteorder", + "crunchy", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" +dependencies = [ + "smallvec 1.2.0", +] + +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasm-bindgen" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc57ce05287f8376e998cbddfb4c8cb43b84a7ec55cf4551d7c00eef317a47f" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967d37bf6c16cca2973ca3af071d0a2523392e4a594548155d89a678f4237cd" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7add542ea1ac7fdaa9dc25e031a6af33b7d63376292bd24140c637d00d1c312a" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf76fe7d25ac79748a37538b7daeed1c7a6867c92d3245c12c6222e4a20d639" + +[[package]] +name = "wasm-timer" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "324c5e65a08699c9c4334ba136597ab22b85dccd4b65dd1e36ccf8f723a95b54" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.9.0", + "pin-utils", + "send_wrapper", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmi" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf617d864d25af3587aa745529f7aaa541066c876d57e050c0d0c85c61c92aff" +dependencies = [ + "libc", + "memory_units", + "num-rational", + "num-traits", + "parity-wasm", + "wasmi-validation", +] + +[[package]] +name = "wasmi-validation" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93" +dependencies = [ + "parity-wasm", +] + +[[package]] +name = "web-sys" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6f51648d8c56c366144378a33290049eafdd784071077f6fe37dae64c1c4cb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zeroize" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/frame/staking/fuzzer/Cargo.toml b/frame/staking/fuzzer/Cargo.toml new file mode 100644 index 0000000000000..e1431aa54d4a7 --- /dev/null +++ b/frame/staking/fuzzer/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "pallet-staking-fuzz" +version = "0.0.0" +authors = ["Automatically generated"] +publish = false +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet staking fuzzing" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +honggfuzz = "0.5" +codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false, features = ["derive"] } +pallet-staking = { version = "2.0.0", path = "..", features = ["runtime-benchmarks"] } +pallet-staking-reward-curve = { version = "2.0.0", path = "../reward-curve" } +pallet-session = { version = "2.0.0", path = "../../session" } +pallet-indices = { version = "2.0.0", path = "../../indices" } +pallet-balances = { version = "2.0.0", path = "../../balances" } +pallet-timestamp = { version = "2.0.0", path = "../../timestamp" } +frame-system = { version = "2.0.0", path = "../../system" } +frame-support = { version = "2.0.0", path = "../../support" } +sp-std = { version = "2.0.0", path = "../../../primitives/std" } +sp-io ={ version = "2.0.0", path = "../../../primitives/io" } +sp-core = { version = "2.0.0", path = "../../../primitives/core" } +sp-npos-elections = { version = "2.0.0", path = "../../../primitives/npos-elections" } +sp-runtime = { version = "2.0.0", path = "../../../primitives/runtime" } + +[[bin]] +name = "submit_solution" +path = "src/submit_solution.rs" diff --git a/frame/staking/fuzzer/src/mock.rs b/frame/staking/fuzzer/src/mock.rs new file mode 100644 index 0000000000000..b3c9dd9f57b60 --- /dev/null +++ b/frame/staking/fuzzer/src/mock.rs @@ -0,0 +1,184 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2021 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Mock file for staking fuzzing. + +use frame_support::{impl_outer_origin, impl_outer_dispatch, parameter_types}; + +type AccountId = u64; +type AccountIndex = u32; +type BlockNumber = u64; +type Balance = u64; + +pub type System = frame_system::Module; +pub type Balances = pallet_balances::Module; +pub type Staking = pallet_staking::Module; +pub type Indices = pallet_indices::Module; +pub type Session = pallet_session::Module; + +impl_outer_origin! { + pub enum Origin for Test where system = frame_system {} +} + +impl_outer_dispatch! { + pub enum Call for Test where origin: Origin { + staking::Staking, + } +} + +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct Test; + +impl frame_system::Config for Test { + type BaseCallFilter = (); + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = AccountIndex; + type BlockNumber = BlockNumber; + type Call = Call; + type Hash = sp_core::H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = Indices; + type Header = sp_runtime::testing::Header; + type Event = (); + type BlockHashCount = (); + type Version = (); + type PalletInfo = (); + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (Balances,); + type SystemWeightInfo = (); + type SS58Prefix = (); +} +parameter_types! { + pub const ExistentialDeposit: Balance = 10; +} +impl pallet_balances::Config for Test { + type MaxLocks = (); + type Balance = Balance; + type Event = (); + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); +} +impl pallet_indices::Config for Test { + type AccountIndex = AccountIndex; + type Event = (); + type Currency = Balances; + type Deposit = (); + type WeightInfo = (); +} +parameter_types! { + pub const MinimumPeriod: u64 = 5; +} +impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} +impl pallet_session::historical::Config for Test { + type FullIdentification = pallet_staking::Exposure; + type FullIdentificationOf = pallet_staking::ExposureOf; +} + +sp_runtime::impl_opaque_keys! { + pub struct SessionKeys { + pub foo: sp_runtime::testing::UintAuthorityId, + } +} + +pub struct TestSessionHandler; +impl pallet_session::SessionHandler for TestSessionHandler { + const KEY_TYPE_IDS: &'static [sp_runtime::KeyTypeId] = &[]; + + fn on_genesis_session(_validators: &[(AccountId, Ks)]) {} + + fn on_new_session( + _: bool, + _: &[(AccountId, Ks)], + _: &[(AccountId, Ks)], + ) {} + + fn on_disabled(_: usize) {} +} + +impl pallet_session::Config for Test { + type SessionManager = pallet_session::historical::NoteHistoricalRoot; + type Keys = SessionKeys; + type ShouldEndSession = pallet_session::PeriodicSessions<(), ()>; + type NextSessionRotation = pallet_session::PeriodicSessions<(), ()>; + type SessionHandler = TestSessionHandler; + type Event = (); + type ValidatorId = AccountId; + type ValidatorIdOf = pallet_staking::StashOf; + type DisabledValidatorsThreshold = (); + type WeightInfo = (); +} +pallet_staking_reward_curve::build! { + const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} +parameter_types! { + pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; + pub const MaxNominatorRewardedPerValidator: u32 = 64; + pub const MaxIterations: u32 = 20; +} + +pub type Extrinsic = sp_runtime::testing::TestXt; + +impl frame_system::offchain::SendTransactionTypes for Test where + Call: From, +{ + type OverarchingCall = Call; + type Extrinsic = Extrinsic; +} + +impl pallet_staking::Config for Test { + type Currency = Balances; + type UnixTime = pallet_timestamp::Module; + type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; + type RewardRemainder = (); + type Event = (); + type Slash = (); + type Reward = (); + type SessionsPerEra = (); + type SlashDeferDuration = (); + type SlashCancelOrigin = frame_system::EnsureRoot; + type BondingDuration = (); + type SessionInterface = Self; + type RewardCurve = RewardCurve; + type NextNewSession = Session; + type ElectionLookahead = (); + type Call = Call; + type MaxIterations = MaxIterations; + type MinSolutionScoreBump = (); + type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; + type UnsignedPriority = (); + type OffchainSolutionWeightLimit = (); + type WeightInfo = (); +} diff --git a/frame/staking/fuzzer/src/submit_solution.rs b/frame/staking/fuzzer/src/submit_solution.rs new file mode 100644 index 0000000000000..d94ee49b96db4 --- /dev/null +++ b/frame/staking/fuzzer/src/submit_solution.rs @@ -0,0 +1,182 @@ +// This file is part of Substrate. + +// Copyright (C) 2020-2021 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Fuzzing for staking pallet. +//! +//! HFUZZ_RUN_ARGS="-n 8" cargo hfuzz run submit_solution + +use honggfuzz::fuzz; + +use mock::Test; +use pallet_staking::testing_utils::*; +use frame_support::{assert_ok, storage::StorageValue, traits::UnfilteredDispatchable}; +use frame_system::RawOrigin; +use sp_runtime::DispatchError; +use sp_core::offchain::{testing::TestOffchainExt, OffchainExt}; +use pallet_staking::{EraElectionStatus, ElectionStatus, Module as Staking, Call as StakingCall}; + +mod mock; + +#[repr(u32)] +#[allow(dead_code)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Mode { + /// Initial submission. This will be rather cheap. + InitialSubmission, + /// A better submission that will replace the previous ones. This is the most expensive. + StrongerSubmission, + /// A weak submission that will be rejected. This will be rather cheap. + WeakerSubmission, +} + +pub fn new_test_ext(iterations: u32) -> sp_io::TestExternalities { + let mut ext: sp_io::TestExternalities = frame_system::GenesisConfig::default() + .build_storage::() + .map(Into::into) + .expect("Failed to create test externalities."); + + let (offchain, offchain_state) = TestOffchainExt::new(); + + let mut seed = [0u8; 32]; + seed[0..4].copy_from_slice(&iterations.to_le_bytes()); + offchain_state.write().seed = seed; + + ext.register_extension(OffchainExt::new(offchain)); + + ext +} + +fn main() { + let to_range = |x: u32, a: u32, b: u32| { + let collapsed = x % b; + if collapsed >= a { + collapsed + } else { + collapsed + a + } + }; + loop { + fuzz!(|data: (u32, u32, u32, u32, u32)| { + let (mut num_validators, mut num_nominators, mut edge_per_voter, mut to_elect, mode_u32) = data; + // always run with 5 iterations. + let mut ext = new_test_ext(5); + let mode: Mode = unsafe { std::mem::transmute(mode_u32) }; + num_validators = to_range(num_validators, 50, 1000); + num_nominators = to_range(num_nominators, 50, 2000); + edge_per_voter = to_range(edge_per_voter, 1, 16); + to_elect = to_range(to_elect, 20, num_validators); + + let do_reduce = true; + + println!("+++ instance with params {} / {} / {} / {} / {:?}({})", + num_nominators, + num_validators, + edge_per_voter, + to_elect, + mode, + mode_u32, + ); + + ext.execute_with(|| { + // initial setup + init_active_era(); + + assert_ok!(create_validators_with_nominators_for_era::( + num_validators, + num_nominators, + edge_per_voter as usize, + true, + None, + )); + + >::put(ElectionStatus::Open(1)); + assert!(>::create_stakers_snapshot().0); + + let origin = RawOrigin::Signed(create_funded_user::("fuzzer", 0, 100)); + + // stuff to submit + let (winners, compact, score, size) = match mode { + Mode::InitialSubmission => { + // No need to setup anything + get_seq_phragmen_solution::(do_reduce) + }, + Mode::StrongerSubmission => { + let (winners, compact, score, size) = get_weak_solution::(false); + println!("Weak on chain score = {:?}", score); + assert_ok!( + >::submit_election_solution( + origin.clone().into(), + winners, + compact, + score, + current_era::(), + size, + ) + ); + get_seq_phragmen_solution::(do_reduce) + }, + Mode::WeakerSubmission => { + let (winners, compact, score, size) = get_seq_phragmen_solution::(do_reduce); + println!("Strong on chain score = {:?}", score); + assert_ok!( + >::submit_election_solution( + origin.clone().into(), + winners, + compact, + score, + current_era::(), + size, + ) + ); + get_weak_solution::(false) + } + }; + + // must have chosen correct number of winners. + assert_eq!(winners.len() as u32, >::validator_count()); + + // final call and origin + let call = StakingCall::::submit_election_solution( + winners, + compact, + score, + current_era::(), + size, + ); + + // actually submit + match mode { + Mode::WeakerSubmission => { + assert_eq!( + call.dispatch_bypass_filter(origin.into()).unwrap_err().error, + DispatchError::Module { + index: 0, + error: 16, + message: Some("OffchainElectionWeakSubmission"), + }, + ); + }, + // NOTE: so exhaustive pattern doesn't work here.. maybe some rust issue? + // or due to `#[repr(u32)]`? + Mode::InitialSubmission | Mode::StrongerSubmission => { + assert_ok!(call.dispatch_bypass_filter(origin.into())); + } + }; + }) + }); + } +} From 392f35ae782f6825f8272b02a4f2e36ff6e6ff95 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 5 Jan 2021 17:04:41 +0000 Subject: [PATCH 35/62] Fix fuzzers --- Cargo.lock | 22 +++++++++++++++ Cargo.toml | 1 + bin/node/runtime/src/lib.rs | 32 +++++++++++++++------- frame/staking/fuzzer/Cargo.toml | 1 + frame/staking/fuzzer/src/mock.rs | 15 ++++++++++ primitives/election-providers/src/lib.rs | 35 ++++++++++++++++++++++-- 6 files changed, 94 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6889dd2720b37..0655e9b35bafb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5019,6 +5019,28 @@ dependencies = [ "substrate-test-utils", ] +[[package]] +name = "pallet-staking-fuzz" +version = "0.0.0" +dependencies = [ + "frame-support", + "frame-system", + "honggfuzz", + "pallet-balances", + "pallet-indices", + "pallet-session", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-timestamp", + "parity-scale-codec", + "sp-core", + "sp-election-providers", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-staking-reward-curve" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 58641c66e4ee4..09ee8b742dffe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,6 +97,7 @@ members = [ "frame/session/benchmarking", "frame/society", "frame/staking", + "frame/staking/fuzzer", "frame/staking/reward-curve", "frame/election-providers", "frame/sudo", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 807136eb55cd7..91e3b8f6d5ada 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -22,6 +22,7 @@ // `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. #![recursion_limit = "256"] + use sp_std::prelude::*; use frame_support::{ construct_runtime, parameter_types, debug, RuntimeDebug, @@ -503,15 +504,26 @@ impl pallet_staking::Config for Runtime { } parameter_types! { + // phase durations pub const SignedPhase: u32 = 25; pub const UnsignedPhase: u32 = 25; + + // signed configs pub const MaxSignedSubmissions: u32 = 10; pub const SignedRewardBase: Balance = 1 * DOLLARS; pub const SignedDepositBase: Balance = 1 * DOLLARS; + pub const SignedDepositByte: Balance = 1 * CENTS; + + // unsigned configs + pub const TwoPhaseUnsignedPriority: TransactionPriority = StakingUnsignedPriority::get() - 1u64; pub const MaxUnsignedIterations: u32 = 10; + pub SolutionImprovementThreshold: Perbill = Perbill::from_rational_approximation(5u32, 10_000); + pub MinerMaxWeight: Weight = RuntimeBlockWeights::get() + .get(DispatchClass::Normal) + .max_extrinsic.expect("Normal extrinsics have a weight limit configured; qed") + .saturating_sub(BlockExecutionWeight::get()); } - impl pallet_two_phase_election_provider::Config for Runtime { type Event = Event; type Currency = Balances; @@ -519,21 +531,21 @@ impl pallet_two_phase_election_provider::Config for Runtime { type UnsignedPhase = UnsignedPhase; type MaxSignedSubmissions = MaxSignedSubmissions; type SignedRewardBase = SignedRewardBase; - type SignedRewardFactor = (); - type SignedRewardMax = (); + type SignedRewardFactor = (); // no score-based reward + type SignedRewardMax = SignedRewardBase; type SignedDepositBase = SignedDepositBase; - type SignedDepositByte = (); - type SignedDepositWeight = (); - type SolutionImprovementThreshold = (); - type SlashHandler = (); + type SignedDepositByte = SignedDepositByte; + type SignedDepositWeight = (); // no weight-based deposit. + type SolutionImprovementThreshold = MinSolutionScoreBump; + type SlashHandler = (); // burn slashes type RewardHandler = (); type MinerMaxIterations = MaxUnsignedIterations; - type MinerMaxWeight = (); - type UnsignedPriority = (); + type MinerMaxWeight = MinerMaxWeight; + type UnsignedPriority = TwoPhaseUnsignedPriority; type DataProvider = Staking; type OnChainAccuracy = Perbill; type CompactSolution = pallet_staking::CompactAssignments; - type WeightInfo = (); + type WeightInfo = pallet_two_phase_election_provider::weights::SubstrateWeight; } parameter_types! { diff --git a/frame/staking/fuzzer/Cargo.toml b/frame/staking/fuzzer/Cargo.toml index e1431aa54d4a7..59f3fc6816a69 100644 --- a/frame/staking/fuzzer/Cargo.toml +++ b/frame/staking/fuzzer/Cargo.toml @@ -27,6 +27,7 @@ sp-std = { version = "2.0.0", path = "../../../primitives/std" } sp-io ={ version = "2.0.0", path = "../../../primitives/io" } sp-core = { version = "2.0.0", path = "../../../primitives/core" } sp-npos-elections = { version = "2.0.0", path = "../../../primitives/npos-elections" } +sp-election-providers = { version = "2.0.0", path = "../../../primitives/election-providers" } sp-runtime = { version = "2.0.0", path = "../../../primitives/runtime" } [[bin]] diff --git a/frame/staking/fuzzer/src/mock.rs b/frame/staking/fuzzer/src/mock.rs index b3c9dd9f57b60..53653aea9d98c 100644 --- a/frame/staking/fuzzer/src/mock.rs +++ b/frame/staking/fuzzer/src/mock.rs @@ -158,6 +158,20 @@ impl frame_system::offchain::SendTransactionTypes for Test where type Extrinsic = Extrinsic; } +pub struct MockElectionProvider; +impl sp_election_providers::ElectionProvider for MockElectionProvider { + type Error = (); + type DataProvider = pallet_staking::Module; + + fn elect() -> Result, Self::Error> { + Err(()) + } + + fn ongoing() -> bool { + false + } +} + impl pallet_staking::Config for Test { type Currency = Balances; type UnixTime = pallet_timestamp::Module; @@ -181,4 +195,5 @@ impl pallet_staking::Config for Test { type UnsignedPriority = (); type OffchainSolutionWeightLimit = (); type WeightInfo = (); + type ElectionProvider = MockElectionProvider; } diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index 93c739d84e9fe..07a733cf05381 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -215,10 +215,28 @@ pub trait ElectionDataProvider { fn put_npos_snapshot( _voters: Vec<(AccountId, VoteWeight, Vec)>, _targets: Vec, - ) { - } + ) {} } +// TODO: only uncomment if needed, else better not to even provide this. +// impl ElectionDataProvider for () { +// fn targets() -> Vec { +// Default::default() +// } +// fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { +// Default::default() +// } +// fn desired_targets() -> u32 { +// Default::default() +// } +// fn feasibility_check_assignment(_: &Assignment) -> Result<(), &'static str> { +// Err("() as ElectionDataProvider cannot do anything.") +// } +// fn next_election_prediction(now: BlockNumber) -> BlockNumber { +// now +// } +// } + /// Something that can compute the result of an election and pass it back to the caller. /// /// This trait only provides an interface to _request_ an election, i.e. @@ -243,3 +261,16 @@ pub trait ElectionProvider { /// This can be used to dynamically check if a stateful election is still on-going or not. fn ongoing() -> bool; } + +// impl ElectionProvider for () { +// type Error = &'static str; +// type DataProvider = (); + +// fn elect() -> Result, Self::Error> { +// Err("() as ElectionProvider cannot do anything.") +// } + +// fn ongoing() -> bool { +// false +// } +// } From 1337e1bbd16358b5619e609ee61f8f3b3bc00cc7 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 6 Jan 2021 09:14:48 +0000 Subject: [PATCH 36/62] Update frame/election-providers/src/two_phase/mod.rs Co-authored-by: Alexander Popiak --- frame/election-providers/src/two_phase/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 31bd97d857d22..eee7b2e7efbf8 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -575,7 +575,7 @@ pub mod pallet { } fn offchain_worker(n: T::BlockNumber) { - // We only run the OCW in the fist block of the unsigned phase. + // We only run the OCW in the first block of the unsigned phase. if Self::set_check_offchain_execution_status(n).is_ok() && Self::current_phase().is_unsigned_open_at(n) From 4f6ec0d9e6477069190848e5b6c425aa641806e0 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 6 Jan 2021 15:02:49 +0000 Subject: [PATCH 37/62] a round of self review --- bin/node/runtime/src/lib.rs | 2 +- .../src/two_phase/benchmarking.rs | 16 ++- .../src/two_phase/macros.rs | 2 +- frame/election-providers/src/two_phase/mod.rs | 24 ++--- .../src/two_phase/signed.rs | 4 +- .../src/two_phase/unsigned.rs | 30 +++--- frame/staking/src/lib.rs | 98 ++++++------------- frame/staking/src/mock.rs | 6 +- frame/staking/src/offchain_election.rs | 15 +-- primitives/election-providers/src/lib.rs | 87 ++++++++-------- primitives/npos-elections/compact/src/lib.rs | 4 +- .../fuzzer/src/phragmen_balancing.rs | 6 +- .../fuzzer/src/phragmms_balancing.rs | 12 ++- primitives/npos-elections/src/lib.rs | 96 ++++++++++-------- primitives/npos-elections/src/tests.rs | 44 +++++++-- 15 files changed, 233 insertions(+), 213 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 91e3b8f6d5ada..8901291968ead 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -538,7 +538,7 @@ impl pallet_two_phase_election_provider::Config for Runtime { type SignedDepositWeight = (); // no weight-based deposit. type SolutionImprovementThreshold = MinSolutionScoreBump; type SlashHandler = (); // burn slashes - type RewardHandler = (); + type RewardHandler = (); // nothing todo upon rewards/ type MinerMaxIterations = MaxUnsignedIterations; type MinerMaxWeight = MinerMaxWeight; type UnsignedPriority = TwoPhaseUnsignedPriority; diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index ca03f88fa3972..f3c341f76bd9f 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -45,11 +45,18 @@ where > as sp_std::convert::TryFrom>::Error: sp_std::fmt::Debug, { assert!(witness.targets >= winners_count, "must have enough targets"); + assert!( + witness.targets >= (>::LIMIT * 2) as u32, + "must have enough targets for unique votes." + ); assert!( witness.voters >= active_voters_count, "must have enough voters" ); - assert!((>::LIMIT as u32) < winners_count, "must have enough winners to give them votes."); + assert!( + (>::LIMIT as u32) < winners_count, + "must have enough winners to give them votes." + ); let stake: u64 = 1000_000; @@ -67,7 +74,7 @@ where .cloned() .collect::>(); - // generate first active voters who must vote for a subset of winners. + // first generate active voters who must vote for a subset of winners. let active_voters = (0..active_voters_count) .map(|i| { // chose a random subset of winners. @@ -115,6 +122,7 @@ where voters: all_voters.clone(), targets: targets.clone(), }); + // write the snapshot to staking or whoever is the data provider. T::DataProvider::put_npos_snapshot(all_voters.clone(), targets.clone()); let stake_of = crate::stake_of_fn!(all_voters, T::AccountId); @@ -283,7 +291,7 @@ benchmarks! { let v in 200 .. 300; // number of targets in snapshot. let t in 80 .. 140; - // number of assignments, i.e. compact.voters_count(). This means the active nominators, + // number of assignments, i.e. compact.voter_count(). This means the active nominators, // thus must be a subset of `v` component. let a in 80 .. 140; // number of desired targets. Must be a subset of `t` component. @@ -292,7 +300,7 @@ benchmarks! { let witness = WitnessData { voters: v, targets: t }; let raw_solution = solution_with_size::(witness, a, d); - assert_eq!(raw_solution.compact.voters_count() as u32, a); + assert_eq!(raw_solution.compact.voter_count() as u32, a); assert_eq!(raw_solution.compact.unique_targets().len() as u32, d); }: { assert_ok!(>::feasibility_check(raw_solution, ElectionCompute::Unsigned)); diff --git a/frame/election-providers/src/two_phase/macros.rs b/frame/election-providers/src/two_phase/macros.rs index 6bd7de658e6ae..9dbcccedc604e 100644 --- a/frame/election-providers/src/two_phase/macros.rs +++ b/frame/election-providers/src/two_phase/macros.rs @@ -21,7 +21,7 @@ macro_rules! log { ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { frame_support::debug::$level!( - target: crate::LOG_TARGET, + target: $crate::LOG_TARGET, concat!("🏦 ", $patter) $(, $values)* ) }; diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 31bd97d857d22..ea4f283639037 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -395,7 +395,7 @@ pub struct RoundSnapshotMetadata { /// /// Note that this is different from [`pallet::Error`]. #[derive(RuntimeDebug, Eq, PartialEq)] -pub enum InternalError { +pub enum ElectionError { /// A feasibility error. Feasibility(FeasibilityError), /// An error in the on-chain fallback. @@ -410,21 +410,21 @@ pub enum InternalError { PoolSubmissionFailed, } -impl From for InternalError { +impl From for ElectionError { fn from(e: crate::onchain::Error) -> Self { - InternalError::OnChainFallback(e) + ElectionError::OnChainFallback(e) } } -impl From for InternalError { +impl From for ElectionError { fn from(e: sp_npos_elections::Error) -> Self { - InternalError::NposElections(e) + ElectionError::NposElections(e) } } -impl From for InternalError { +impl From for ElectionError { fn from(e: FeasibilityError) -> Self { - InternalError::Feasibility(e) + ElectionError::Feasibility(e) } } @@ -582,6 +582,8 @@ pub mod pallet { { let _ = Self::mine_and_submit().map_err(|e| { log!(error, "error while submitting transaction in OCW: {:?}", e) + }).map(|_| { + log!(info, "successfully submitted a solution via OCW at block {}", n) }); } } @@ -676,7 +678,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::submit_unsigned( witness.voters, witness.targets, - solution.compact.voters_count() as u32, + solution.compact.voter_count() as u32, solution.compact.unique_targets().len() as u32 ))] pub fn submit_unsigned( @@ -1048,7 +1050,7 @@ where .map_err::(Into::into)?; // Finally, check that the claimed score was indeed correct. - let known_score = supports.evaluate(); + let known_score = (&supports).evaluate(); ensure!(known_score == score, FeasibilityError::InvalidScore); // let supports = supports.flatten(); @@ -1060,7 +1062,7 @@ where } /// On-chain fallback of election. - fn onchain_fallback() -> Result, InternalError> + fn onchain_fallback() -> Result, ElectionError> where ExtendedBalance: From<::Inner>, { @@ -1077,7 +1079,7 @@ where ExtendedBalance: From>>, ExtendedBalance: From>>, { - type Error = InternalError; // TODO: rename to ELectionError + type Error = ElectionError; type DataProvider = T::DataProvider; fn elect() -> Result, Self::Error> { diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index c026133a96500..d0eaa7d9c4aed 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -49,7 +49,7 @@ where deposit, reward, } = best; - let active_voters = solution.compact.voters_count() as u32; + let active_voters = solution.compact.voter_count() as u32; let feasibility_weight = { // defensive only: at the end of signed phase, snapshot will exits. let RoundSnapshotMetadata { @@ -230,7 +230,7 @@ where let feasibility_weight = T::WeightInfo::feasibility_check( witness.voters, witness.targets, - solution.compact.voters_count() as u32, + solution.compact.voter_count() as u32, solution.compact.unique_targets().len() as u32, ); diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 9c0161e081fc2..2e5d7f0c3a35f 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -40,10 +40,10 @@ where /// Min a new npos solution. pub fn mine_solution( iters: usize, - ) -> Result<(RawSolution>, WitnessData), InternalError> { + ) -> Result<(RawSolution>, WitnessData), ElectionError> { let RoundSnapshot { voters, targets } = - Self::snapshot().ok_or(InternalError::SnapshotUnAvailable)?; - let desired_targets = Self::desired_targets().ok_or(InternalError::SnapshotUnAvailable)?; + Self::snapshot().ok_or(ElectionError::SnapshotUnAvailable)?; + let desired_targets = Self::desired_targets().ok_or(ElectionError::SnapshotUnAvailable)?; seq_phragmen::<_, CompactAccuracyOf>( desired_targets as usize, @@ -61,11 +61,11 @@ where /// Will always reduce the solution as well. pub fn prepare_election_result( election_result: ElectionResult>, - ) -> Result<(RawSolution>, WitnessData), InternalError> { + ) -> Result<(RawSolution>, WitnessData), ElectionError> { // storage items. Note: we have already read this from storage, they must be in cache. let RoundSnapshot { voters, targets } = - Self::snapshot().ok_or(InternalError::SnapshotUnAvailable)?; - let desired_targets = Self::desired_targets().ok_or(InternalError::SnapshotUnAvailable)?; + Self::snapshot().ok_or(ElectionError::SnapshotUnAvailable)?; + let desired_targets = Self::desired_targets().ok_or(ElectionError::SnapshotUnAvailable)?; // closures. let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); @@ -82,7 +82,7 @@ where // convert to staked and reduce. let mut staked = sp_npos_elections::assignment_ratio_to_staked_normalized(assignments, &stake_of) - .map_err::(Into::into)?; + .map_err::(Into::into)?; sp_npos_elections::reduce(&mut staked); // convert back to ration and make compact. @@ -137,7 +137,7 @@ where /// struct. /// /// Note that the solution is already computed, and the winners are elected based on the merit - /// of teh entire stake in the system. Nonetheless, some of the voters will be removed further + /// of the entire stake in the system. Nonetheless, some of the voters will be removed further /// down the line. /// /// Indeed, the score must be computed **after** this step. If this step reduces the score too @@ -146,14 +146,14 @@ where maximum_allowed_voters: u32, mut compact: CompactOf, nominator_index: FN, - ) -> Result, InternalError> + ) -> Result, ElectionError> where for<'r> FN: Fn(&'r T::AccountId) -> Option>, { - match compact.voters_count().checked_sub(maximum_allowed_voters as usize) { + match compact.voter_count().checked_sub(maximum_allowed_voters as usize) { Some(to_remove) if to_remove > 0 => { // grab all voters and sort them by least stake. - let RoundSnapshot { voters, .. } = Self::snapshot().ok_or(InternalError::SnapshotUnAvailable)?; + let RoundSnapshot { voters, .. } = Self::snapshot().ok_or(ElectionError::SnapshotUnAvailable)?; let mut voters_sorted = voters .into_iter() .map(|(who, stake, _)| (who.clone(), stake)) @@ -167,7 +167,7 @@ where .iter() .map(|(who, stake)| (nominator_index(&who), stake)) { - let index = maybe_index.ok_or(InternalError::SnapshotUnAvailable)?; + let index = maybe_index.ok_or(ElectionError::SnapshotUnAvailable)?; if compact.remove_voter(index) { removed += 1 } @@ -303,8 +303,8 @@ where } } - /// Mine a new solution, and submit it back to the chian as an unsigned transaction. - pub(crate) fn mine_and_submit() -> Result<(), InternalError> { + /// Mine a new solution, and submit it back to the chain as an unsigned transaction. + pub(crate) fn mine_and_submit() -> Result<(), ElectionError> { let balancing = Self::get_balancing_iters(); let (raw_solution, witness) = Self::mine_solution(balancing)?; @@ -312,7 +312,7 @@ where let call = Call::submit_unsigned(raw_solution, witness).into(); SubmitTransaction::>::submit_unsigned_transaction(call) - .map_err(|_| InternalError::PoolSubmissionFailed) + .map_err(|_| ElectionError::PoolSubmissionFailed) } pub(crate) fn unsigned_pre_dispatch_checks( diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index fe3f76ecf66df..f1fa390f2496c 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -327,9 +327,10 @@ use frame_system::{ }; use sp_npos_elections::{ ExtendedBalance, Assignment, ElectionScore, ElectionResult as PrimitiveElectionResult, - to_support_map, EvaluateSupport, seq_phragmen, generate_solution_type, - is_score_better, SupportMap, VoteWeight, CompactSolution, PerThing128, + to_supports, EvaluateSupport, seq_phragmen, generate_solution_type, is_score_better, Supports, + VoteWeight, CompactSolution, PerThing128, }; +use sp_election_providers::ElectionProvider; pub use weights::WeightInfo; const STAKING_ID: LockIdentifier = *b"staking "; @@ -792,7 +793,12 @@ pub trait Config: frame_system::Config + SendTransactionTypes> { type CurrencyToVote: CurrencyToVote>; /// Something that provides the election functionality. - type ElectionProvider: sp_election_providers::ElectionProvider>; + type ElectionProvider: sp_election_providers::ElectionProvider< + Self::AccountId, + Self::BlockNumber, + // we only accept an election provider that has staking as data provider + DataProvider = Module, + >; /// Tokens have been minted and are unused for validator-reward. /// See [Era payout](./index.html#era-payout). @@ -2129,7 +2135,7 @@ decl_module! { #[weight = T::WeightInfo::submit_solution_better( size.validators.into(), size.nominators.into(), - compact.voters_count() as u32, + compact.voter_count() as u32, winners.len() as u32, )] pub fn submit_election_solution( @@ -2163,7 +2169,7 @@ decl_module! { #[weight = T::WeightInfo::submit_solution_better( size.validators.into(), size.nominators.into(), - compact.voters_count() as u32, + compact.voter_count() as u32, winners.len() as u32, )] pub fn submit_election_solution_unsigned( @@ -2408,7 +2414,7 @@ impl Module { } } - /// Plan a new session, potentially trigger a new era. + /// Plan a new session potentially trigger a new era. fn new_session(session_index: SessionIndex) -> Option> { if let Some(current_era) = Self::current_era() { // Initial era has been set. @@ -2625,17 +2631,15 @@ impl Module { ); // build the support map thereof in order to evaluate. - let supports = to_support_map::( - &winners, - &staked_assignments, - ).map_err(|_| Error::::OffchainElectionBogusEdge)?; + let supports = to_supports(&winners, &staked_assignments) + .map_err(|_| Error::::OffchainElectionBogusEdge)?; // Check if the score is the same as the claimed one. - let submitted_score = supports.evaluate(); + let submitted_score = (&supports).evaluate(); ensure!(submitted_score == claimed_score, Error::::OffchainElectionBogusScore); // At last, alles Ok. Exposures and store the result. - let exposures = Self::collect_exposure(supports); + let exposures = Self::collect_exposures(supports); log!( info, "💸 A better solution (with compute {:?} and score {:?}) has been validated and stored on chain.", @@ -2771,8 +2775,7 @@ impl Module { // Set staking information for new era. let maybe_new_validators = Self::select_and_update_validators(current_era); - // TODO: TWO_PHASE:: later on, switch to enact_election which uses `T::ElectionProvider`. - // let maybe_new_validators = Self::enact_election(current_era); + let _unused_new_validators = Self::enact_election(current_era); maybe_new_validators } @@ -2889,7 +2892,7 @@ impl Module { Self::slashable_balance_of_fn(), ); - let supports = to_support_map::( + let supports = to_supports( &elected_stashes, &staked_assignments, ) @@ -2902,7 +2905,7 @@ impl Module { .ok()?; // collect exposures - let exposures = Self::collect_exposure(supports); + let exposures = Self::collect_exposures(supports); // In order to keep the property required by `on_session_ending` that we must return the // new validator set even if it's the same as the old, as long as any underlying @@ -2983,46 +2986,10 @@ impl Module { } } - /// Consume a set of [`SupportMap`] from [`sp_npos_elections`] and collect them into a - /// [`Exposure`]. - fn collect_exposure( - supports: SupportMap, - ) -> Vec<(T::AccountId, Exposure>)> { - let total_issuance = T::Currency::total_issuance(); - let to_currency = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); - - supports.into_iter().map(|(validator, support)| { - // build `struct exposure` from `support` - let mut others = Vec::with_capacity(support.voters.len()); - let mut own: BalanceOf = Zero::zero(); - let mut total: BalanceOf = Zero::zero(); - support.voters - .into_iter() - .map(|(nominator, weight)| (nominator, to_currency(weight))) - .for_each(|(nominator, stake)| { - if nominator == validator { - own = own.saturating_add(stake); - } else { - others.push(IndividualExposure { who: nominator, value: stake }); - } - total = total.saturating_add(stake); - }); - - let exposure = Exposure { - own, - others, - total, - }; - - (validator, exposure) - }).collect::)>>() - } - - /// Consume a set of [`Supports`] from [`sp_npos_elections`] and collect them into a /// [`Exposure`]. - fn collect_exposure_flat( - supports: sp_npos_elections::Supports, + fn collect_exposures( + supports: Supports, ) -> Vec<(T::AccountId, Exposure>)> { let total_issuance = T::Currency::total_issuance(); let to_currency = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); @@ -3062,11 +3029,12 @@ impl Module { /// /// Returns `Err(())` if less than [`MinimumValidatorCount`] validators have been elected, `Ok` /// otherwise. + #[allow(dead_code)] // TODO: TWO_PHASE pub fn process_election( flat_supports: sp_npos_elections::Supports, current_era: EraIndex, ) -> Result, ()> { - let exposures = Self::collect_exposure_flat(flat_supports); + let exposures = Self::collect_exposures(flat_supports); let elected_stashes = exposures .iter() .cloned() @@ -3125,21 +3093,11 @@ impl Module { /// Enact and process the election using the `ElectionProvider` type. /// /// This will also process the election, as noted in [`process_election`]. - #[allow(dead_code)] // TODO: TWO_PHASE - fn enact_election(current_era: EraIndex) -> Option> { - use sp_election_providers::ElectionProvider; - T::ElectionProvider::elect() - .map_err(|err| { - log!( - error, - "enacting new validator set at the end of era {} failed due to {:?}", - current_era, - err, - ); - () - }) - .and_then(|flat_supports| Self::process_election(flat_supports, current_era)) - .ok() + fn enact_election(_current_era: EraIndex) -> Option> { + let outcome = T::ElectionProvider::elect().map(|_| ()); + log!(debug, "Experimental election provider outputted {:?}", outcome); + // TODO: TWO_PHASE: This code path shall not return anything for now. + None } /// Remove all associated data of a stash account from the staking system. diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index a47868fc80a47..e637e81125a28 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -27,7 +27,7 @@ use frame_support::{ use sp_core::H256; use sp_io; use sp_npos_elections::{ - to_support_map, reduce, ExtendedBalance, StakedAssignment, ElectionScore, EvaluateSupport, + to_supports, reduce, ExtendedBalance, StakedAssignment, ElectionScore, EvaluateSupport, }; use sp_runtime::{ curve::PiecewiseLinear, @@ -858,7 +858,7 @@ pub(crate) fn horrible_npos_solution( let score = { let (_, _, better_score) = prepare_submission_with(true, true, 0, |_| {}); - let support = to_support_map::(&winners, &staked_assignment).unwrap(); + let support = to_supports::(&winners, &staked_assignment).unwrap(); let score = support.evaluate(); assert!(sp_npos_elections::is_score_better::( @@ -958,7 +958,7 @@ pub(crate) fn prepare_submission_with( Staking::slashable_balance_of_fn(), ); - let support_map = to_support_map( + let support_map = to_supports( winners.as_slice(), staked.as_slice(), ).unwrap(); diff --git a/frame/staking/src/offchain_election.rs b/frame/staking/src/offchain_election.rs index c21fcda73762c..5e88cfe3d9e58 100644 --- a/frame/staking/src/offchain_election.rs +++ b/frame/staking/src/offchain_election.rs @@ -25,7 +25,7 @@ use codec::Decode; use frame_support::{traits::Get, weights::Weight, IterableStorageMap}; use frame_system::offchain::SubmitTransaction; use sp_npos_elections::{ - to_support_map, EvaluateSupport, reduce, Assignment, ElectionResult, ElectionScore, + to_supports, EvaluateSupport, reduce, Assignment, ElectionResult, ElectionScore, ExtendedBalance, CompactSolution, }; use sp_runtime::{ @@ -265,7 +265,10 @@ pub fn trim_to_weight( where for<'r> FN: Fn(&'r T::AccountId) -> Option, { - match compact.voters_count().checked_sub(maximum_allowed_voters as usize) { + match compact + .voter_count() + .checked_sub(maximum_allowed_voters as usize) + { Some(to_remove) if to_remove > 0 => { // grab all voters and sort them by least stake. let balance_of = >::slashable_balance_of_fn(); @@ -300,7 +303,7 @@ where warn, "💸 {} nominators out of {} had to be removed from compact solution due to size limits.", removed, - compact.voters_count() + removed, + compact.voter_count() + removed, ); Ok(compact) } @@ -403,11 +406,11 @@ where T::WeightInfo::submit_solution_better( size.validators.into(), size.nominators.into(), - compact.voters_count() as u32, + compact.voter_count() as u32, winners.len() as u32, ), maximum_allowed_voters, - compact.voters_count(), + compact.voter_count(), ); let compact = trim_to_weight::(maximum_allowed_voters, compact, &nominator_index)?; @@ -423,7 +426,7 @@ where >::slashable_balance_of_fn(), ); - let support_map = to_support_map::(&winners, &staked) + let support_map = to_supports::(&winners, &staked) .map_err(|_| OffchainElectionError::ElectionFailed)?; support_map.evaluate() }; diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index 07a733cf05381..8fe652a05e19b 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -22,7 +22,7 @@ //! //! Something that will provide the functionality of election will implement [`ElectionProvider`], //! whilst needing an associated [`ElectionProvider::DataProvider`], which needs to be fulfilled by -//! an entity implementing [`ElectionDataProvider`]. Most often, the data provider *is* the receiver +//! an entity implementing [`ElectionDataProvider`]. Most often, *the data provider is* the receiver //! of the election, resulting in a diagram as below: //! //! ```ignore @@ -68,9 +68,12 @@ //! 3. A number of desired targets to be elected (i.e. _winners_) //! //! In addition to that, the [`ElectionDataProvider`] must also hint [`ElectionProvider`] at when -//! the next election might happen ([`ElectionDataProvider::next_election_prediction`]). +//! the next election might happen ([`ElectionDataProvider::next_election_prediction`]). A stateless +//! election provider would probably ignore this. A stateful election provider can use this to +//! prepare the election result in advance. +//! //! Nonetheless, an [`ElectionProvider`] shan't rely on this and should preferably provide some -//! means of fallback election as well. +//! means of fallback election as well, in case the `elect` was called immaturely early. //! //! ## Example //! @@ -167,13 +170,9 @@ use sp_std::prelude::*; /// Re-export some type as they are used in the interface. pub use sp_arithmetic::PerThing; -pub use sp_npos_elections::{ - Assignment, ExtendedBalance, PerThing128, Supports, VoteWeight, -}; +pub use sp_npos_elections::{Assignment, ExtendedBalance, PerThing128, Supports, VoteWeight}; -/// Something that can provide the data to something else that implements [`ElectionProvider`]. -/// -/// The underlying purpose of this is to provide auxillary data to stateful election providers. +/// Something that can provide the data to an [`ElectionProvider`]. pub trait ElectionDataProvider { /// All possible targets for the election, i.e. the candidates. fn targets() -> Vec; @@ -186,17 +185,16 @@ pub trait ElectionDataProvider { /// The number of targets to elect. fn desired_targets() -> u32; - /// Check the feasibility of a single assignment for the underlying [`ElectionProvider`]. - /// - /// This might be called by the [`ElectionProvider`] upon processing election solutions. + /// Check the feasibility of a single assignment for the underlying [`ElectionProvider`]. This + /// might be called by the [`ElectionProvider`] upon processing election solutions. /// /// Note that each this must only contain checks that the [`ElectionProvider`] cannot know - /// about. Basics checks that can be known from [`Self::npos_voters`] and [`Self::npos_targets`] - /// should typically be done by [`ElectionProvider`]. + /// about. Basics checks that can be known from [`Self::voters`] and [`Self::targets`] should + /// typically be done by [`ElectionProvider`]. /// /// For example, if a pallet contains some *private* knowledge that could potentially invalidate /// an `assignment`, it should be checked here, as [`ElectionProvider`] has no way of knowing - /// about this. + /// about it. fn feasibility_check_assignment( assignment: &Assignment, ) -> Result<(), &'static str>; @@ -218,24 +216,25 @@ pub trait ElectionDataProvider { ) {} } -// TODO: only uncomment if needed, else better not to even provide this. -// impl ElectionDataProvider for () { -// fn targets() -> Vec { -// Default::default() -// } -// fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { -// Default::default() -// } -// fn desired_targets() -> u32 { -// Default::default() -// } -// fn feasibility_check_assignment(_: &Assignment) -> Result<(), &'static str> { -// Err("() as ElectionDataProvider cannot do anything.") -// } -// fn next_election_prediction(now: BlockNumber) -> BlockNumber { -// now -// } -// } +impl ElectionDataProvider for () { + fn targets() -> Vec { + Default::default() + } + fn voters() -> Vec<(AccountId, VoteWeight, Vec)> { + Default::default() + } + fn desired_targets() -> u32 { + Default::default() + } + fn feasibility_check_assignment( + _: &Assignment, + ) -> Result<(), &'static str> { + Err("() as ElectionDataProvider cannot do anything.") + } + fn next_election_prediction(now: BlockNumber) -> BlockNumber { + now + } +} /// Something that can compute the result of an election and pass it back to the caller. /// @@ -253,8 +252,6 @@ pub trait ElectionProvider { /// /// The result is returned in a target major format, namely as vector of supports. fn elect() -> Result, Self::Error>; - // where - // ExtendedBalance: From<

::Inner>; /// Returns true if an election is still ongoing. /// @@ -262,15 +259,15 @@ pub trait ElectionProvider { fn ongoing() -> bool; } -// impl ElectionProvider for () { -// type Error = &'static str; -// type DataProvider = (); +impl ElectionProvider for () { + type Error = &'static str; + type DataProvider = (); -// fn elect() -> Result, Self::Error> { -// Err("() as ElectionProvider cannot do anything.") -// } + fn elect() -> Result, Self::Error> { + Err("() as ElectionProvider cannot do anything.") + } -// fn ongoing() -> bool { -// false -// } -// } + fn ongoing() -> bool { + false + } +} diff --git a/primitives/npos-elections/compact/src/lib.rs b/primitives/npos-elections/compact/src/lib.rs index b6e30085fdf86..595bd7719cadb 100644 --- a/primitives/npos-elections/compact/src/lib.rs +++ b/primitives/npos-elections/compact/src/lib.rs @@ -179,7 +179,7 @@ fn struct_def( type Target = #target_type; type Accuracy = #weight_type; - fn voters_count(&self) -> usize { + fn voter_count(&self) -> usize { let mut all_len = 0usize; #len_impl all_len @@ -192,6 +192,8 @@ fn struct_def( } fn unique_targets(&self) -> Vec { + // NOTE: this implementation returns the targets sorted, but we don't use it yet per + // se, nor is the API enforcing it. let mut all_targets: Vec = Vec::with_capacity(self.average_edge_count()); let mut maybe_insert_target = |t: Self::Target| { match all_targets.binary_search(&t) { diff --git a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs index 672cf29ac804d..3b6562cb983fe 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs @@ -23,7 +23,7 @@ use common::*; use honggfuzz::fuzz; use rand::{self, SeedableRng}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, is_score_better, seq_phragmen, to_support_map, + assignment_ratio_to_staked_normalized, is_score_better, seq_phragmen, to_supports, to_without_backing, EvaluateSupport, VoteWeight, }; use sp_runtime::Perbill; @@ -72,7 +72,7 @@ fn main() { ) .unwrap(); let winners = to_without_backing(unbalanced.winners.clone()); - let score = to_support_map(winners.as_ref(), staked.as_ref()) + let score = to_supports(winners.as_ref(), staked.as_ref()) .unwrap() .evaluate(); @@ -94,7 +94,7 @@ fn main() { let balanced_score = { let staked = assignment_ratio_to_staked_normalized(balanced.assignments.clone(), &stake_of).unwrap(); let winners = to_without_backing(balanced.winners); - to_support_map(winners.as_ref(), staked.as_ref()).unwrap().evaluate() + to_supports(winners.as_ref(), staked.as_ref()).unwrap().evaluate() }; diff --git a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs index 8f8fe00dff2d4..92b4010dae2f5 100644 --- a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs @@ -23,7 +23,7 @@ use common::*; use honggfuzz::fuzz; use rand::{self, SeedableRng}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, is_score_better, phragmms, to_support_map, + assignment_ratio_to_staked_normalized, is_score_better, phragmms, to_supports, to_without_backing, EvaluateSupport, VoteWeight, }; use sp_runtime::Perbill; @@ -72,7 +72,7 @@ fn main() { ) .unwrap(); let winners = to_without_backing(unbalanced.winners.clone()); - let score = to_support_map(&winners, &staked).unwrap().evaluate(); + let score = to_supports(&winners, &staked).unwrap().evaluate(); if score[0] == 0 { // such cases cannot be improved by balancing. @@ -89,9 +89,13 @@ fn main() { ).unwrap(); let balanced_score = { - let staked = assignment_ratio_to_staked_normalized(balanced.assignments.clone(), &stake_of).unwrap(); + let staked = + assignment_ratio_to_staked_normalized(balanced.assignments.clone(), &stake_of) + .unwrap(); let winners = to_without_backing(balanced.winners); - to_support_map(winners.as_ref(), staked.as_ref()).unwrap().evaluate() + to_supports(winners.as_ref(), staked.as_ref()) + .unwrap() + .evaluate() }; let enhance = is_score_better(balanced_score, unbalanced_score, Perbill::zero()); diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 40e1e0a63f948..69aaa23e7ba9b 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -147,6 +147,7 @@ pub trait CompactSolution: Sized { /// The weight/accuracy type of each vote. type Accuracy: PerThing128; + /// Build self from a `Vec>`. fn from_assignment( assignments: Vec>, voter_index: FV, @@ -157,20 +158,21 @@ pub trait CompactSolution: Sized { for<'r> FV: Fn(&'r A) -> Option, for<'r> FT: Fn(&'r A) -> Option; + /// Convert self into a `Vec>` fn into_assignment( self, voter_at: impl Fn(Self::Voter) -> Option, target_at: impl Fn(Self::Target) -> Option, ) -> Result>, Error>; - /// Get the length of all the assignments that this type is encoding. + /// Get the length of all the voters that this type is encoding. /// - /// This is basically the same as the number of assignments, or the number of voters in total. - fn voters_count(&self) -> usize; + /// This is basically the same as the number of assignments. + fn voter_count(&self) -> usize; /// Get the total count of edges. /// - /// This is effectively in the range of {[`Self::voters_count`], [`Self::voters_count`] * + /// This is effectively in the range of {[`Self::voter_count`], [`Self::voter_count`] * /// [`Self::LIMIT`]}. fn edge_count(&self) -> usize; @@ -178,14 +180,12 @@ pub trait CompactSolution: Sized { /// /// Once presented with a list of winners, this set and the set of winners must be /// equal. - /// - /// The resulting indices are sorted. fn unique_targets(&self) -> Vec; /// Get the average edge count. fn average_edge_count(&self) -> usize { self.edge_count() - .checked_div(self.voters_count()) + .checked_div(self.voter_count()) .unwrap_or(0) } @@ -201,8 +201,6 @@ pub trait CompactSolution: Sized { /// Compute the score of this compact solution type. fn score( self, - // TODO: this param is just for error checking.. we can remove it if we make the error API - // better. winners: &[A], stake_of: FS, voter_at: impl Fn(Self::Voter) -> Option, @@ -215,8 +213,8 @@ pub trait CompactSolution: Sized { { let ratio = self.into_assignment(voter_at, target_at)?; let staked = helpers::assignment_ratio_to_staked_normalized(ratio, stake_of)?; - let support = to_supports(winners, &staked)?; - Ok(support.evaluate()) + let supports = to_supports(winners, &staked)?; + Ok(supports.evaluate()) } } @@ -498,11 +496,8 @@ pub struct StakedAssignment { impl StakedAssignment { /// Converts self into the normal [`Assignment`] type. /// - /// If `fill` is set to true, it _tries_ to ensure that all the potential rounding errors are - /// compensated and the distribution's sum is exactly equal to 100%, by adding or subtracting - /// the remainder from the last distribution. - /// - /// NOTE: it is quite critical that this attempt always works. The data type returned here will + /// NOTE: This will always round down, and thus the results might be less than a full 100% `P`. + /// Use a normalization post-processing to fix this. The data type returned here will /// potentially get used to create a compact type; a compact type requires sum of ratios to be /// less than 100% upon un-compacting. /// @@ -578,12 +573,16 @@ pub struct Support { pub voters: Vec<(AccountId, ExtendedBalance)>, } -/// A flat variant of [`SupportMap`]. +/// A target-major representation of the the election outcome. +/// +/// Essentially a flat variant of [`SupportMap`]. /// /// The main advantage of this is that it is encodable. pub type Supports = Vec<(A, Support)>; /// Linkage from a winner to their [`Support`]. +/// +/// This is more helpful than a normal [`Supports`] as it allows faster error checking. pub type SupportMap = BTreeMap>; /// Helper trait to convert from a support map to a flat support vector. @@ -594,14 +593,14 @@ pub trait FlattenSupportMap { impl FlattenSupportMap for SupportMap { fn flatten(self) -> Supports { - self.into_iter().map(|(k, v)| (k, v)).collect::>() + self.into_iter().collect::>() } } /// Build the support map from the winners and assignments. /// -/// The list of winners is basically a redundancy; It basically ensures that all the targets pointed -/// to by the `assignments` are present in the `winners`. +/// The list of winners is basically a redundancy for error checking only; It ensures that all the +/// targets pointed to by the [`assignments`] are present in the `winners`. pub fn to_support_map( winners: &[A], assignments: &[StakedAssignment], @@ -628,6 +627,8 @@ pub fn to_support_map( /// Same as [`to_support_map`] except it calls `FlattenSupportMap` on top of the result to return a /// flat vector. +/// +/// Similar to [`build_support_map`], `winners` is used for error checking. pub fn to_supports( winners: &[A], assignments: &[StakedAssignment], @@ -636,42 +637,55 @@ pub fn to_supports( } /// Extension trait for evaluating a support map or vector. -pub trait EvaluateSupport { +pub trait EvaluateSupport { /// Evaluate a support map. The returned tuple contains: /// /// - Minimum support. This value must be **maximized**. /// - Sum of all supports. This value must be **maximized**. /// - Sum of all supports squared. This value must be **minimized**. - fn evaluate(&self) -> ElectionScore; + fn evaluate(self) -> ElectionScore; } -impl EvaluateSupport for SupportMap { - fn evaluate(&self) -> ElectionScore { - let mut min_support = ExtendedBalance::max_value(); - let mut sum: ExtendedBalance = Zero::zero(); - // NOTE: The third element might saturate but fine for now since this will run on-chain and - // need to be fast. - let mut sum_squared: ExtendedBalance = Zero::zero(); - for (_, ref support) in self.into_iter() { - sum = sum.saturating_add(support.total); - let squared = support.total.saturating_mul(support.total); - sum_squared = sum_squared.saturating_add(squared); - if support.total < min_support { - min_support = support.total; - } - } - [min_support, sum, sum_squared] +/// A common wrapper trait for both (&A, &B) and &(A, B). +/// +/// This allows us to implemented something for both `Vec<_>` and `BTreeMap<_>`, such as +/// [`EvaluateSupport`]. +pub trait TupleRef { + fn extract(&self) -> (&K, &V); +} + +impl TupleRef for &(K, V) { + fn extract(&self) -> (&K, &V) { + (&self.0, &self.1) + } +} + +impl TupleRef for (K, V) { + fn extract(&self) -> (&K, &V) { + (&self.0, &self.1) } } -impl EvaluateSupport for Supports { - fn evaluate(&self) -> ElectionScore { +impl TupleRef for (&K, &V) { + fn extract(&self) -> (&K, &V) { + (self.0, self.1) + } +} + +impl EvaluateSupport for C +where + C: IntoIterator, + I: TupleRef>, + A: IdentifierT, +{ + fn evaluate(self) -> ElectionScore { let mut min_support = ExtendedBalance::max_value(); let mut sum: ExtendedBalance = Zero::zero(); // NOTE: The third element might saturate but fine for now since this will run on-chain and // need to be fast. let mut sum_squared: ExtendedBalance = Zero::zero(); - for (_, ref support) in self.into_iter() { + for item in self { + let (_, support) = item.extract(); sum = sum.saturating_add(support.total); let squared = support.total.saturating_mul(support.total); sum_squared = sum_squared.saturating_add(squared); diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index 39e89a9769bb9..f3ad0c6282a3a 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -19,7 +19,8 @@ use crate::{ balancing, helpers::*, is_score_better, mock::*, seq_phragmen, seq_phragmen_core, setup_inputs, - to_support_map, Assignment, ElectionResult, ExtendedBalance, StakedAssignment, Support, Voter, + to_support_map, to_supports, Assignment, ElectionResult, ExtendedBalance, StakedAssignment, + Support, Voter, EvaluateSupport, }; use sp_arithmetic::{PerU16, Perbill, Percent, Permill}; use substrate_test_utils::assert_eq_uvec; @@ -841,6 +842,34 @@ fn duplicate_target_is_ignored_when_winner() { ); } +#[test] +fn support_map_and_vec_can_be_evaluated() { + let candidates = vec![1, 2, 3]; + let voters = vec![(10, vec![1, 2]), (20, vec![1, 3]), (30, vec![2, 3])]; + + let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30)]); + let ElectionResult { + winners, + assignments, + } = seq_phragmen::<_, Perbill>( + 2, + candidates, + voters + .iter() + .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) + .collect::>(), + None, + ) + .unwrap(); + + let staked = assignment_ratio_to_staked(assignments, &stake_of); + let winners = to_without_backing(winners); + let support_map = to_support_map::(&winners, &staked).unwrap(); + let support_vec = to_supports(&winners, &staked).unwrap(); + + assert_eq!(support_map.evaluate(), support_vec.evaluate()); +} + mod assignment_convert_normalize { use super::*; #[test] @@ -1189,7 +1218,7 @@ mod solution_type { compact, Decode::decode(&mut &encoded[..]).unwrap(), ); - assert_eq!(compact.voters_count(), 4); + assert_eq!(compact.voter_count(), 4); assert_eq!(compact.edge_count(), 2 + 4); assert_eq!(compact.unique_targets(), vec![10, 11, 20, 40, 50, 51]); } @@ -1325,7 +1354,7 @@ mod solution_type { ).unwrap(); // basically number of assignments that it is encoding. - assert_eq!(compacted.voters_count(), assignments.len()); + assert_eq!(compacted.voter_count(), assignments.len()); assert_eq!( compacted.edge_count(), assignments.iter().fold(0, |a, b| a + b.distribution.len()), @@ -1409,9 +1438,12 @@ mod solution_type { ..Default::default() }; - assert_eq!(compact.unique_targets(), vec![1, 2, 3, 4, 7, 8, 11, 12, 13, 66, 67]); + assert_eq!( + compact.unique_targets(), + vec![1, 2, 3, 4, 7, 8, 11, 12, 13, 66, 67] + ); assert_eq!(compact.edge_count(), 2 + (2 * 2) + 3 + 16); - assert_eq!(compact.voters_count(), 6); + assert_eq!(compact.voter_count(), 6); // this one has some duplicates. let compact = TestSolutionCompact { @@ -1428,7 +1460,7 @@ mod solution_type { assert_eq!(compact.unique_targets(), vec![1, 3, 4, 7, 8, 11, 13]); assert_eq!(compact.edge_count(), 2 + (2 * 2) + 3); - assert_eq!(compact.voters_count(), 5); + assert_eq!(compact.voter_count(), 5); } #[test] From b3113f78e4ebda0c6934a812470a162093acb956 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 7 Jan 2021 13:57:42 +0000 Subject: [PATCH 38/62] A large number of bugfixes after local test and self-review --- bin/node/runtime/src/constants.rs | 4 +- bin/node/runtime/src/lib.rs | 16 +- .../election-providers/src/two_phase/mock.rs | 112 +++- frame/election-providers/src/two_phase/mod.rs | 555 ++++++++++++++---- .../src/two_phase/signed.rs | 33 +- .../src/two_phase/unsigned.rs | 156 +++-- frame/staking/src/lib.rs | 48 +- frame/staking/src/offchain_election.rs | 10 +- primitives/npos-elections/compact/src/lib.rs | 29 +- primitives/npos-elections/src/tests.rs | 2 - 10 files changed, 743 insertions(+), 222 deletions(-) diff --git a/bin/node/runtime/src/constants.rs b/bin/node/runtime/src/constants.rs index f447486c7ffc4..1ab0b85639e6e 100644 --- a/bin/node/runtime/src/constants.rs +++ b/bin/node/runtime/src/constants.rs @@ -35,7 +35,7 @@ pub mod time { use node_primitives::{Moment, BlockNumber}; /// Since BABE is probabilistic this is the average expected block time that - /// we are targetting. Blocks will be produced at a minimum duration defined + /// we are targeting. Blocks will be produced at a minimum duration defined /// by `SLOT_DURATION`, but some slots will not be allocated to any /// authority and hence no block will be produced. We expect to have this /// block time on average following the defined slot duration and the value @@ -59,7 +59,7 @@ pub mod time { // 1 in 4 blocks (on average, not counting collisions) will be primary BABE blocks. pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); - pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES; + pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 1 * MINUTES; pub const EPOCH_DURATION_IN_SLOTS: u64 = { const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64; diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 8901291968ead..5d0b3b13accd9 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -147,7 +147,7 @@ impl OnUnbalanced for DealWithFees { } } -/// We assume that ~10% of the block weight is consumed by `on_initalize` handlers. +/// We assume that ~10% of the block weight is consumed by `on_initialize` handlers. /// This is used to limit the maximal weight of a single extrinsic. const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used @@ -455,12 +455,12 @@ pallet_staking_reward_curve::build! { } parameter_types! { - pub const SessionsPerEra: sp_staking::SessionIndex = 6; + pub const SessionsPerEra: sp_staking::SessionIndex = 2; pub const BondingDuration: pallet_staking::EraIndex = 24 * 28; pub const SlashDeferDuration: pallet_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominatorRewardedPerValidator: u32 = 256; - pub const ElectionLookahead: BlockNumber = EPOCH_DURATION_IN_BLOCKS / 4; + pub const ElectionLookahead: BlockNumber = 10; pub const MaxIterations: u32 = 10; // 0.05%. The higher the value, the more strict solution acceptance becomes. pub MinSolutionScoreBump: Perbill = Perbill::from_rational_approximation(5u32, 10_000); @@ -505,8 +505,8 @@ impl pallet_staking::Config for Runtime { parameter_types! { // phase durations - pub const SignedPhase: u32 = 25; - pub const UnsignedPhase: u32 = 25; + pub const SignedPhase: u32 = 5; + pub const UnsignedPhase: u32 = 5; // signed configs pub const MaxSignedSubmissions: u32 = 10; @@ -514,6 +514,9 @@ parameter_types! { pub const SignedDepositBase: Balance = 1 * DOLLARS; pub const SignedDepositByte: Balance = 1 * CENTS; + // fallback: no need to do on-chain phragmen initially. + pub const Fallback: pallet_two_phase_election_provider::FallbackStrategy = pallet_two_phase_election_provider::FallbackStrategy::Nothing; + // unsigned configs pub const TwoPhaseUnsignedPriority: TransactionPriority = StakingUnsignedPriority::get() - 1u64; pub const MaxUnsignedIterations: u32 = 10; @@ -545,6 +548,7 @@ impl pallet_two_phase_election_provider::Config for Runtime { type DataProvider = Staking; type OnChainAccuracy = Perbill; type CompactSolution = pallet_staking::CompactAssignments; + type Fallback = Fallback; type WeightInfo = pallet_two_phase_election_provider::weights::SubstrateWeight; } @@ -594,7 +598,7 @@ impl pallet_democracy::Config for Runtime { >; type BlacklistOrigin = EnsureRoot; // Any single technical committee member may veto a coming council proposal, however they can - // only do it once and it lasts only for the cooloff period. + // only do it once and it lasts only for the cool-off period. type VetoOrigin = pallet_collective::EnsureMember; type CooloffPeriod = CooloffPeriod; type PreimageByteDeposit = PreimageByteDeposit; diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 6527fa88203b0..19ecd71c24cb5 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -1,7 +1,11 @@ use super::*; use crate::two_phase; pub use frame_support::{assert_noop, assert_ok}; -use frame_support::{parameter_types, traits::OnInitialize, weights::Weight}; +use frame_support::{ + parameter_types, + traits::{Hooks}, + weights::Weight, +}; use parking_lot::RwLock; use sp_core::{ offchain::{ @@ -69,6 +73,15 @@ pub fn roll_to(n: u64) { } } +pub fn roll_to_with_ocw(n: u64) { + let now = System::block_number(); + for i in now + 1..=n { + System::set_block_number(i); + TwoPhase::on_initialize(i); + TwoPhase::offchain_worker(i); + } +} + /// Get the free and reserved balance of some account. pub fn balances(who: &AccountId) -> (Balance, Balance) { (Balances::free_balance(who), Balances::reserved_balance(who)) @@ -180,6 +193,7 @@ parameter_types! { (30, 30, vec![30]), (40, 40, vec![40]), ]; + pub static BlacklistedVoters: Vec = vec![]; pub static DesiredTargets: u32 = 2; pub static SignedDepositBase: Balance = 5; pub static SignedDepositByte: Balance = 0; @@ -192,6 +206,71 @@ parameter_types! { pub static SolutionImprovementThreshold: Perbill = Perbill::zero(); pub static MinerMaxWeight: Weight = BlockWeights::get().max_block; pub static EpochLength: u64 = 30; + pub static Fallback: FallbackStrategy = FallbackStrategy::OnChain; + pub static MockWeightInfo: bool = false; +} + +// Hopefully this won't be too much of a hassle to maintain. +pub struct DualMockWeightInfo; +impl two_phase::weights::WeightInfo for DualMockWeightInfo { + fn on_initialize_nothing() -> Weight { + if MockWeightInfo::get() { + Zero::zero() + } else { + <() as two_phase::weights::WeightInfo>::on_initialize_nothing() + } + } + fn on_initialize_open_signed() -> Weight { + if MockWeightInfo::get() { + Zero::zero() + } else { + <() as two_phase::weights::WeightInfo>::on_initialize_open_signed() + } + } + fn on_initialize_open_unsigned() -> Weight { + if MockWeightInfo::get() { + Zero::zero() + } else { + <() as two_phase::weights::WeightInfo>::on_initialize_open_unsigned() + } + } + fn finalize_signed_phase_accept_solution() -> Weight { + if MockWeightInfo::get() { + Zero::zero() + } else { + <() as two_phase::weights::WeightInfo>::finalize_signed_phase_accept_solution() + } + } + fn finalize_signed_phase_reject_solution() -> Weight { + if MockWeightInfo::get() { + Zero::zero() + } else { + <() as two_phase::weights::WeightInfo>::finalize_signed_phase_reject_solution() + } + } + fn submit(c: u32) -> Weight { + if MockWeightInfo::get() { + Zero::zero() + } else { + <() as two_phase::weights::WeightInfo>::submit(c) + } + } + fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight { + if MockWeightInfo::get() { + // 10 base + // 5 per edge. + (10 as Weight).saturating_add((5 as Weight).saturating_mul(a as Weight)) + } else { + <() as two_phase::weights::WeightInfo>::submit_unsigned(v, t, a, d) + } + } + fn feasibility_check(v: u32, t: u32, a: u32, d: u32) -> Weight { + if MockWeightInfo::get() { + Zero::zero() + } else { + <() as two_phase::weights::WeightInfo>::feasibility_check(v, t, a, d) + } + } } impl crate::two_phase::Config for Runtime { @@ -213,8 +292,9 @@ impl crate::two_phase::Config for Runtime { type MinerMaxWeight = MinerMaxWeight; type UnsignedPriority = UnsignedPriority; type DataProvider = StakingMock; - type WeightInfo = (); + type WeightInfo = DualMockWeightInfo; type OnChainAccuracy = Perbill; + type Fallback = Fallback; type CompactSolution = TestCompact; } @@ -243,9 +323,17 @@ impl ElectionDataProvider for StakingMock { DesiredTargets::get() } fn feasibility_check_assignment( - _: &Assignment, + assignment: &Assignment, ) -> Result<(), &'static str> { - Ok(()) + if ::get() + .into_iter() + .find(|x| *x == assignment.who) + .is_some() + { + Err("blacklisted") + } else { + Ok(()) + } } fn next_election_prediction(now: u64) -> u64 { now + EpochLength::get() - now % EpochLength::get() @@ -282,6 +370,18 @@ impl ExtBuilder { ::set(max); self } + pub fn fallabck(self, fallback: FallbackStrategy) -> Self { + ::set(fallback); + self + } + pub fn miner_weight(self, weight: Weight) -> Self { + ::set(weight); + self + } + pub fn mock_weight_info(self, mock: bool) -> Self { + ::set(mock); + self + } pub fn desired_targets(self, t: u32) -> Self { ::set(t); self @@ -290,6 +390,10 @@ impl ExtBuilder { VOTERS.with(|v| v.borrow_mut().push((who, stake, targets))); self } + pub fn blacklist_voter(self, who: AccountId) -> Self { + BLACKLISTED_VOTERS.with(|v| v.borrow_mut().push(who)); + self + } pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::default() diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index ea4f283639037..4c06d757370dc 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -104,9 +104,10 @@ //! ### Fallback //! //! If we reach the end of both phases (i.e. call to [`ElectionProvider::elect`] happens) and no -//! good solution is queued, then we fallback to an on-chain election. The on-chain election is -//! slow, and contains no balancing or reduction post-processing. See -//! [`onchain::OnChainSequentialPhragmen`]. +//! good solution is queued, then the fallback strategy [`Config::Fallback`] is used to determine +//! what needs to be done. The on-chain election is slow, and contains no balancing or reduction +//! post-processing. See [`onchain::OnChainSequentialPhragmen`]. The [`FallbackStrategy::Nothing`] +//! should probably only be used for testing. //! //! ## Feasible Solution (correct solution) //! @@ -155,6 +156,15 @@ //! when the signed submissions are checked against an absolute measure (e.g. PJR), then we can only //! open the unsigned phase in extreme conditions (i.e. "not good signed solution received") to //! spare some work in the validators +//! +//! **Allow smaller solutions and build up**: For now we only allow solutions that are exactly +//! [`DesiredTargets`], no more, no less. Over time, we can change this to a [min, max] where any +//! solution within this range is acceptable, where bigger solutions are prioritized. +//! +//! **Recursive Fallback**: Currently, the fallback is a separate enum. A different and fancier way +//! of doing this would be to have the fallback be another [`ElectionProvider`]. In this case, this +//! pallet can even have the on-chain election provider as fallback, or special _noop_ fallback that +//! simply returns an error, thus replicating `Fallback::Nothing`. use crate::onchain::OnChainSequentialPhragmen; use codec::{Decode, Encode, HasCompact}; @@ -171,7 +181,6 @@ use sp_npos_elections::{ EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, }; use sp_runtime::{ - traits::Zero, transaction_validity::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, @@ -179,6 +188,10 @@ use sp_runtime::{ DispatchError, InnerOf, PerThing, Perbill, RuntimeDebug, SaturatedConversion, }; use sp_std::{convert::TryInto, prelude::*}; +use sp_arithmetic::{ + UpperOf, + traits::{Zero, CheckedAdd}, +}; #[cfg(any(feature = "runtime-benchmarks", test))] mod benchmarking; @@ -275,6 +288,19 @@ impl Phase { } } +/// A configuration for the module to indicate what should happen in the case of a fallback i.e. +/// reaching a call to `elect` with no good solution. +#[cfg_attr(test, derive(Clone))] +pub enum FallbackStrategy { + /// Run a on-chain sequential phragmen. + /// + /// This might burn the chain for a few minutes due to a stall, but is generally a safe + /// approach to maintain a sensible validator set. + OnChain, + /// Nothing. Return an error. + Nothing, +} + /// The type of `Computation` that provided this election data. #[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] pub enum ElectionCompute { @@ -400,6 +426,8 @@ pub enum ElectionError { Feasibility(FeasibilityError), /// An error in the on-chain fallback. OnChainFallback(crate::onchain::Error), + /// No fallback is configured + NoFallbackConfigured, /// An internal error in the NPoS elections crate. NposElections(sp_npos_elections::Error), /// Snapshot data was unavailable unexpectedly. @@ -449,6 +477,8 @@ pub enum FeasibilityError { InvalidScore, /// An error from the data provider's feasibility check DataProvider(&'static str), + /// The provided round is incorrect. + InvalidRound, } impl From for FeasibilityError { @@ -512,6 +542,9 @@ pub mod pallet { /// the pallet. type MinerMaxIterations: Get; /// Maximum weight that the miner should consume. + /// + /// The miner will ensure that the total weight of the unsigned solution will not exceed + /// this values, based on [`WeightInfo::submit_unsigned`]. type MinerMaxWeight: Get; /// Handler for the slashed deposits. @@ -534,14 +567,13 @@ pub mod pallet { /// Accuracy used for fallback on-chain election. type OnChainAccuracy: PerThing128; + /// Configuration for the fallback + type Fallback: Get; + /// The weight of the pallet. type WeightInfo: WeightInfo; } - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(PhantomData); - #[pallet::hooks] impl Hooks> for Pallet where @@ -576,17 +608,41 @@ pub mod pallet { fn offchain_worker(n: T::BlockNumber) { // We only run the OCW in the fist block of the unsigned phase. - if - Self::set_check_offchain_execution_status(n).is_ok() && - Self::current_phase().is_unsigned_open_at(n) - { - let _ = Self::mine_and_submit().map_err(|e| { - log!(error, "error while submitting transaction in OCW: {:?}", e) - }).map(|_| { - log!(info, "successfully submitted a solution via OCW at block {}", n) - }); + if Self::current_phase().is_unsigned_open_at(n) { + match Self::set_check_offchain_execution_status(n) { + Ok(_) => match Self::mine_and_submit() { + Ok(_) => log!( + info, + "successfully submitted a solution via OCW at block {:?}", + n + ), + Err(e) => log!(error, "error while submitting transaction in OCW: {:?}", e), + }, + Err(why) => log!(error, "Error in unsigned offchain worker: {:?}", why), + } } } + + fn integrity_test() { + let max_vote: usize = as CompactSolution>::LIMIT; + // based on the requirements of [`sp_npos_elections::Assignment::try_normalize`]. + + // 1. Maximum sum of [ChainAccuracy; 16] must fit into `UpperOf`.. + let maximum_chain_accuracy: Vec>> = (0..max_vote) + .map(|_| >::one().deconstruct().into()) + .collect(); + let _: UpperOf> = maximum_chain_accuracy + .iter() + .fold(Zero::zero(), |acc, x| acc.checked_add(x).unwrap()); + + // 2. Maximum sum of [CompactAccuracy; 16] must fit into `UpperOf`. + let maximum_chain_accuracy: Vec>> = (0..max_vote) + .map(|_| >::one().deconstruct().into()) + .collect(); + let _: UpperOf> = maximum_chain_accuracy + .iter() + .fold(Zero::zero(), |acc, x| acc.checked_add(x).unwrap()); + } } #[pallet::call] @@ -618,19 +674,16 @@ pub mod pallet { // ensure witness data is correct. ensure!( - witness_data == >::decode_len().unwrap_or_default() as u32, - Error::::InvalidWitness + witness_data >= >::decode_len().unwrap_or_default() as u32, + Error::::InvalidWitness, ); // ensure solution is timely. ensure!( Self::current_phase().is_signed(), - Error::::EarlySubmission + Error::::EarlySubmission, ); - // ensure round is correct. - ensure!(Self::round() == solution.round, Error::::InvalidRound); - // NOTE: this is the only case where having separate snapshot would have been better // because could do just decode_len. But we can create abstractions to do this. @@ -655,8 +708,16 @@ pub mod pallet { // store the new signed submission. debug_assert!(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()); - >::put(signed_submissions); + log!( + info, + "queued signed solution with (claimed) score {:?}", + signed_submissions + .get(index) + .map(|s| s.solution.score) + .unwrap_or_default() + ); + >::put(signed_submissions); Self::deposit_event(Event::SolutionStored(ElectionCompute::Signed)); Ok(None.into()) } @@ -687,33 +748,32 @@ pub mod pallet { witness: WitnessData, ) -> DispatchResultWithPostInfo { ensure_none(origin)?; + let error_message = "Invalid unsigned submission must produce invalid block and \ + deprive validator from their authoring reward."; // check phase and score. // NOTE: since we do this in pre-dispatch, we can just ignore it here. - let _ = Self::unsigned_pre_dispatch_checks(&solution)?; + Self::unsigned_pre_dispatch_checks(&solution).expect(error_message); // ensure witness was correct. let RoundSnapshotMetadata { voters_len, targets_len, - } = Self::snapshot_metadata().unwrap_or_default(); - ensure!( - voters_len as u32 == witness.voters, - Error::::InvalidWitness - ); - ensure!( - targets_len as u32 == witness.targets, - Error::::InvalidWitness - ); + } = Self::snapshot_metadata().expect(error_message); + + // NOTE: we are asserting, not `ensure`ing -- we want to panic here. + assert!(voters_len as u32 == witness.voters, error_message); + assert!(targets_len as u32 == witness.targets, error_message); let ready = - Self::feasibility_check(solution, ElectionCompute::Unsigned) - .expect( - "Invalid unsigned submission must produce invalid block and deprive \ - validator from their authoring reward." - ); + Self::feasibility_check(solution, ElectionCompute::Unsigned).expect(error_message); // store the newly received solution. + log!( + info, + "queued unsigned solution with score {:?}", + ready.score + ); >::put(ready); Self::deposit_event(Event::SolutionStored(ElectionCompute::Unsigned)); @@ -747,10 +807,6 @@ pub mod pallet { UnsignedPhaseStarted(u32), } - /// Old name generated by `decl_event`. - // #[deprecated(note = "use `Event` instead")] - // pub type RawEvent = Event; - #[pallet::error] pub enum Error { /// Submission was too early. @@ -763,8 +819,6 @@ pub mod pallet { CannotPayDeposit, /// WitnessData is invalid. InvalidWitness, - /// Round number is invalid. - InvalidRound, } #[pallet::origin] @@ -788,6 +842,10 @@ pub mod pallet { } let _ = Self::unsigned_pre_dispatch_checks(solution) + .map_err(|err| { + log!(error, "unsigned transaction validation failed due to {:?}", err); + err + }) .map_err(dispatch_error_to_invalid) .map(Into::into)?; @@ -878,6 +936,10 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn snapshot_metadata)] pub type SnapshotMetadata = StorageValue<_, RoundSnapshotMetadata>; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData); } impl Pallet @@ -913,7 +975,13 @@ where // noop if no signed phase has been open. NOTE: benchmarks assume this is noop, we return //additional weight manually. - let (_, additional_weight) = Self::finalize_signed_phase(); + let (_found, additional_weight) = Self::finalize_signed_phase(); + log!( + info, + "[{:?}] Signed phase closed, found solution = {}", + now, + _found + ); // for now always start the unsigned phase. >::put(Phase::Unsigned((true, now))); @@ -941,24 +1009,6 @@ where >::put(RoundSnapshot { voters, targets }); } - /// Perform the tasks to be done after a new `elect` has been triggered: - /// - /// 1. Increment round. - /// 2. Change phase to [`Phase::Off`] - /// 3. Clear all snapshot data. - fn post_elect() { - // inc round - >::mutate(|r| *r = *r + 1); - - // change phase - >::put(Phase::Off); - - // kill snapshots - >::kill(); - >::kill(); - >::kill(); - } - /// Build the witness data from the snapshot metadata, if it exists. Else, returns `None`. fn build_witness() -> Option { let metadata = Self::snapshot_metadata()?; @@ -981,11 +1031,19 @@ where solution: RawSolution>, compute: ElectionCompute, ) -> Result, FeasibilityError> { - let RawSolution { compact, score, .. } = solution; + let RawSolution { + compact, + score, + round, + } = solution; + + // first, check round. + ensure!(Self::round() == round, FeasibilityError::InvalidRound); // winners are not directly encoded in the solution. let winners = compact.unique_targets(); + // TODO: this can probably checked ahead of time, both in signed and unsigned story. let desired_targets = Self::desired_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; @@ -1011,6 +1069,7 @@ where .collect::, FeasibilityError>>()?; // Then convert compact -> Assignment. This will fail if any of the indices are gibberish. + // that winner indices are already checked. let assignments = compact .into_assignment(voter_at, target_at) .map_err::(Into::into)?; @@ -1019,7 +1078,11 @@ where let _ = assignments .iter() .map(|ref assignment| { - // check that assignment.who is actually a voter. + // check that assignment.who is actually a voter (defensive-only). + // NOTE: This check is fully defensive as we know that this assignment.who is + // a voter, what we don't know is stake and targets. Essentially, we have lost the + // index after converting `compact` -> `assignment`. This can be optimized in the + // future. let (_voter, _stake, targets) = snapshot_voters .iter() .find(|(v, _, _)| v == &assignment.who) @@ -1042,10 +1105,11 @@ where // ----- Start building support. First, we need some more closures. let stake_of = stake_of_fn!(snapshot_voters, T::AccountId); - // // This might fail if the normalization fails. Very unlikely. + // This might fail if the normalization fails. Very unlikely. See `integrity_test`. let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) .map_err::(Into::into)?; - // This might fail if one of the voter edges is pointing to a non-winner. + // This might fail if one of the voter edges is pointing to a non-winner, which is not + // really possible anymore because all the winners come from the same `compact`. let supports = sp_npos_elections::to_supports(&winners, &staked_assignments) .map_err::(Into::into)?; @@ -1061,6 +1125,24 @@ where }) } + /// Perform the tasks to be done after a new `elect` has been triggered: + /// + /// 1. Increment round. + /// 2. Change phase to [`Phase::Off`] + /// 3. Clear all snapshot data. + fn post_elect() { + // inc round + >::mutate(|r| *r = *r + 1); + + // change phase + >::put(Phase::Off); + + // kill snapshots + >::kill(); + >::kill(); + >::kill(); + } + /// On-chain fallback of election. fn onchain_fallback() -> Result, ElectionError> where @@ -1072,29 +1154,24 @@ where >>::elect() .map_err(Into::into) } -} - -impl ElectionProvider for Pallet -where - ExtendedBalance: From>>, - ExtendedBalance: From>>, -{ - type Error = ElectionError; - type DataProvider = T::DataProvider; - fn elect() -> Result, Self::Error> { - Self::queued_solution() + fn do_elect() -> Result, ElectionError> { + // NOTE: SignedSubmission is guaranteed to be drained by the end of the signed phase too, + // thus no need for a manual cleanup: + debug_assert!(Self::signed_submissions().is_empty()); + >::take() .map_or_else( - || { - - Self::onchain_fallback() + || match T::Fallback::get() { + FallbackStrategy::OnChain => Self::onchain_fallback() .map(|r| (r, ElectionCompute::OnChain)) - .map_err(Into::into) + .map_err(Into::into), + FallbackStrategy::Nothing => Err(ElectionError::NoFallbackConfigured), }, - |ReadySolution { supports, compute, ..}| Ok((supports, compute)), + |ReadySolution { + supports, compute, .. + }| Ok((supports, compute)), ) .map(|(supports, compute)| { - Self::post_elect(); Self::deposit_event(Event::ElectionFinalized(Some(compute))); log!(info, "Finalized election round with compute {:?}.", compute); supports @@ -1105,6 +1182,22 @@ where err }) } +} + +impl ElectionProvider for Pallet +where + ExtendedBalance: From>>, + ExtendedBalance: From>>, +{ + type Error = ElectionError; + type DataProvider = T::DataProvider; + + fn elect() -> Result, Self::Error> { + let outcome = Self::do_elect(); + // cleanup. + Self::post_elect(); + outcome + } fn ongoing() -> bool { matches!(Self::current_phase(), Phase::Signed | Phase::Unsigned(_)) @@ -1113,7 +1206,7 @@ where /// convert a DispatchError to a custom InvalidTransaction with the inner code being the error /// number. -fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { +pub fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { let error_number = match error { DispatchError::Module { error, .. } => error, _ => 0, @@ -1121,6 +1214,210 @@ fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { InvalidTransaction::Custom(error_number) } +#[cfg(test)] +mod feasibility_check { + //! All of the tests here should be dedicated to only testing the feasibility check and nothing + //! more. The best way to audit and review these tests is to try and come up with a solution + //! that is invalid, but gets through the system as valid. + + use super::{mock::*, *}; + + const COMPUTE: ElectionCompute = ElectionCompute::OnChain; + + #[test] + fn snapshot_is_there() { + ExtBuilder::default().build_and_execute(|| { + roll_to(::get() - ::get() - ::get()); + assert!(TwoPhase::current_phase().is_signed()); + let solution = raw_solution(); + + // for whatever reason it might be: + >::kill(); + + assert_noop!( + TwoPhase::feasibility_check(solution, COMPUTE), + FeasibilityError::SnapshotUnavailable + ); + }) + } + + #[test] + fn round() { + ExtBuilder::default().build_and_execute(|| { + roll_to(::get() - ::get() - ::get()); + assert!(TwoPhase::current_phase().is_signed()); + + let mut solution = raw_solution(); + solution.round += 1; + assert_noop!( + TwoPhase::feasibility_check(solution, COMPUTE), + FeasibilityError::InvalidRound + ); + }) + } + + #[test] + fn desired_targets() { + ExtBuilder::default() + .desired_targets(8) + .build_and_execute(|| { + roll_to(::get() - ::get() - ::get()); + assert!(TwoPhase::current_phase().is_signed()); + + let solution = raw_solution(); + + assert_eq!(solution.compact.unique_targets().len(), 4); + assert_eq!(TwoPhase::desired_targets().unwrap(), 8); + + assert_noop!( + TwoPhase::feasibility_check(solution, COMPUTE), + FeasibilityError::WrongWinnerCount + ); + }) + } + + #[test] + fn winner_indices() { + ExtBuilder::default() + .desired_targets(2) + .build_and_execute(|| { + roll_to(::get() - ::get() - ::get()); + assert!(TwoPhase::current_phase().is_signed()); + + let mut solution = raw_solution(); + assert_eq!(TwoPhase::snapshot().unwrap().targets.len(), 4); + // ----------------------------------------------------^^ valid range is [0..3]. + + // swap all votes from 3 to 4. This will ensure that the number of unique winners will + // still be 4, but one of the indices will be gibberish. Requirement is to make sure 3 + // a winner, which we don't do here. + solution + .compact + .votes1 + .iter_mut() + .filter(|(_, t)| *t == 3u16) + .for_each(|(_, t)| *t += 1); + solution + .compact + .votes2 + .iter_mut() + .for_each(|(_, (t0, _), t1)| { + if *t0 == 3u16 { + *t0 += 1 + }; + if *t1 == 3u16 { + *t1 += 1 + }; + }); + assert_noop!( + TwoPhase::feasibility_check(solution, COMPUTE), + FeasibilityError::InvalidWinner + ); + }) + } + + #[test] + fn voter_indices() { + // should be caught in `compact.into_assignment`. + ExtBuilder::default() + .desired_targets(2) + .build_and_execute(|| { + roll_to(::get() - ::get() - ::get()); + assert!(TwoPhase::current_phase().is_signed()); + + let mut solution = raw_solution(); + assert_eq!(TwoPhase::snapshot().unwrap().voters.len(), 8); + // ----------------------------------------------------^^ valid range is [0..7]. + + // check that there is a index 7 in votes1, and flip to 8. + assert!( + solution + .compact + .votes1 + .iter_mut() + .filter(|(v, _)| *v == 7u32) + .map(|(v, _)| *v = 8) + .count() > 0 + ); + assert_noop!( + TwoPhase::feasibility_check(solution, COMPUTE), + FeasibilityError::NposElection(sp_npos_elections::Error::CompactInvalidIndex), + ); + }) + } + + #[test] + fn voter_votes() { + ExtBuilder::default() + .desired_targets(2) + .build_and_execute(|| { + roll_to(::get() - ::get() - ::get()); + assert!(TwoPhase::current_phase().is_signed()); + + let mut solution = raw_solution(); + assert_eq!(TwoPhase::snapshot().unwrap().voters.len(), 8); + // ----------------------------------------------------^^ valid range is [0..7]. + + // first, check that voter at index 7 (40) actually voted for 3 (40) -- this is self + // vote. Then, change the vote to 2 (30). + assert_eq!( + solution + .compact + .votes1 + .iter_mut() + .filter(|(v, t)| *v == 7 && *t == 3) + .map(|(_, t)| *t = 2) + .count(), + 1, + ); + assert_noop!( + TwoPhase::feasibility_check(solution, COMPUTE), + FeasibilityError::InvalidVote, + ); + }) + } + + #[test] + fn score() { + ExtBuilder::default() + .desired_targets(2) + .build_and_execute(|| { + roll_to(::get() - ::get() - ::get()); + assert!(TwoPhase::current_phase().is_signed()); + + let mut solution = raw_solution(); + assert_eq!(TwoPhase::snapshot().unwrap().voters.len(), 8); + + // simply faff with the score. + solution.score[0] += 1; + + assert_noop!( + TwoPhase::feasibility_check(solution, COMPUTE), + FeasibilityError::InvalidScore, + ); + }) + } + + #[test] + fn data_provider_feasibility_chec() { + ExtBuilder::default() + .blacklist_voter(4) + .build_and_execute(|| { + roll_to(::get() - ::get() - ::get()); + assert!(TwoPhase::current_phase().is_signed()); + + let solution = raw_solution(); + assert_eq!(TwoPhase::snapshot().unwrap().voters.len(), 8); + + // solution already contains a vote from 4, nothing to do. + assert_noop!( + TwoPhase::feasibility_check(solution, COMPUTE), + FeasibilityError::DataProvider("blacklisted"), + ); + }) + } +} + #[cfg(test)] mod tests { use super::{mock::*, Event, *}; @@ -1189,40 +1486,6 @@ mod tests { }) } - #[test] - fn onchain_backup_works() { - ExtBuilder::default().build_and_execute(|| { - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Signed); - - roll_to(25); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); - - // zilch solutions thus far. - let supports = TwoPhase::elect().unwrap(); - - assert_eq!( - supports, - vec![ - ( - 30, - Support { - total: 40, - voters: vec![(2, 5), (4, 5), (30, 30)] - } - ), - ( - 40, - Support { - total: 60, - voters: vec![(2, 5), (3, 10), (4, 5), (40, 40)] - } - ) - ] - ) - }) - } - #[test] fn signed_phase_void() { ExtBuilder::default().phases(0, 10).build_and_execute(|| { @@ -1324,4 +1587,56 @@ mod tests { assert!(TwoPhase::queued_solution().is_none()); }) } + + #[test] + fn fallback_strategy_works() { + ExtBuilder::default() + .fallabck(FallbackStrategy::OnChain) + .build_and_execute(|| { + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + + roll_to(25); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); + + // zilch solutions thus far. + let supports = TwoPhase::elect().unwrap(); + + assert_eq!( + supports, + vec![ + ( + 30, + Support { + total: 40, + voters: vec![(2, 5), (4, 5), (30, 30)] + } + ), + ( + 40, + Support { + total: 60, + voters: vec![(2, 5), (3, 10), (4, 5), (40, 40)] + } + ) + ] + ) + }); + + ExtBuilder::default() + .fallabck(FallbackStrategy::Nothing) + .build_and_execute(|| { + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); + + roll_to(25); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); + + // zilch solutions thus far. + assert_eq!( + TwoPhase::elect().unwrap_err(), + ElectionError::NoFallbackConfigured + ); + }) + } } diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/election-providers/src/two_phase/signed.rs index d0eaa7d9c4aed..d86b310da8d38 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/election-providers/src/two_phase/signed.rs @@ -16,8 +16,6 @@ // limitations under the License. //! The signed phase implementation. -//! -//! THis is asda asdasda asd asdasdasd use crate::two_phase::*; use codec::Encode; @@ -31,7 +29,7 @@ where ExtendedBalance: From>>, { /// Finish the singed phase. Process the signed submissions from best to worse until a valid one - /// is found, rewarding the best oen and slashing the invalid ones along the way. + /// is found, rewarding the best one and slashing the invalid ones along the way. /// /// Returns true if we have a good solution in the signed phase. /// @@ -79,7 +77,7 @@ where break; } Err(_) => { - // we assume a worse ase feasibility check happened anyhow. + // we assume a worse case feasibility check happened anyhow. weight = weight.saturating_add(feasibility_weight); Self::finalize_signed_phase_reject_solution(&who, deposit); weight = weight @@ -207,7 +205,9 @@ where } /// Removes the weakest element of the queue, namely the first one, should the length of the - /// queue be enough. noop if the queue is empty. Bond of the removed solution is returned. + /// queue be enough. + /// + /// noop if the queue is empty. Bond of the removed solution is returned. pub fn remove_weakest( queue: &mut Vec, CompactOf>>, ) { @@ -290,7 +290,23 @@ mod tests { } #[test] - fn wrong_witness_fails() {} + fn wrong_witness_fails() { + ExtBuilder::default().build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); + + let solution = raw_solution(); + // submit this once correctly + assert_ok!(submit_with_witness(Origin::signed(99), solution.clone())); + assert_eq!(TwoPhase::signed_submissions().len(), 1); + + // now try and cheat by passing a lower queue length + assert_noop!( + TwoPhase::submit(Origin::signed(99), solution, 0,), + Error::::InvalidWitness, + ); + }) + } #[test] fn should_pay_deposit() { @@ -565,7 +581,7 @@ mod tests { } #[test] - fn equally_good_is_not_accepted() { + fn equally_good_solution_is_not_accepted() { ExtBuilder::default() .max_signed_submission(3) .build_and_execute(|| { @@ -708,7 +724,4 @@ mod tests { assert_eq!(balances(&9999), (100, 0)); }) } - - #[test] - fn invalid_round_fails() {} } diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/election-providers/src/two_phase/unsigned.rs index 2e5d7f0c3a35f..68364936c4297 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/election-providers/src/two_phase/unsigned.rs @@ -25,7 +25,7 @@ use sp_runtime::{offchain::storage::StorageValueRef, traits::TrailingZeroInput}; use sp_std::cmp::Ordering; /// Storage key used to store the persistent offchain worker status. -pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/unsigned-election/"; +pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/two-phase-unsigned-election/"; /// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice /// within a window of 5 blocks. pub(crate) const OFFCHAIN_REPEAT: u32 = 5; @@ -52,6 +52,13 @@ where Some((iters, 0)), ) .map_err(Into::into) + .and_then(|election_result| { + if election_result.winners.len() as u32 == desired_targets { + Ok(election_result) + } else { + Err(ElectionError::Feasibility(FeasibilityError::WrongWinnerCount)) + } + }) .and_then(Self::prepare_election_result) } @@ -98,6 +105,12 @@ where witness, T::MinerMaxWeight::get(), ); + log!( + debug, + "miner: current compact solution voters = {}, maximum_allowed = {}", + compact.voter_count(), + maximum_allowed_voters, + ); let compact = Self::trim_compact(maximum_allowed_voters, compact, &voter_index)?; // re-calc score. @@ -565,28 +578,28 @@ mod tests { // initial assert_eq!(TwoPhase::current_phase(), Phase::Off); - matches!( + assert!(matches!( ::validate_unsigned(TransactionSource::Local, &call) .unwrap_err(), - TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) - ); - matches!( + TransactionValidityError::Invalid(InvalidTransaction::Custom(0)) + )); + assert!(matches!( ::pre_dispatch(&call).unwrap_err(), - TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) - ); + TransactionValidityError::Invalid(InvalidTransaction::Custom(0)) + )); // signed roll_to(15); assert_eq!(TwoPhase::current_phase(), Phase::Signed); - matches!( + assert!(matches!( ::validate_unsigned(TransactionSource::Local, &call) .unwrap_err(), - TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) - ); - matches!( + TransactionValidityError::Invalid(InvalidTransaction::Custom(0)) + )); + assert!(matches!( ::pre_dispatch(&call).unwrap_err(), - TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) - ); + TransactionValidityError::Invalid(InvalidTransaction::Custom(0)) + )); // unsigned roll_to(25); @@ -629,15 +642,15 @@ mod tests { >::put(ready); // won't work anymore. - matches!( + assert!(matches!( ::validate_unsigned(TransactionSource::Local, &call) .unwrap_err(), - TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) - ); - matches!( + TransactionValidityError::Invalid(InvalidTransaction::Custom(1)) + )); + assert!(matches!( ::pre_dispatch(&call).unwrap_err(), - TransactionValidityError::Invalid(InvalidTransaction::Custom(99)) - ); + TransactionValidityError::Invalid(InvalidTransaction::Custom(1)) + )); }) } @@ -673,12 +686,12 @@ mod tests { expected = "Invalid unsigned submission must produce invalid block and deprive \ validator from their authoring reward.: FeasibilityError::WrongWinnerCount" )] - fn invalid_solution_panics() { + fn unfeasible_solution_panics() { ExtBuilder::default().build_and_execute(|| { roll_to(25); assert!(TwoPhase::current_phase().is_unsigned()); - // This is in itself an invalid BS solution.. + // This is in itself an invalid BS solution. let solution = RawSolution:: { score: [5, 0, 0], ..Default::default() @@ -689,6 +702,30 @@ mod tests { }) } + #[test] + #[should_panic( + expected = "Invalid unsigned submission must produce invalid block and deprive validator from their authoring reward." + )] + fn wrong_witness_panics() { + ExtBuilder::default().build_and_execute(|| { + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); + + // This solution is unfeasible as well, but we won't even get there. + let solution = RawSolution:: { + score: [5, 0, 0], + ..Default::default() + }; + + let mut correct_witness = witness(); + correct_witness.voters += 1; + correct_witness.targets -= 1; + let call = Call::submit_unsigned(solution.clone(), correct_witness); + let outer_call: OuterCall = call.into(); + let _ = outer_call.dispatch(Origin::none()); + }) + } + #[test] fn miner_works() { ExtBuilder::default().build_and_execute(|| { @@ -711,16 +748,58 @@ mod tests { #[test] fn miner_trims_weight() { - // set a proper max weight and mock weighInfo, test weight being trimmed. + ExtBuilder::default() + .miner_weight(100) + .mock_weight_info(true) + .build_and_execute(|| { + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); + + let (solution, witness) = TwoPhase::mine_solution(2).unwrap(); + let solution_weight = ::WeightInfo::submit_unsigned( + witness.voters, + witness.targets, + solution.compact.voter_count() as u32, + solution.compact.unique_targets().len() as u32, + ); + // default solution will have 5 edges (5 * 5 + 10) + assert_eq!(solution_weight, 35); + assert_eq!(solution.compact.voter_count(), 5); + + // now reduce the max weight + ::set(25); + + let (solution, witness) = TwoPhase::mine_solution(2).unwrap(); + let solution_weight = ::WeightInfo::submit_unsigned( + witness.voters, + witness.targets, + solution.compact.voter_count() as u32, + solution.compact.unique_targets().len() as u32, + ); + // default solution will have 5 edges (5 * 5 + 10) + assert_eq!(solution_weight, 25); + assert_eq!(solution.compact.voter_count(), 3); + }) } #[test] - fn ocw_will_only_submit_if_feasible() { - // the ocw should only submit a solution if it is sure that it is valid. + fn miner_will_not_submit_if_not_enough_winners() { + ExtBuilder::default() + .desired_targets(8) + .build_and_execute(|| { + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); + + // mine seq_phragmen solution with 2 iters. + assert_eq!( + TwoPhase::mine_solution(2).unwrap_err(), + ElectionError::Feasibility(FeasibilityError::WrongWinnerCount), + ); + }) } #[test] - fn can_only_submit_threshold_better() { + fn unsigned_per_dispatch_checks_can_only_submit_threshold_better() { ExtBuilder::default() .desired_targets(1) .add_voter(7, 2, vec![10]) @@ -741,8 +820,9 @@ mod tests { distribution: vec![(10, PerU16::one())], }], }; - let (compact, witness) = TwoPhase::prepare_election_result(result).unwrap(); - assert_ok!(TwoPhase::submit_unsigned(Origin::none(), compact, witness)); + let (solution, witness) = TwoPhase::prepare_election_result(result).unwrap(); + assert_ok!(TwoPhase::unsigned_pre_dispatch_checks(&solution)); + assert_ok!(TwoPhase::submit_unsigned(Origin::none(), solution, witness)); assert_eq!(TwoPhase::queued_solution().unwrap().score[0], 10); // trial 1: a solution who's score is only 2, i.e. 20% better in the first element. @@ -760,14 +840,14 @@ mod tests { }, ], }; - let (solution, witness) = TwoPhase::prepare_election_result(result).unwrap(); + let (solution, _) = TwoPhase::prepare_election_result(result).unwrap(); // 12 is not 50% more than 10 assert_eq!(solution.score[0], 12); - assert_noop!( - TwoPhase::submit_unsigned(Origin::none(), solution, witness), + TwoPhase::unsigned_pre_dispatch_checks(&solution), Error::::WeakSubmission, ); + // submitting this will actually panic. // trial 2: a solution who's score is only 7, i.e. 70% better in the first element. let result = ElectionResult { @@ -792,6 +872,7 @@ mod tests { assert_eq!(solution.score[0], 17); // and it is fine + assert_ok!(TwoPhase::unsigned_pre_dispatch_checks(&solution)); assert_ok!(TwoPhase::submit_unsigned(Origin::none(), solution, witness)); }) } @@ -860,20 +941,17 @@ mod tests { fn ocw_can_submit_to_pool() { let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); ext.execute_with(|| { - roll_to(25); + roll_to_with_ocw(25); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); - TwoPhase::offchain_worker(25); + // OCW must have submitted now let encoded = pool.read().transactions[0].clone(); let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); let call = extrinsic.call; - matches!(call, OuterCall::TwoPhase(Call::submit_unsigned(_, _))); + assert!(matches!( + call, + OuterCall::TwoPhase(Call::submit_unsigned(_, _)) + )); }) } - - #[test] - fn wrong_witness_fails() {} - - #[test] - fn invalid_round_fails() {} } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index f1fa390f2496c..f91ae7f6fd4d0 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -343,7 +343,7 @@ macro_rules! log { ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { frame_support::debug::$level!( target: crate::LOG_TARGET, - $patter $(, $values)* + concat!("💸 ", $patter) $(, $values)* ) }; } @@ -1331,14 +1331,14 @@ decl_module! { ElectionStatus::::Open(now) ); add_weight(0, 1, 0); - log!(info, "💸 Election window is Open({:?}). Snapshot created", now); + log!(info, "Election window is Open({:?}). Snapshot created", now); } else { - log!(warn, "💸 Failed to create snapshot at {:?}.", now); + log!(warn, "Failed to create snapshot at {:?}.", now); } } } } else { - log!(warn, "💸 Estimating next session change failed."); + log!(warn, "Estimating next session change failed."); } add_weight(0, 0, T::NextNewSession::weight(now)) } @@ -1353,16 +1353,15 @@ decl_module! { /// to open. If so, it runs the offchain worker code. fn offchain_worker(now: T::BlockNumber) { use offchain_election::{set_check_offchain_execution_status, compute_offchain_election}; - if Self::era_election_status().is_open_at(now) { let offchain_status = set_check_offchain_execution_status::(now); if let Err(why) = offchain_status { - log!(warn, "💸 skipping offchain worker in open election window due to [{}]", why); + log!(warn, "skipping offchain worker in open election window due to [{}]", why); } else { if let Err(e) = compute_offchain_election::() { - log!(error, "💸 Error in election offchain worker: {:?}", e); + log!(error, "Error in election offchain worker: {:?}", e); } else { - log!(debug, "💸 Executed offchain worker thread without errors."); + log!(debug, "Executed offchain worker thread without errors."); } } } @@ -2250,7 +2249,7 @@ impl Module { { log!( warn, - "💸 Snapshot size too big [{} <> {}][{} <> {}].", + "Snapshot size too big [{} <> {}][{} <> {}].", num_validators, MAX_VALIDATORS, num_nominators, @@ -2567,7 +2566,7 @@ impl Module { validator_at, ).map_err(|e| { // log the error since it is not propagated into the runtime error. - log!(warn, "💸 un-compacting solution failed due to {:?}", e); + log!(warn, "un-compacting solution failed due to {:?}", e); Error::::OffchainElectionBogusCompact })?; @@ -2582,7 +2581,7 @@ impl Module { // all of the indices must map to either a validator or a nominator. If this is ever // not the case, then the locking system of staking is most likely faulty, or we // have bigger problems. - log!(error, "💸 detected an error in the staking locking and snapshot."); + log!(error, "detected an error in the staking locking and snapshot."); // abort. return Err(Error::::OffchainElectionBogusNominator.into()); } @@ -2642,7 +2641,7 @@ impl Module { let exposures = Self::collect_exposures(supports); log!( info, - "💸 A better solution (with compute {:?} and score {:?}) has been validated and stored on chain.", + "A better solution (with compute {:?} and score {:?}) has been validated and stored on chain.", compute, submitted_score, ); @@ -2843,7 +2842,7 @@ impl Module { log!( info, - "💸 new validator set of size {:?} has been elected via {:?} for era {:?}", + "new validator set of size {:?} has been elected via {:?} for staring era {:?}", elected_stashes.len(), compute, current_era, @@ -2899,7 +2898,7 @@ impl Module { .map_err(|_| log!( error, - "💸 on-chain phragmen is failing due to a problem in the result. This must be a bug." + "on-chain phragmen is failing due to a problem in the result. This must be a bug." ) ) .ok()?; @@ -2970,7 +2969,7 @@ impl Module { // If we don't have enough candidates, nothing to do. log!( warn, - "💸 Chain does not have enough staking candidates to operate. Era {:?}.", + "chain does not have enough staking candidates to operate. Era {:?}.", Self::current_era() ); None @@ -3044,7 +3043,7 @@ impl Module { if (elected_stashes.len() as u32) <= Self::minimum_validator_count() { log!( warn, - "💸 Chain does not have enough staking candidates to operate for era {:?}", + "chain does not have enough staking candidates to operate for era {:?}", current_era, ); return Err(()); @@ -3082,7 +3081,7 @@ impl Module { log!( info, - "💸 new validator set of size {:?} has been processed for era {:?}", + "new validator set of size {:?} has been processed for era {:?}", elected_stashes.len(), current_era, ); @@ -3095,8 +3094,13 @@ impl Module { /// This will also process the election, as noted in [`process_election`]. fn enact_election(_current_era: EraIndex) -> Option> { let outcome = T::ElectionProvider::elect().map(|_| ()); - log!(debug, "Experimental election provider outputted {:?}", outcome); - // TODO: TWO_PHASE: This code path shall not return anything for now. + log!( + debug, + "Experimental election provider outputted {:?}", + outcome + ); + // TODO: TWO_PHASE: This code path shall not return anything for now. Later on, redirect the + // results to `process_election`. None } @@ -3260,7 +3264,9 @@ impl Module { } } -impl sp_election_providers::ElectionDataProvider for Module { +impl sp_election_providers::ElectionDataProvider + for Module +{ fn desired_targets() -> u32 { Self::validator_count() } @@ -3663,7 +3669,7 @@ impl frame_support::unsigned::ValidateUnsigned for Module { return invalid.into(); } - log!(debug, "💸 validateUnsigned succeeded for a solution at era {}.", era); + log!(debug, "validateUnsigned succeeded for a solution at era {}.", era); ValidTransaction::with_tag_prefix("StakingOffchain") // The higher the score[0], the better a solution is. diff --git a/frame/staking/src/offchain_election.rs b/frame/staking/src/offchain_election.rs index 5e88cfe3d9e58..25379559f13a8 100644 --- a/frame/staking/src/offchain_election.rs +++ b/frame/staking/src/offchain_election.rs @@ -127,7 +127,7 @@ pub(crate) fn compute_offchain_election() -> Result<(), OffchainElect crate::log!( info, - "💸 prepared a seq-phragmen solution with {} balancing iterations and score {:?}", + "prepared a seq-phragmen solution with {} balancing iterations and score {:?}", iters, score, ); @@ -287,7 +287,7 @@ where if compact.remove_voter(index) { crate::log!( trace, - "💸 removed a voter at index {} with stake {:?} from compact to reduce the size", + "removed a voter at index {} with stake {:?} from compact to reduce the size", index, _stake, ); @@ -301,7 +301,7 @@ where crate::log!( warn, - "💸 {} nominators out of {} had to be removed from compact solution due to size limits.", + "{} nominators out of {} had to be removed from compact solution due to size limits.", removed, compact.voter_count() + removed, ); @@ -311,7 +311,7 @@ where // nada, return as-is crate::log!( info, - "💸 Compact solution did not get trimmed due to block weight limits.", + "Compact solution did not get trimmed due to block weight limits.", ); Ok(compact) } @@ -401,7 +401,7 @@ where let maximum_allowed_voters = maximum_compact_len::(winners.len() as u32, size, maximum_weight); - crate::log!(debug, "💸 Maximum weight = {:?} // current weight = {:?} // maximum voters = {:?} // current votes = {:?}", + crate::log!(debug, "Maximum weight = {:?} // current weight = {:?} // maximum voters = {:?} // current votes = {:?}", maximum_weight, T::WeightInfo::submit_solution_better( size.validators.into(), diff --git a/primitives/npos-elections/compact/src/lib.rs b/primitives/npos-elections/compact/src/lib.rs index 595bd7719cadb..01b59c1a43549 100644 --- a/primitives/npos-elections/compact/src/lib.rs +++ b/primitives/npos-elections/compact/src/lib.rs @@ -117,29 +117,32 @@ fn struct_def( let singles = { let name = field_name_for(1); + // NOTE: we use the visibility of the struct for the fields as well.. could be made better. quote!( - #name: Vec<(#voter_type, #target_type)>, + #vis #name: Vec<(#voter_type, #target_type)>, ) }; let doubles = { let name = field_name_for(2); quote!( - #name: Vec<(#voter_type, (#target_type, #weight_type), #target_type)>, + #vis #name: Vec<(#voter_type, (#target_type, #weight_type), #target_type)>, ) }; - let rest = (3..=count).map(|c| { - let field_name = field_name_for(c); - let array_len = c - 1; - quote!( - #field_name: Vec<( - #voter_type, - [(#target_type, #weight_type); #array_len], - #target_type - )>, - ) - }).collect::(); + let rest = (3..=count) + .map(|c| { + let field_name = field_name_for(c); + let array_len = c - 1; + quote!( + #vis #field_name: Vec<( + #voter_type, + [(#target_type, #weight_type); #array_len], + #target_type + )>, + ) + }) + .collect::(); let len_impl = len_impl(count); let edge_count_impl = edge_count_impl(count); diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index f3ad0c6282a3a..359ddc58ee403 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -1153,7 +1153,6 @@ mod solution_type { type TestAccuracy = Percent; generate_solution_type!(pub struct TestSolutionCompact::(16)); - #[allow(dead_code)] mod __private { // This is just to make sure that that the compact can be generated in a scope without any @@ -1164,7 +1163,6 @@ mod solution_type { #[compact] struct InnerTestSolutionCompact::(12) ); - } #[test] From 876f666fa9d313a264520b984561f8a6a2051678 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 7 Jan 2021 19:29:37 +0000 Subject: [PATCH 39/62] Apply suggestions from code review --- bin/node/runtime/src/constants.rs | 2 +- bin/node/runtime/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/node/runtime/src/constants.rs b/bin/node/runtime/src/constants.rs index 1ab0b85639e6e..c549b1977d376 100644 --- a/bin/node/runtime/src/constants.rs +++ b/bin/node/runtime/src/constants.rs @@ -59,7 +59,7 @@ pub mod time { // 1 in 4 blocks (on average, not counting collisions) will be primary BABE blocks. pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); - pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 1 * MINUTES; + pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES; pub const EPOCH_DURATION_IN_SLOTS: u64 = { const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64; diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 6ea0e1656f63c..4adbeee367a6e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -455,12 +455,12 @@ pallet_staking_reward_curve::build! { } parameter_types! { - pub const SessionsPerEra: sp_staking::SessionIndex = 2; + pub const SessionsPerEra: sp_staking::SessionIndex = 6; pub const BondingDuration: pallet_staking::EraIndex = 24 * 28; pub const SlashDeferDuration: pallet_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominatorRewardedPerValidator: u32 = 256; - pub const ElectionLookahead: BlockNumber = 10; + pub const ElectionLookahead: BlockNumber = EPOCH_DURATION_IN_BLOCKS / 4; pub const MaxIterations: u32 = 10; // 0.05%. The higher the value, the more strict solution acceptance becomes. pub MinSolutionScoreBump: Perbill = Perbill::from_rational_approximation(5u32, 10_000); From 81df1dfb76a16dfac1516aae27f7b72e45d7dc22 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 7 Jan 2021 19:39:45 +0000 Subject: [PATCH 40/62] Update frame/election-providers/src/two_phase/benchmarking.rs Co-authored-by: Shawn Tabrizi --- frame/election-providers/src/two_phase/benchmarking.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index f3c341f76bd9f..78dfa5a02f6cb 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -162,7 +162,6 @@ benchmarks! { > as sp_std::convert::TryFrom>::Error: sp_std::fmt::Debug, ExtendedBalance: From>>, } - _{} on_initialize_nothing { assert!(>::current_phase().is_off()); From e3862cef97083866fe08b5aed515c6793957c3f1 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 8 Jan 2021 09:22:57 +0000 Subject: [PATCH 41/62] Fix some review grumbles. --- Cargo.lock | 2 +- frame/election-providers/Cargo.toml | 2 +- frame/election-providers/src/onchain.rs | 19 ++--------- .../src/two_phase/benchmarking.rs | 7 ++-- .../election-providers/src/two_phase/mock.rs | 20 +----------- frame/election-providers/src/two_phase/mod.rs | 32 ++----------------- frame/staking/src/lib.rs | 26 ++------------- primitives/election-providers/src/lib.rs | 29 ++--------------- 8 files changed, 17 insertions(+), 120 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c13894561d39..9af6e72b6d853 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1599,7 +1599,7 @@ dependencies = [ "hex-literal", "pallet-balances", "parity-scale-codec", - "parking_lot 0.10.2", + "parking_lot 0.11.1", "paste 1.0.3", "rand 0.7.3", "serde", diff --git a/frame/election-providers/Cargo.toml b/frame/election-providers/Cargo.toml index ddd40f986bb59..3de94e73b2f6d 100644 --- a/frame/election-providers/Cargo.toml +++ b/frame/election-providers/Cargo.toml @@ -38,7 +38,7 @@ pallet-balances = { version = "2.0.0", path = "../balances" } sp-core = { version = "2.0.0", path = "../../primitives/core" } paste = "1.0.3" substrate-test-utils = { version = "2.0.0", path = "../../test-utils" } -parking_lot = "0.10.2" +parking_lot = "0.11.0" sp-tracing = { version = "2.0.0", path = "../../primitives/tracing" } rand = { version = "0.7.3" } frame-benchmarking = { path = "../benchmarking" } diff --git a/frame/election-providers/src/onchain.rs b/frame/election-providers/src/onchain.rs index efda232ade34f..f5df77a80d8b4 100644 --- a/frame/election-providers/src/onchain.rs +++ b/frame/election-providers/src/onchain.rs @@ -31,8 +31,6 @@ use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*}; pub enum Error { /// An internal error in the NPoS elections crate. NposElections(sp_npos_elections::Error), - /// An assignment failed to pass the feasibility check - Feasibility(&'static str), } impl From for Error { @@ -41,7 +39,7 @@ impl From for Error { } } -/// A simple on-chian implementation of the election provider trait. +/// A simple on-chain implementation of the election provider trait. /// /// This will accept voting data on the fly and produce the results immediately. /// @@ -92,13 +90,6 @@ where } = sp_npos_elections::seq_phragmen::<_, T::Accuracy>(desired_targets, targets, voters, None) .map_err(Error::from)?; - // check all assignments for feasibility, based on election data provider. - assignments - .iter() - .map(Self::DataProvider::feasibility_check_assignment) - .collect::>() - .map_err(|e| Error::Feasibility(e))?; - let staked = sp_npos_elections::assignment_ratio_to_staked_normalized(assignments, &stake_of)?; let winners = sp_npos_elections::to_without_backing(winners); @@ -114,7 +105,7 @@ where #[cfg(test)] mod tests { use super::*; - use sp_election_providers::{Assignment, VoteWeight}; + use sp_election_providers::VoteWeight; use sp_npos_elections::Support; use sp_runtime::Perbill; @@ -153,12 +144,6 @@ mod tests { 2 } - fn feasibility_check_assignment( - _: &Assignment, - ) -> Result<(), &'static str> { - Ok(()) - } - fn next_election_prediction(_: BlockNumber) -> BlockNumber { 0 } diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/election-providers/src/two_phase/benchmarking.rs index f3c341f76bd9f..b1b410a80acde 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/election-providers/src/two_phase/benchmarking.rs @@ -27,6 +27,7 @@ use rand::{prelude::SliceRandom, rngs::SmallRng, SeedableRng}; use sp_election_providers::Assignment; use sp_npos_elections::ExtendedBalance; use sp_runtime::InnerOf; +use sp_arithmetic::traits::One; use sp_std::convert::TryInto; const SEED: u32 = 0; @@ -58,7 +59,8 @@ where "must have enough winners to give them votes." ); - let stake: u64 = 1000_000; + let ed: VoteWeight = T::Currency::minimum_balance().saturated_into::(); + let stake: VoteWeight = ed.max(One::one()).saturating_mul(100); // first generates random targets. let targets: Vec = (0..witness.targets) @@ -123,7 +125,7 @@ where targets: targets.clone(), }); // write the snapshot to staking or whoever is the data provider. - T::DataProvider::put_npos_snapshot(all_voters.clone(), targets.clone()); + T::DataProvider::put_snapshot(all_voters.clone(), targets.clone()); let stake_of = crate::stake_of_fn!(all_voters, T::AccountId); let voter_index = crate::voter_index_fn!(all_voters, T::AccountId, T); @@ -162,7 +164,6 @@ benchmarks! { > as sp_std::convert::TryFrom>::Error: sp_std::fmt::Debug, ExtendedBalance: From>>, } - _{} on_initialize_nothing { assert!(>::current_phase().is_off()); diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/election-providers/src/two_phase/mock.rs index 19ecd71c24cb5..35d15b8853ee8 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/election-providers/src/two_phase/mock.rs @@ -14,7 +14,7 @@ use sp_core::{ }, H256, }; -use sp_election_providers::{Assignment, ElectionDataProvider}; +use sp_election_providers::ElectionDataProvider; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, to_without_backing, CompactSolution, ElectionResult, EvaluateSupport, @@ -193,7 +193,6 @@ parameter_types! { (30, 30, vec![30]), (40, 40, vec![40]), ]; - pub static BlacklistedVoters: Vec = vec![]; pub static DesiredTargets: u32 = 2; pub static SignedDepositBase: Balance = 5; pub static SignedDepositByte: Balance = 0; @@ -322,19 +321,6 @@ impl ElectionDataProvider for StakingMock { fn desired_targets() -> u32 { DesiredTargets::get() } - fn feasibility_check_assignment( - assignment: &Assignment, - ) -> Result<(), &'static str> { - if ::get() - .into_iter() - .find(|x| *x == assignment.who) - .is_some() - { - Err("blacklisted") - } else { - Ok(()) - } - } fn next_election_prediction(now: u64) -> u64 { now + EpochLength::get() - now % EpochLength::get() } @@ -390,10 +376,6 @@ impl ExtBuilder { VOTERS.with(|v| v.borrow_mut().push((who, stake, targets))); self } - pub fn blacklist_voter(self, who: AccountId) -> Self { - BLACKLISTED_VOTERS.with(|v| v.borrow_mut().push(who)); - self - } pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::default() diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 4c06d757370dc..8723966610db2 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -118,9 +118,7 @@ //! 0. **all** of the used indices must be correct. //! 1. present correct number of winners. //! 2. any assignment is checked to match with [`Snapshot::voters`]. -//! 3. for each assignment, the check of ``ElectionDataProvider::feasibility_check_assignment`` is -//! also examined and must be correct. -//! 4. the claimed score is valid. +//! 3. the claimed score is valid. //! //! ## Accuracy //! @@ -475,8 +473,6 @@ pub enum FeasibilityError { InvalidWinner, /// The given score was invalid. InvalidScore, - /// An error from the data provider's feasibility check - DataProvider(&'static str), /// The provided round is incorrect. InvalidRound, } @@ -1088,16 +1084,13 @@ where .find(|(v, _, _)| v == &assignment.who) .ok_or(FeasibilityError::InvalidVoter)?; // check that all of the targets are valid based on the snapshot. - if !assignment + if assignment .distribution .iter() - .all(|(d, _)| targets.contains(d)) + .any(|(d, _)| !targets.contains(d)) { return Err(FeasibilityError::InvalidVote); } - // check the feasibility based on the data provider - T::DataProvider::feasibility_check_assignment::>(assignment) - .map_err(|r| FeasibilityError::DataProvider(r))?; Ok(()) }) .collect::>()?; @@ -1397,25 +1390,6 @@ mod feasibility_check { ); }) } - - #[test] - fn data_provider_feasibility_chec() { - ExtBuilder::default() - .blacklist_voter(4) - .build_and_execute(|| { - roll_to(::get() - ::get() - ::get()); - assert!(TwoPhase::current_phase().is_signed()); - - let solution = raw_solution(); - assert_eq!(TwoPhase::snapshot().unwrap().voters.len(), 8); - - // solution already contains a vote from 4, nothing to do. - assert_noop!( - TwoPhase::feasibility_check(solution, COMPUTE), - FeasibilityError::DataProvider("blacklisted"), - ); - }) - } } #[cfg(test)] diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index f91ae7f6fd4d0..2a973362c2e04 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -304,7 +304,7 @@ use frame_support::{ }; use pallet_session::historical; use sp_runtime::{ - Percent, Perbill, PerU16, PerThing, InnerOf, RuntimeDebug, DispatchError, + Percent, Perbill, PerU16, InnerOf, RuntimeDebug, DispatchError, curve::PiecewiseLinear, traits::{ Convert, Zero, StaticLookup, CheckedSub, Saturating, SaturatedConversion, @@ -3305,30 +3305,8 @@ impl sp_election_providers::ElectionDataProvider( - assignment: &Assignment, - ) -> Result<(), &'static str> { - if let Some(nomination) = Self::nominators(&assignment.who) { - if assignment.distribution.iter().all(|(t, _)| { - Self::slashing_spans(t).map_or(true, |spans| { - nomination.submitted_in >= spans.last_nonzero_slash() - }) - }) { - Ok(()) - } else { - Err("Slashed distribution.") - } - } else if >::contains_key(&assignment.who) { - // validators can self-vote in any case if they want to. NOTE: self vote itself is - // checked by the election provider module, because we inject the self vote. - Ok(()) - } else { - Err("Unknown assignment") - } - } - #[cfg(any(feature = "runtime-benchmarks", test))] - fn put_npos_snapshot( + fn put_snapshot( voters: Vec<(T::AccountId, VoteWeight, Vec)>, targets: Vec, ) { diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index 8fe652a05e19b..713e1fbc4052e 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -108,11 +108,6 @@ //! fn targets() -> Vec { //! vec![10, 20, 30] //! } -//! fn feasibility_check_assignment( -//! _: &Assignment, -//! ) -> Result<(), &'static str> { -//! Ok(()) -//! } //! fn next_election_prediction(now: BlockNumber) -> BlockNumber { //! 0 //! } @@ -185,20 +180,6 @@ pub trait ElectionDataProvider { /// The number of targets to elect. fn desired_targets() -> u32; - /// Check the feasibility of a single assignment for the underlying [`ElectionProvider`]. This - /// might be called by the [`ElectionProvider`] upon processing election solutions. - /// - /// Note that each this must only contain checks that the [`ElectionProvider`] cannot know - /// about. Basics checks that can be known from [`Self::voters`] and [`Self::targets`] should - /// typically be done by [`ElectionProvider`]. - /// - /// For example, if a pallet contains some *private* knowledge that could potentially invalidate - /// an `assignment`, it should be checked here, as [`ElectionProvider`] has no way of knowing - /// about it. - fn feasibility_check_assignment( - assignment: &Assignment, - ) -> Result<(), &'static str>; - /// Provide a best effort prediction about when the next election is about to happen. /// /// In essence, the implementor should predict with this function when it will trigger the @@ -210,10 +191,11 @@ pub trait ElectionDataProvider { /// Utility function only to be used in benchmarking scenarios, to be implemented optionally, /// else a noop. #[cfg(any(feature = "runtime-benchmarks", test))] - fn put_npos_snapshot( + fn put_snapshot( _voters: Vec<(AccountId, VoteWeight, Vec)>, _targets: Vec, - ) {} + ) { + } } impl ElectionDataProvider for () { @@ -226,11 +208,6 @@ impl ElectionDataProvider for () fn desired_targets() -> u32 { Default::default() } - fn feasibility_check_assignment( - _: &Assignment, - ) -> Result<(), &'static str> { - Err("() as ElectionDataProvider cannot do anything.") - } fn next_election_prediction(now: BlockNumber) -> BlockNumber { now } From ca06f8e925e3873d0b3b908cc92b518bbe12fa66 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 8 Jan 2021 10:15:26 +0000 Subject: [PATCH 42/62] Fix some docs --- frame/election-providers/src/lib.rs | 8 ++- frame/election-providers/src/two_phase/mod.rs | 62 ++++++++++--------- primitives/election-providers/src/lib.rs | 2 +- primitives/npos-elections/src/lib.rs | 9 +-- 4 files changed, 47 insertions(+), 34 deletions(-) diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs index fbd20a9287aed..30f8d9fb3a820 100644 --- a/frame/election-providers/src/lib.rs +++ b/frame/election-providers/src/lib.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Various implementation for `ElectionProvider`. +//! Various implementation for [`sp_election_providers::ElectionProvider`]. //! //! Two main election providers are implemented in this crate. //! @@ -32,6 +32,12 @@ pub mod onchain; /// The two-phase module. pub mod two_phase; +// re-export only for docs, as it help with intra-crate link resolution. +#[cfg(doc)] +pub use two_phase::*; +#[cfg(doc)] +pub use onchain::*; + const LOG_TARGET: &'static str = "election-provider"; // for the helper macros diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/election-providers/src/two_phase/mod.rs index 8723966610db2..3f7b8a58a4770 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/election-providers/src/two_phase/mod.rs @@ -23,9 +23,9 @@ //! ## Phases //! //! The timeline of pallet is as follows. At each block, -//! [`ElectionDataProvider::next_election_prediction`] is used to estimate the time remaining to the -//! next call to [`ElectionProvider::elect`]. Based on this, a phase is chosen. The timeline is as -//! follows. +//! [`sp_election_providers::ElectionDataProvider::next_election_prediction`] is used to estimate +//! the time remaining to the next call to [`sp_election_providers::ElectionProvider::elect`]. Based +//! on this, a phase is chosen. The timeline is as follows. //! //! ```ignore //! elect() @@ -35,9 +35,12 @@ //! //! ``` //! -//! Note that the unsigned phase starts [`Config::UnsignedPhase`] blocks before the -//! `next_election_prediction`, but only ends when a call to [`Config::ElectionProvider::elect`] -//! happens. +//! Note that the unsigned phase starts [`pallet::Config::UnsignedPhase`] blocks before the +//! `next_election_prediction`, but only ends when a call to +//! [`pallet::Config::ElectionProvider::elect`] happens. +//! +//! > Given this, it is rather important for the user of this pallet to ensure it alwasy terminates +//! election via `elect` before requesting a new one. //! //! Each of the phases can be disabled by essentially setting their length to zero. If both phases //! have length zero, then the pallet essentially runs only the on-chain backup. @@ -47,8 +50,8 @@ //! In the signed phase, solutions (of type [`RawSolution`]) are submitted and queued on chain. A //! deposit is reserved, based on the size of the solution, for the cost of keeping this solution //! on-chain for a number of blocks, and the potential weight of the solution upon being checked. A -//! maximum of [`Config::MaxSignedSubmissions`] solutions are stored. The queue is always sorted -//! based on score (worse to best). +//! maximum of [`pallet::Config::MaxSignedSubmissions`] solutions are stored. The queue is always +//! sorted based on score (worse to best). //! //! Upon arrival of a new solution: //! @@ -63,7 +66,7 @@ //! origin can not bail out in any way, if their solution is queued. //! //! Upon the end of the signed phase, the solutions are examined from best to worse (i.e. `pop()`ed -//! until drained). Each solution undergoes an expensive [`Module::feasibility_check`], which +//! until drained). Each solution undergoes an expensive [`Pallet::feasibility_check`], which //! ensures the score claimed by this score was correct, and it is valid based on the election data //! (i.e. votes and candidates). At each step, if the current best solution passes the feasibility //! check, it is considered to be the best one. The sender of the origin is rewarded, and the rest @@ -98,16 +101,16 @@ //! valid if propagated, and it acts similar to an inherent. //! //! Validators will only submit solutions if the one that they have computed is sufficiently better -//! than the best queued one (see [`SolutionImprovementThreshold`]) and will limit the weigh of the -//! solution to [`MinerMaxWeight`]. +//! than the best queued one (see [`pallet::Config::SolutionImprovementThreshold`]) and will limit +//! the weigh of the solution to [`pallet::Config::MinerMaxWeight`]. //! //! ### Fallback //! //! If we reach the end of both phases (i.e. call to [`ElectionProvider::elect`] happens) and no -//! good solution is queued, then the fallback strategy [`Config::Fallback`] is used to determine -//! what needs to be done. The on-chain election is slow, and contains no balancing or reduction -//! post-processing. See [`onchain::OnChainSequentialPhragmen`]. The [`FallbackStrategy::Nothing`] -//! should probably only be used for testing. +//! good solution is queued, then the fallback strategy [`pallet::Config::Fallback`] is used to +//! determine what needs to be done. The on-chain election is slow, and contains no balancing or +//! reduction post-processing. See [`onchain::OnChainSequentialPhragmen`]. The +//! [`FallbackStrategy::Nothing`] should probably only be used for testing, and returns an error. //! //! ## Feasible Solution (correct solution) //! @@ -116,16 +119,15 @@ //! is as follows: //! //! 0. **all** of the used indices must be correct. -//! 1. present correct number of winners. +//! 1. present *exactly* correct number of winners. //! 2. any assignment is checked to match with [`Snapshot::voters`]. -//! 3. the claimed score is valid. +//! 3. the claimed score is valid, based on the fixed point arithmetic accuracy. //! //! ## Accuracy //! //! The accuracy of the election is configured via two trait parameters. namely, -//! [`Config::OnChainAccuracy`] dictates the accuracy used to compute the on-chain fallback election -//! (see [`OnChainAccuracyOf`]) and `[Config::DataProvider::CompactSolution::Accuracy]` is the -//! accuracy that the submitted solutions must adhere to. +//! [`OnChainAccuracyOf`] dictates the accuracy used to compute the on-chain fallback election and +//! [`CompactAccuracyOf`] is the accuracy that the submitted solutions must adhere to. //! //! Note that both accuracies are of great importance. The offchain solution should be as small as //! possible, reducing solutions size/weight. The on-chain solution can use more space for accuracy, @@ -148,7 +150,7 @@ //! afterwards, and remove their solution (for a small cost of probably just transaction fees, or a //! portion of the bond). //! -//! ** Conditionally open unsigned phase: Currently, the unsigned phase is always opened. This is +//! **Conditionally open unsigned phase**: Currently, the unsigned phase is always opened. This is //! useful because an honest validation will run our OCW code, which should be good enough to trump //! a mediocre or malicious signed submission (assuming in the absence of honest signed bots). If an //! when the signed submissions are checked against an absolute measure (e.g. PJR), then we can only @@ -160,9 +162,13 @@ //! solution within this range is acceptable, where bigger solutions are prioritized. //! //! **Recursive Fallback**: Currently, the fallback is a separate enum. A different and fancier way -//! of doing this would be to have the fallback be another [`ElectionProvider`]. In this case, this -//! pallet can even have the on-chain election provider as fallback, or special _noop_ fallback that -//! simply returns an error, thus replicating `Fallback::Nothing`. +//! of doing this would be to have the fallback be another +//! [`sp_election_provider::ElectionProvider`]. In this case, this pallet can even have the on-chain +//! election provider as fallback, or special _noop_ fallback that simply returns an error, thus +//! replicating [`FallbackStrategy::Nothing`]. +//! +//! **Score based on size**: We should always prioritize small solutions over bigger ones, if there +//! is a tie. Even more harsh should be to enforce the bound of the `reduce` algorithm. use crate::onchain::OnChainSequentialPhragmen; use codec::{Decode, Encode, HasCompact}; @@ -213,7 +219,7 @@ pub type CompactVoterIndexOf = as CompactSolution>::Voter; pub type CompactTargetIndexOf = as CompactSolution>::Target; /// The accuracy of the election, when submitted from offchain. Derived from [`CompactOf`]. pub type CompactAccuracyOf = as CompactSolution>::Accuracy; -/// The accuracy of the election, when computed on-chain. Equal to [`T::OnChainAccuracy`]. +/// The accuracy of the election, when computed on-chain. Equal to [`Config::OnChainAccuracy`]. pub type OnChainAccuracyOf = ::OnChainAccuracy; type BalanceOf = @@ -321,7 +327,7 @@ impl Default for ElectionCompute { /// This is what will get submitted to the chain. /// /// Such a solution should never become effective in anyway before being checked by the -/// [`Module::feasibility_check`] +/// [`Pallet::feasibility_check`] #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] pub struct RawSolution { /// Compact election edges. @@ -943,7 +949,7 @@ where ExtendedBalance: From>>, ExtendedBalance: From>>, { - /// Logic for [`Module::on_initialize`] when signed phase is being opened. + /// Logic for [`Pallet::on_initialize`] when signed phase is being opened. /// /// This is decoupled for easy weight calculation. pub fn on_initialize_open_signed() { @@ -952,7 +958,7 @@ where Self::deposit_event(Event::SignedPhaseStarted(Self::round())); } - /// Logic for [`Module::on_initialize`] when unsigned phase is being opened. + /// Logic for [`Pallet::on_initialize`] when unsigned phase is being opened. /// /// This is decoupled for easy weight calculation. Note that the default weight benchmark of /// this function will assume an empty signed queue for `finalize_signed_phase`. diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index 713e1fbc4052e..76cea316b292b 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -183,7 +183,7 @@ pub trait ElectionDataProvider { /// Provide a best effort prediction about when the next election is about to happen. /// /// In essence, the implementor should predict with this function when it will trigger the - /// [`ElectionDataProvider::elect`]. + /// [`ElectionProvider::elect`]. /// /// This is only useful for stateful election providers. fn next_election_prediction(now: BlockNumber) -> BlockNumber; diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 69aaa23e7ba9b..e31f1efc68c65 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -133,7 +133,7 @@ impl __OrInvalidIndex for Option { /// A common interface for all compact solutions. /// -/// See [`compact`] for more info. +/// See [`sp-npos-elections-compact`] for more info. pub trait CompactSolution: Sized { /// The maximum number of votes that are allowed. const LIMIT: usize; @@ -253,7 +253,8 @@ pub type VoteWeight = u64; /// A type in which performing operations on vote weights are safe. pub type ExtendedBalance = u128; -/// The score of an assignment. This can be computed from the support map via [`evaluate_support`]. +/// The score of an assignment. This can be computed from the support map via +/// [`EvaluateSupport::evaluate`]. pub type ElectionScore = [ExtendedBalance; 3]; /// A winner, with their respective approval stake. @@ -600,7 +601,7 @@ impl FlattenSupportMap for SupportMap { /// Build the support map from the winners and assignments. /// /// The list of winners is basically a redundancy for error checking only; It ensures that all the -/// targets pointed to by the [`assignments`] are present in the `winners`. +/// targets pointed to by the [`Assignment`] are present in the `winners`. pub fn to_support_map( winners: &[A], assignments: &[StakedAssignment], @@ -628,7 +629,7 @@ pub fn to_support_map( /// Same as [`to_support_map`] except it calls `FlattenSupportMap` on top of the result to return a /// flat vector. /// -/// Similar to [`build_support_map`], `winners` is used for error checking. +/// Similar to [`to_support_map`], `winners` is used for error checking. pub fn to_supports( winners: &[A], assignments: &[StakedAssignment], From 63776ff8d14fddc0b33c129bbf33b4f887a2a1c7 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 8 Jan 2021 16:50:31 +0000 Subject: [PATCH 43/62] Maybe relocalte the code? --- Cargo.lock | 885 +++++++++--------- Cargo.toml | 2 +- bin/node/runtime/Cargo.toml | 6 +- bin/node/runtime/src/lib.rs | 1 - frame/election-providers/src/lib.rs | 49 - frame/staking/Cargo.toml | 1 - frame/staking/src/mock.rs | 2 +- .../Cargo.toml | 4 +- .../src}/benchmarking.rs | 4 +- .../src/lib.rs} | 53 +- .../src}/macros.rs | 16 +- .../src}/mock.rs | 21 +- .../src}/signed.rs | 2 +- .../src}/unsigned.rs | 6 +- .../src}/weights.rs | 0 primitives/election-providers/Cargo.toml | 10 +- primitives/election-providers/src/lib.rs | 1 + .../election-providers/src/onchain.rs | 9 +- 18 files changed, 525 insertions(+), 547 deletions(-) delete mode 100644 frame/election-providers/src/lib.rs rename frame/{election-providers => two-phase-election-provider}/Cargo.toml (96%) rename frame/{election-providers/src/two_phase => two-phase-election-provider/src}/benchmarking.rs (99%) rename frame/{election-providers/src/two_phase/mod.rs => two-phase-election-provider/src/lib.rs} (97%) rename frame/{election-providers/src/two_phase => two-phase-election-provider/src}/macros.rs (73%) rename frame/{election-providers/src/two_phase => two-phase-election-provider/src}/mock.rs (93%) rename frame/{election-providers/src/two_phase => two-phase-election-provider/src}/signed.rs (99%) rename frame/{election-providers/src/two_phase => two-phase-election-provider/src}/unsigned.rs (99%) rename frame/{election-providers/src/two_phase => two-phase-election-provider/src}/weights.rs (100%) rename {frame => primitives}/election-providers/src/onchain.rs (93%) diff --git a/Cargo.lock b/Cargo.lock index 7d1be8446c013..e7dd6d417a15a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,9 +12,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" dependencies = [ "gimli 0.23.0", ] @@ -55,7 +55,7 @@ dependencies = [ "aes", "block-cipher", "ghash", - "subtle 2.3.0", + "subtle 2.4.0", ] [[package]] @@ -81,9 +81,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6789e291be47ace86a60303502173d84af8327e3627ecf334356ee0f87a164c" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" [[package]] name = "aho-corasick" @@ -114,9 +114,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.34" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" +checksum = "ee67c11feeac938fae061b232e38e0b6d94f97a9df10e6271319325ac4c56a86" [[package]] name = "approx" @@ -135,9 +135,9 @@ checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569" [[package]] name = "arc-swap" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" +checksum = "dabe5a181f83789739c194cbe5a897dde195078fac08568d09221fd6137a7ba8" [[package]] name = "arrayref" @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "assert_cmd" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c88b9ca26f9c16ec830350d309397e74ee9abdfd8eb1f71cb6ecc71a3fc818da" +checksum = "3dc1679af9a1ab4bea16f228b05d18f8363f8327b1fa8db00d2760cfafc6b61e" dependencies = [ "doc-comment", "predicates", @@ -265,17 +265,35 @@ dependencies = [ "event-listener", ] +[[package]] +name = "async-process" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8cea09c1fb10a317d1b5af8024eeba256d6554763e85ecd90ff8df31c7bbda" +dependencies = [ + "async-io", + "blocking", + "cfg-if 0.1.10", + "event-listener", + "futures-lite", + "once_cell", + "signal-hook", + "winapi 0.3.9", +] + [[package]] name = "async-std" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7e82538bc65a25dbdff70e4c5439d52f068048ab97cdea0acd73f131594caa1" +checksum = "8f9f84f1280a2b436a2c77c2582602732b6c2f4321d5494d6e799e6c367859a8" dependencies = [ + "async-channel", "async-global-executor", "async-io", "async-mutex", + "async-process", "blocking", - "crossbeam-utils 0.8.0", + "crossbeam-utils 0.8.1", "futures-channel", "futures-core", "futures-io", @@ -286,7 +304,7 @@ dependencies = [ "memchr", "num_cpus", "once_cell", - "pin-project-lite 0.1.11", + "pin-project-lite 0.2.1", "pin-utils", "slab", "wasm-bindgen-futures", @@ -313,9 +331,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b246867b8b3b6ae56035f1eb1ed557c1d8eae97f0d53696138a50fa0e3a3b8c0" +checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" dependencies = [ "proc-macro2", "quote", @@ -362,9 +380,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.54" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2baad346b2d4e94a24347adeee9c7a93f412ee94b9cc26e5b59dea23848e9f28" +checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" dependencies = [ "addr2line", "cfg-if 1.0.0", @@ -581,9 +599,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "ffea412272c01cbee45e0d34f71c54af698d48f7d404a61fb46b71f48e3f30db" [[package]] name = "bytes" @@ -610,11 +628,12 @@ checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" [[package]] name = "cargo_metadata" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345" +checksum = "83f95cf4bf0dda0ac2e65371ae7215d0dce3c187613a9dbf23aaa9374186f97a" dependencies = [ "semver 0.11.0", + "semver-parser 0.10.0", "serde", "serde_json", ] @@ -630,9 +649,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.62" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" dependencies = [ "jobserver", ] @@ -763,15 +782,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "cloudabi" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" -dependencies = [ - "bitflags", -] - [[package]] name = "concurrent-queue" version = "1.2.2" @@ -803,9 +813,9 @@ dependencies = [ [[package]] name = "const_fn" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab" +checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" [[package]] name = "constant_time_eq" @@ -835,6 +845,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" +[[package]] +name = "cpuid-bool" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" + [[package]] name = "cranelift-bforest" version = "0.66.0" @@ -859,7 +875,7 @@ dependencies = [ "log", "regalloc", "serde", - "smallvec 1.5.0", + "smallvec 1.6.0", "target-lexicon", "thiserror", ] @@ -897,7 +913,7 @@ checksum = "2ef419efb4f94ecc02e5d9fbcc910d2bb7f0040e2de570e63a454f883bc891d6" dependencies = [ "cranelift-codegen", "log", - "smallvec 1.5.0", + "smallvec 1.6.0", "target-lexicon", ] @@ -979,7 +995,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.0", + "crossbeam-utils 0.8.1", ] [[package]] @@ -1000,8 +1016,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ "cfg-if 1.0.0", - "crossbeam-epoch 0.9.0", - "crossbeam-utils 0.8.0", + "crossbeam-epoch 0.9.1", + "crossbeam-utils 0.8.1", ] [[package]] @@ -1015,21 +1031,21 @@ dependencies = [ "crossbeam-utils 0.7.2", "lazy_static", "maybe-uninit", - "memoffset", + "memoffset 0.5.6", "scopeguard", ] [[package]] name = "crossbeam-epoch" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f" +checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" dependencies = [ "cfg-if 1.0.0", "const_fn", - "crossbeam-utils 0.8.0", + "crossbeam-utils 0.8.1", "lazy_static", - "memoffset", + "memoffset 0.6.1", "scopeguard", ] @@ -1057,13 +1073,12 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5" +checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" dependencies = [ "autocfg 1.0.1", "cfg-if 1.0.0", - "const_fn", "lazy_static", ] @@ -1090,14 +1105,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array 0.14.4", - "subtle 2.3.0", + "subtle 2.4.0", ] [[package]] name = "csv" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4666154fd004af3fd6f1da2e81a96fd5a81927fe8ddb6ecc79e2aa6e138b54" +checksum = "f9d58633299b24b515ac72a3f869f8b91306a3cec616a602843a383acd6f9e97" dependencies = [ "bstr", "csv-core", @@ -1126,9 +1141,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484" +checksum = "373c88d9506e2e9230f6107701b7d8425f4cb3f6df108ec3042a26e936666da5" dependencies = [ "quote", "syn", @@ -1147,27 +1162,27 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "2.1.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5" +checksum = "434e1720189a637d44fe464f4df1e6eb900b4835255b14354497c78af37d9bb8" dependencies = [ "byteorder", "digest 0.8.1", "rand_core 0.5.1", - "subtle 2.3.0", + "subtle 2.4.0", "zeroize", ] [[package]] name = "curve25519-dalek" -version = "3.0.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8492de420e9e60bc9a1d66e2dbb91825390b738a388606600663fc529b4b307" +checksum = "f627126b946c25a4638eec0ea634fc52506dea98db118aae985118ce7c3d723f" dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", - "subtle 2.3.0", + "subtle 2.4.0", "zeroize", ] @@ -1287,9 +1302,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d55796afa1b20c2945ca8eabfc421839f2b766619209f1ede813cf2484f31804" +checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" [[package]] name = "ed25519" @@ -1306,7 +1321,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek 3.0.0", + "curve25519-dalek 3.0.2", "ed25519", "rand 0.7.3", "serde", @@ -1374,9 +1389,9 @@ checksum = "6576a1755ddffd988788025e75bce9e74b018f7cc226198fe931d077911c6d7e" [[package]] name = "erased-serde" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ca8b296792113e1500fd935ae487be6e00ce318952a6880555554824d6ebf38" +checksum = "0465971a8cc1fa2455c8465aaa377131e1f1cf4983280f474a13e68793aa770c" dependencies = [ "serde", ] @@ -1414,7 +1429,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", ] [[package]] @@ -1486,7 +1501,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8feb87a63249689640ac9c011742c33139204e3c134293d3054022276869133b" dependencies = [ "either", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 2.0.2", "log", "num-traits", @@ -1589,32 +1604,6 @@ dependencies = [ "structopt", ] -[[package]] -name = "frame-election-providers" -version = "2.0.0" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "hex-literal", - "pallet-balances", - "parity-scale-codec", - "parking_lot 0.11.1", - "paste 1.0.3", - "rand 0.7.3", - "serde", - "sp-arithmetic", - "sp-core", - "sp-election-providers", - "sp-io", - "sp-npos-elections", - "sp-runtime", - "sp-std", - "sp-tracing", - "static_assertions", - "substrate-test-utils", -] - [[package]] name = "frame-executive" version = "2.0.0" @@ -1661,7 +1650,7 @@ dependencies = [ "paste 0.1.18", "pretty_assertions", "serde", - "smallvec 1.5.0", + "smallvec 1.6.0", "sp-api", "sp-arithmetic", "sp-core", @@ -1814,9 +1803,9 @@ checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" [[package]] name = "futures" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3b0c040a1fe6529d30b3c5944b280c7f0dcb2930d2c3062bca967b602583d0" +checksum = "c70be434c505aee38639abccb918163b63158a4b4bb791b45b7023044bdc3c9c" dependencies = [ "futures-channel", "futures-core", @@ -1829,9 +1818,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7109687aa4e177ef6fe84553af6280ef2778bdb7783ba44c9dc3399110fe64" +checksum = "f01c61843314e95f96cc9245702248733a3a3d744e43e2e755e3c7af8348a0a9" dependencies = [ "futures-core", "futures-sink", @@ -1839,9 +1828,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "847ce131b72ffb13b6109a221da9ad97a64cbe48feb1028356b836b47b8f1748" +checksum = "db8d3b0917ff63a2a96173133c02818fac4a746b0a57569d3baca9ec0e945e08" [[package]] name = "futures-cpupool" @@ -1860,7 +1849,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdcef58a173af8148b182684c9f2d5250875adbcaff7b5794073894f9d8634a9" dependencies = [ "futures 0.1.30", - "futures 0.3.8", + "futures 0.3.9", "lazy_static", "log", "parking_lot 0.9.0", @@ -1871,9 +1860,9 @@ dependencies = [ [[package]] name = "futures-executor" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4caa2b2b68b880003057c1dd49f1ed937e38f22fcf6c212188a121f08cf40a65" +checksum = "9ee9ca2f7eb4475772cf39dd1cd06208dce2670ad38f4d9c7262b3e15f127068" dependencies = [ "futures-core", "futures-task", @@ -1883,30 +1872,30 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611834ce18aaa1bd13c4b374f5d653e1027cf99b6b502584ff8c9a64413b30bb" +checksum = "e37c1a51b037b80922864b8eed90692c5cd8abd4c71ce49b77146caa47f3253b" [[package]] name = "futures-lite" -version = "1.11.2" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6c079abfac3ab269e2927ec048dabc89d009ebfdda6b8ee86624f30c689658" +checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb" dependencies = [ "fastrand", "futures-core", "futures-io", "memchr", "parking", - "pin-project-lite 0.1.11", + "pin-project-lite 0.2.1", "waker-fn", ] [[package]] name = "futures-macro" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77408a692f1f97bcc61dc001d752e00643408fbc922e4d634c655df50d595556" +checksum = "0f8719ca0e1f3c5e34f3efe4570ef2c0610ca6da85ae7990d472e9cbfba13664" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -1916,15 +1905,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f878195a49cee50e006b02b93cf7e0a95a38ac7b776b4c4d9cc1207cd20fcb3d" +checksum = "f6adabac1290109cfa089f79192fb6244ad2c3f1cc2281f3e1dd987592b71feb" [[package]] name = "futures-task" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c554eb5bf48b2426c4771ab68c6b14468b6e76cc90996f528c3338d761a4d0d" +checksum = "a92a0843a2ff66823a8f7c77bffe9a09be2b64e533562c412d63075643ec0038" dependencies = [ "once_cell", ] @@ -1947,9 +1936,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d304cff4a7b99cfb7986f7d43fbe93d175e72e704a8860787cc95e9ffd85cbd2" +checksum = "036a2107cdeb57f6d7322f1b6c363dad67cd63ca3b7d1b925bdf75bd5d96cda9" dependencies = [ "futures 0.1.30", "futures-channel", @@ -1959,7 +1948,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project 1.0.2", + "pin-project-lite 0.2.1", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -1973,7 +1962,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce54d63f8b0c75023ed920d46fd71d0cbbb830b0ee012726b5b4f506fb6dea5b" dependencies = [ "bytes 0.5.6", - "futures 0.3.8", + "futures 0.3.9", "memchr", "pin-project 0.4.27", ] @@ -1984,19 +1973,6 @@ version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -[[package]] -name = "generator" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc" -dependencies = [ - "cc", - "libc", - "log", - "rustc_version", - "winapi 0.3.9", -] - [[package]] name = "generic-array" version = "0.12.3" @@ -2027,11 +2003,12 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", "wasm-bindgen", @@ -2046,16 +2023,17 @@ dependencies = [ "cfg-if 1.0.0", "js-sys", "libc", - "wasi 0.10.0+wasi-snapshot-preview1", + "wasi 0.10.1+wasi-snapshot-preview1", "wasm-bindgen", ] [[package]] name = "ghash" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6e27f0689a6e15944bdce7e45425efb87eaa8ab0c6e87f11d0987a9133e2531" +checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" dependencies = [ + "opaque-debug 0.3.0", "polyval", ] @@ -2137,10 +2115,10 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.1", + "http 0.2.2", "indexmap", "slab", - "tokio 0.2.23", + "tokio 0.2.24", "tokio-util", "tracing", "tracing-futures", @@ -2154,9 +2132,9 @@ checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" [[package]] name = "handlebars" -version = "3.5.1" +version = "3.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2764f9796c0ddca4b82c07f25dd2cb3db30b9a8f47940e78e1c883d9e95c3db9" +checksum = "964d0e99a61fe9b1b347389b77ebf8b7e1587b70293676aaca7d27e59b9073b2" dependencies = [ "log", "pest", @@ -2192,9 +2170,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" dependencies = [ "unicode-segmentation", ] @@ -2281,9 +2259,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" +checksum = "84129d298a6d57d246960ff8eb831ca4af3f96d29e2e28848dae275408658e26" dependencies = [ "bytes 0.5.6", "fnv", @@ -2309,7 +2287,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" dependencies = [ "bytes 0.5.6", - "http 0.2.1", + "http 0.2.2", ] [[package]] @@ -2374,14 +2352,14 @@ dependencies = [ "futures-core", "futures-util", "h2 0.2.7", - "http 0.2.1", + "http 0.2.2", "http-body 0.3.1", "httparse", "httpdate", "itoa", - "pin-project 1.0.2", + "pin-project 1.0.3", "socket2", - "tokio 0.2.23", + "tokio 0.2.24", "tower-service", "tracing", "want 0.3.0", @@ -2400,7 +2378,7 @@ dependencies = [ "log", "rustls 0.18.1", "rustls-native-certs", - "tokio 0.2.23", + "tokio 0.2.24", "tokio-rustls", "webpki", ] @@ -2455,7 +2433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16d7c5e361e6b05c882b4847dd98992534cebc6fcde7f4bc98225bcf10fd6d0d" dependencies = [ "async-io", - "futures 0.3.8", + "futures 0.3.9", "futures-lite", "if-addrs", "ipnet", @@ -2506,9 +2484,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" +checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" dependencies = [ "autocfg 1.0.1", "hashbrown", @@ -2517,9 +2495,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -2542,7 +2520,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64fa110ec7b8f493f416eed552740d10e7030ad5f63b2308f82c9608ec2df275" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "futures-timer 2.0.2", ] @@ -2587,9 +2565,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "jobserver" @@ -2775,7 +2753,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92312348daade49976a6dc59263ad39ed54f840aacb5664874f7c9aa16e5f848" dependencies = [ "parity-util-mem", - "smallvec 1.5.0", + "smallvec 1.6.0", ] [[package]] @@ -2804,7 +2782,7 @@ dependencies = [ "parking_lot 0.11.1", "regex", "rocksdb", - "smallvec 1.5.0", + "smallvec 1.6.0", ] [[package]] @@ -2813,7 +2791,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7bfe11b3202691673766b1224c432996f6b8047db17ceb743675bef3404e714" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "js-sys", "kvdb", "kvdb-memorydb", @@ -2845,9 +2823,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" [[package]] name = "libloading" @@ -2873,7 +2851,7 @@ checksum = "2e17c636b5fe5ff900ccc2840b643074bfac321551d821243a781d0d46f06588" dependencies = [ "atomic", "bytes 0.5.6", - "futures 0.3.8", + "futures 0.3.9", "lazy_static", "libp2p-core", "libp2p-core-derive", @@ -2898,8 +2876,8 @@ dependencies = [ "libp2p-yamux", "parity-multiaddr", "parking_lot 0.11.1", - "pin-project 1.0.2", - "smallvec 1.5.0", + "pin-project 1.0.3", + "smallvec 1.6.0", "wasm-timer", ] @@ -2914,7 +2892,7 @@ dependencies = [ "ed25519-dalek", "either", "fnv", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "lazy_static", "libsecp256k1", @@ -2923,14 +2901,14 @@ dependencies = [ "multistream-select", "parity-multiaddr", "parking_lot 0.11.1", - "pin-project 1.0.2", + "pin-project 1.0.3", "prost", "prost-build", "rand 0.7.3", "ring", "rw-stream-sink", "sha2 0.9.2", - "smallvec 1.5.0", + "smallvec 1.6.0", "thiserror", "unsigned-varint", "void", @@ -2954,7 +2932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3257a41f376aa23f237231971fee7e350e4d8353cfcf233aef34d6d6b638f0c" dependencies = [ "flate2", - "futures 0.3.8", + "futures 0.3.9", "libp2p-core", ] @@ -2964,7 +2942,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e09bab25af01326b4ed9486d31325911437448edda30bc57681502542d49f20" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "libp2p-core", "log", ] @@ -2977,14 +2955,14 @@ checksum = "6fd8cdd5ef1dd0b7346975477216d752de976b92e43051bc8bd808c372ea6cec" dependencies = [ "cuckoofilter", "fnv", - "futures 0.3.8", + "futures 0.3.9", "libp2p-core", "libp2p-swarm", "log", "prost", "prost-build", "rand 0.7.3", - "smallvec 1.5.0", + "smallvec 1.6.0", ] [[package]] @@ -2997,7 +2975,7 @@ dependencies = [ "byteorder", "bytes 0.5.6", "fnv", - "futures 0.3.8", + "futures 0.3.9", "futures_codec", "hex_fmt", "libp2p-core", @@ -3008,7 +2986,7 @@ dependencies = [ "prost-build", "rand 0.7.3", "sha2 0.9.2", - "smallvec 1.5.0", + "smallvec 1.6.0", "unsigned-varint", "wasm-timer", ] @@ -3019,13 +2997,13 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43bc51a9bc3780288c526615ba0f5f8216820ea6dcc02b89e8daee526c5fccb" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "libp2p-core", "libp2p-swarm", "log", "prost", "prost-build", - "smallvec 1.5.0", + "smallvec 1.6.0", "wasm-timer", ] @@ -3039,7 +3017,7 @@ dependencies = [ "bytes 0.5.6", "either", "fnv", - "futures 0.3.8", + "futures 0.3.9", "futures_codec", "libp2p-core", "libp2p-swarm", @@ -3048,7 +3026,7 @@ dependencies = [ "prost-build", "rand 0.7.3", "sha2 0.9.2", - "smallvec 1.5.0", + "smallvec 1.6.0", "uint 0.8.5", "unsigned-varint", "void", @@ -3064,14 +3042,14 @@ dependencies = [ "async-io", "data-encoding", "dns-parser", - "futures 0.3.8", + "futures 0.3.9", "if-watch", "lazy_static", "libp2p-core", "libp2p-swarm", "log", "rand 0.7.3", - "smallvec 1.5.0", + "smallvec 1.6.0", "socket2", "void", ] @@ -3083,14 +3061,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce3200fbe6608e623bd9efa459cc8bafa0e4efbb0a2dfcdd0e1387ff4181264b" dependencies = [ "bytes 0.5.6", - "futures 0.3.8", + "futures 0.3.9", "futures_codec", "libp2p-core", "log", "nohash-hasher", "parking_lot 0.11.1", "rand 0.7.3", - "smallvec 1.5.0", + "smallvec 1.6.0", "unsigned-varint", ] @@ -3101,8 +3079,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0580e0d18019d254c9c349c03ff7b22e564b6f2ada70c045fc39738e144f2139" dependencies = [ "bytes 0.5.6", - "curve25519-dalek 3.0.0", - "futures 0.3.8", + "curve25519-dalek 3.0.2", + "futures 0.3.9", "lazy_static", "libp2p-core", "log", @@ -3122,7 +3100,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50b2ec86a18cbf09d7df440e7786a2409640c774e476e9a3b4d031382c3d7588" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "libp2p-core", "libp2p-swarm", "log", @@ -3138,7 +3116,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a7b1bdcbe46a3a2159c231601ed29645282653c0a96ce3a2ad8352c9fbe6800" dependencies = [ "bytes 0.5.6", - "futures 0.3.8", + "futures 0.3.9", "futures_codec", "libp2p-core", "log", @@ -3154,9 +3132,9 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce3374f3b28162db9d3442c9347c4f14cb01e8290052615c7d341d40eae0599" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "log", - "pin-project 1.0.2", + "pin-project 1.0.3", "rand 0.7.3", "salsa20", "sha3", @@ -3170,14 +3148,14 @@ checksum = "620e2950decbf77554b5aed3824f7d0e2c04923f28c70f9bff1a402c47ef6b1e" dependencies = [ "async-trait", "bytes 0.5.6", - "futures 0.3.8", + "futures 0.3.9", "libp2p-core", "libp2p-swarm", "log", "lru", "minicbor", "rand 0.7.3", - "smallvec 1.5.0", + "smallvec 1.6.0", "unsigned-varint", "wasm-timer", ] @@ -3189,11 +3167,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf5894ee1ee63a38aa58d58a16e3dcf7ede6b59ea7b22302c00c1a41d7aec41" dependencies = [ "either", - "futures 0.3.8", + "futures 0.3.9", "libp2p-core", "log", "rand 0.7.3", - "smallvec 1.5.0", + "smallvec 1.6.0", "void", "wasm-timer", ] @@ -3205,7 +3183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d2113a7dab2b502c55fe290910cd7399a2aa04fe70a2f5a415a87a1db600c0e" dependencies = [ "async-std", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "if-addrs", "ipnet", @@ -3221,7 +3199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af05fe92c2a3aa320bc82a308ddb7b33bef3b060154c5a4b9fb0b01f15385fc0" dependencies = [ "async-std", - "futures 0.3.8", + "futures 0.3.9", "libp2p-core", "log", ] @@ -3232,7 +3210,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37cd44ea05a4523f40183f60ab6e6a80e400a5ddfc98b0df1c55edeb85576cd9" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "js-sys", "libp2p-core", "parity-send-wrapper", @@ -3248,7 +3226,7 @@ checksum = "270c80528e21089ea25b41dd1ab8fd834bdf093ebee422fed3b68699a857a083" dependencies = [ "async-tls", "either", - "futures 0.3.8", + "futures 0.3.9", "libp2p-core", "log", "quicksink", @@ -3266,7 +3244,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36799de9092c35782f080032eddbc8de870f94a0def87cf9f8883efccd5cacf0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "libp2p-core", "parking_lot 0.11.1", "thiserror", @@ -3297,7 +3275,7 @@ dependencies = [ "hmac-drbg", "rand 0.7.3", "sha2 0.8.2", - "subtle 2.3.0", + "subtle 2.4.0", "typenum", ] @@ -3382,33 +3360,20 @@ dependencies = [ "cfg-if 0.1.10", ] -[[package]] -name = "loom" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed" -dependencies = [ - "cfg-if 0.1.10", - "generator", - "scoped-tls", - "serde", - "serde_json", -] - [[package]] name = "lru" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be716eb6878ca2263eb5d00a781aa13264a794f519fe6af4fbb2668b2d5441c0" +checksum = "3aae342b73d57ad0b8b364bd12584819f2c1fe9114285dfcf8b0722607671635" dependencies = [ "hashbrown", ] [[package]] name = "lru_time_cache" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebac060fafad3adedd0c66a80741a92ff4bc8e94a273df2ba3770ab206f2e29a" +checksum = "2cc2beb26938dfd9988fc368548b70bcdfaf955f55aa788e1682198de794a451" [[package]] name = "mach" @@ -3442,9 +3407,9 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "matrixmultiply" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4f7ec66360130972f34830bfad9ef05c6610a43938a467bcc9ab9369ab3478f" +checksum = "916806ba0031cd542105d916a97c8572e1fa6dd79c9c51e7eb43a09ec2dd84c1" dependencies = [ "rawpointer", ] @@ -3480,6 +3445,15 @@ dependencies = [ "autocfg 1.0.1", ] +[[package]] +name = "memoffset" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +dependencies = [ + "autocfg 1.0.1", +] + [[package]] name = "memory-db" version = "0.25.0" @@ -3541,9 +3515,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.22" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" dependencies = [ "cfg-if 0.1.10", "fuchsia-zircon", @@ -3552,7 +3526,7 @@ dependencies = [ "kernel32-sys", "libc", "log", - "miow 0.2.1", + "miow 0.2.2", "net2", "slab", "winapi 0.2.8", @@ -3595,9 +3569,9 @@ dependencies = [ [[package]] name = "miow" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" dependencies = [ "kernel32-sys", "net2", @@ -3623,9 +3597,9 @@ checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" [[package]] name = "multihash" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb63389ee5fcd4df3f8727600f4a0c3df53c541f0ed4e8b50a9ae51a80fc1efe" +checksum = "4dac63698b887d2d929306ea48b63760431ff8a24fac40ddb22f9c7f49fb7cab" dependencies = [ "digest 0.9.0", "generic-array 0.14.4", @@ -3636,9 +3610,9 @@ dependencies = [ [[package]] name = "multihash-derive" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f5653449cd45d502a53480ee08d7a599e8f4893d2bacb33c63d65bc20af6c1a" +checksum = "85ee3c48cb9d9b275ad967a0e96715badc13c6029adb92f34fa17b9ff28fd81f" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -3661,10 +3635,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dda822043bba2d6da31c4e14041f9794f8fb130a5959289038d0b809d8888614" dependencies = [ "bytes 0.5.6", - "futures 0.3.8", + "futures 0.3.9", "log", - "pin-project 1.0.2", - "smallvec 1.5.0", + "pin-project 1.0.3", + "smallvec 1.6.0", "unsigned-varint", ] @@ -3707,9 +3681,9 @@ dependencies = [ [[package]] name = "net2" -version = "0.2.35" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" dependencies = [ "cfg-if 0.1.10", "libc", @@ -3735,7 +3709,7 @@ version = "0.8.0" dependencies = [ "derive_more", "fs_extra", - "futures 0.3.8", + "futures 0.3.9", "hash-db", "hex", "kvdb", @@ -3771,7 +3745,7 @@ dependencies = [ name = "node-browser-testing" version = "2.0.0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "jsonrpc-core", "libp2p", @@ -3792,7 +3766,7 @@ dependencies = [ "frame-benchmarking-cli", "frame-support", "frame-system", - "futures 0.3.8", + "futures 0.3.9", "hex-literal", "log", "nix", @@ -3973,7 +3947,6 @@ name = "node-runtime" version = "2.0.0" dependencies = [ "frame-benchmarking", - "frame-election-providers", "frame-executive", "frame-support", "frame-system", @@ -4018,6 +3991,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", + "pallet-two-phase-election-provider", "pallet-utility", "pallet-vesting", "parity-scale-codec", @@ -4122,7 +4096,7 @@ dependencies = [ "frame-support", "frame-system", "fs_extra", - "futures 0.3.8", + "futures 0.3.9", "log", "node-executor", "node-primitives", @@ -4277,9 +4251,9 @@ dependencies = [ [[package]] name = "oorandom" -version = "11.1.2" +version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "opaque-debug" @@ -4500,7 +4474,7 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "parity-wasm 0.41.0", - "paste 1.0.3", + "paste 1.0.4", "pretty_assertions", "pwasm-utils 0.16.0", "rand 0.7.3", @@ -5021,7 +4995,6 @@ name = "pallet-staking" version = "2.0.0" dependencies = [ "frame-benchmarking", - "frame-election-providers", "frame-support", "frame-system", "hex", @@ -5153,7 +5126,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", "serde", - "smallvec 1.5.0", + "smallvec 1.6.0", "sp-core", "sp-io", "sp-runtime", @@ -5209,6 +5182,32 @@ dependencies = [ "sp-storage", ] +[[package]] +name = "pallet-two-phase-election-provider" +version = "2.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "hex-literal", + "pallet-balances", + "parity-scale-codec", + "parking_lot 0.11.1", + "paste 1.0.4", + "rand 0.7.3", + "serde", + "sp-arithmetic", + "sp-core", + "sp-election-providers", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-std", + "sp-tracing", + "static_assertions", + "substrate-test-utils", +] + [[package]] name = "pallet-utility" version = "2.0.0" @@ -5338,7 +5337,7 @@ dependencies = [ "parity-util-mem-derive", "parking_lot 0.11.1", "primitive-types", - "smallvec 1.5.0", + "smallvec 1.6.0", "winapi 0.3.9", ] @@ -5421,7 +5420,7 @@ checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ "instant", "lock_api 0.4.2", - "parking_lot_core 0.8.0", + "parking_lot_core 0.8.2", ] [[package]] @@ -5431,7 +5430,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" dependencies = [ "cfg-if 0.1.10", - "cloudabi 0.0.3", + "cloudabi", "libc", "redox_syscall", "rustc_version", @@ -5446,25 +5445,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" dependencies = [ "cfg-if 0.1.10", - "cloudabi 0.0.3", + "cloudabi", "libc", "redox_syscall", - "smallvec 1.5.0", + "smallvec 1.6.0", "winapi 0.3.9", ] [[package]] name = "parking_lot_core" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" +checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" dependencies = [ - "cfg-if 0.1.10", - "cloudabi 0.1.0", + "cfg-if 1.0.0", "instant", "libc", "redox_syscall", - "smallvec 1.5.0", + "smallvec 1.6.0", "winapi 0.3.9", ] @@ -5480,9 +5478,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7151b083b0664ed58ed669fcdd92f01c3d2fdbf10af4931a301474950b52bfa9" +checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" [[package]] name = "paste-impl" @@ -5600,11 +5598,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccc2237c2c489783abd8c4c80e5450fc0e98644555b1364da68cc29aa151ca7" +checksum = "5a83804639aad6ba65345661744708855f9fbcb71176ea8d28d05aeb11d975e7" dependencies = [ - "pin-project-internal 1.0.2", + "pin-project-internal 1.0.3", ] [[package]] @@ -5620,9 +5618,9 @@ dependencies = [ [[package]] name = "pin-project-internal" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f" +checksum = "b7bcc46b8f73443d15bc1c5fecbb315718491fa9187fa483f0e359323cde8b3a" dependencies = [ "proc-macro2", "quote", @@ -5637,9 +5635,9 @@ checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" [[package]] name = "pin-project-lite" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c" +checksum = "e36743d754ccdf9954c2e352ce2d4b106e024c814f6499c2dadff80da9a442d8" [[package]] name = "pin-utils" @@ -5686,20 +5684,22 @@ dependencies = [ [[package]] name = "poly1305" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ce46de8e53ee414ca4d02bfefac75d8c12fba948b76622a40b4be34dfce980" +checksum = "4b7456bc1ad2d4cf82b3a016be4c2ac48daf11bf990c1603ebd447fe6f30fca8" dependencies = [ + "cpuid-bool 0.2.0", "universal-hash", ] [[package]] name = "polyval" -version = "0.4.1" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5884790f1ce3553ad55fec37b5aaac5882e0e845a2612df744d6c85c9bf046c" +checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" dependencies = [ - "cfg-if 0.1.10", + "cpuid-bool 0.2.0", + "opaque-debug 0.3.0", "universal-hash", ] @@ -5711,9 +5711,9 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "predicates" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bfead12e90dccead362d62bb2c90a5f6fc4584963645bc7f71a735e0b0735a" +checksum = "73dd9b7b200044694dfede9edf907c1ca19630908443e9447e624993700c6932" dependencies = [ "difference", "predicates-core", @@ -5721,15 +5721,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178" +checksum = "fb3dbeaaf793584e29c58c7e3a82bbb3c7c06b63cea68d13b0e3cddc124104dc" [[package]] name = "predicates-tree" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124" +checksum = "aee95d988ee893cb35c06b148c80ed2cd52c8eea927f50ba7a0be1a786aeab73" dependencies = [ "predicates-core", "treeline", @@ -5937,9 +5937,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ "proc-macro2", ] @@ -5998,7 +5998,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", @@ -6068,7 +6068,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", ] [[package]] @@ -6133,7 +6133,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" dependencies = [ - "cloudabi 0.0.3", + "cloudabi", "fuchsia-cprng", "libc", "rand_core 0.4.2", @@ -6171,9 +6171,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "7.0.3" +version = "7.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a349ca83373cfa5d6dbb66fd76e58b2cca08da71a5f6400de0a0a6a9bceeaf" +checksum = "beb71f708fe39b2c5e98076204c3cc094ee5a4c12c4cdb119a2b72dc34164f41" dependencies = [ "bitflags", "cc", @@ -6206,7 +6206,7 @@ checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ "crossbeam-channel", "crossbeam-deque 0.8.0", - "crossbeam-utils 0.8.0", + "crossbeam-utils 0.8.1", "lazy_static", "num_cpus", ] @@ -6232,25 +6232,25 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", "redox_syscall", "rust-argon2", ] [[package]] name = "ref-cast" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17626b2f4bcf35b84bf379072a66e28cfe5c3c6ae58b38e4914bb8891dabece" +checksum = "300f2a835d808734ee295d45007adacb9ebb29dd3ae2424acfa17930cae541da" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c523ccaed8ac4b0288948849a350b37d3035827413c458b6a40ddb614bb4f72" +checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2" dependencies = [ "proc-macro2", "quote", @@ -6265,7 +6265,7 @@ checksum = "b9ba8aaf5fe7cf307c6dbdaeed85478961d29e25e3bee5169e11b92fa9f027a8" dependencies = [ "log", "rustc-hash", - "smallvec 1.5.0", + "smallvec 1.6.0", ] [[package]] @@ -6319,15 +6319,15 @@ dependencies = [ [[package]] name = "retain_mut" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e005d658ad26eacc2b6c506dfde519f4e277e328d0eb3379ca61647d70a8f531" +checksum = "53552c6c49e1e13f1a203ef0080ab3bbef0beb570a528993e83df057a9d9bba1" [[package]] name = "ring" -version = "0.16.16" +version = "0.16.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b72b84d47e8ec5a4f2872e8262b8f8256c5be1c938a7d6d3a867a3ba8f722f74" +checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226" dependencies = [ "cc", "libc", @@ -6360,14 +6360,14 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" dependencies = [ - "base64 0.12.3", + "base64 0.13.0", "blake2b_simd", "constant_time_eq", - "crossbeam-utils 0.7.2", + "crossbeam-utils 0.8.1", ] [[package]] @@ -6447,7 +6447,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "pin-project 0.4.27", "static_assertions", ] @@ -6492,7 +6492,7 @@ dependencies = [ "async-trait", "derive_more", "either", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "libp2p", "log", @@ -6520,7 +6520,7 @@ dependencies = [ name = "sc-basic-authorship" version = "0.8.0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -6597,7 +6597,7 @@ dependencies = [ "atty", "chrono", "fdlimit", - "futures 0.3.8", + "futures 0.3.9", "hex", "libp2p", "log", @@ -6627,7 +6627,7 @@ dependencies = [ "tempfile", "thiserror", "tiny-bip39", - "tokio 0.2.23", + "tokio 0.2.24", "tracing", "tracing-log", "tracing-subscriber", @@ -6649,7 +6649,7 @@ version = "2.0.0" dependencies = [ "derive_more", "fnv", - "futures 0.3.8", + "futures 0.3.9", "hash-db", "kvdb", "kvdb-memorydb", @@ -6729,7 +6729,7 @@ name = "sc-consensus-aura" version = "0.8.0" dependencies = [ "derive_more", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "getrandom 0.2.1", "log", @@ -6770,7 +6770,7 @@ version = "0.8.0" dependencies = [ "derive_more", "fork-tree", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "log", "merlin", @@ -6823,7 +6823,7 @@ name = "sc-consensus-babe-rpc" version = "0.8.0" dependencies = [ "derive_more", - "futures 0.3.8", + "futures 0.3.9", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -6865,7 +6865,7 @@ version = "0.8.0" dependencies = [ "assert_matches", "derive_more", - "futures 0.3.8", + "futures 0.3.9", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -6893,7 +6893,7 @@ dependencies = [ "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", "tempfile", - "tokio 0.2.23", + "tokio 0.2.24", ] [[package]] @@ -6901,7 +6901,7 @@ name = "sc-consensus-pow" version = "0.8.0" dependencies = [ "derive_more", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -6923,7 +6923,7 @@ dependencies = [ name = "sc-consensus-slots" version = "0.8.0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -7053,7 +7053,7 @@ dependencies = [ "derive_more", "finality-grandpa", "fork-tree", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -7087,7 +7087,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", - "tokio 0.2.23", + "tokio 0.2.24", ] [[package]] @@ -7096,7 +7096,7 @@ version = "0.8.0" dependencies = [ "derive_more", "finality-grandpa", - "futures 0.3.8", + "futures 0.3.9", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -7125,7 +7125,7 @@ name = "sc-informant" version = "0.8.0" dependencies = [ "ansi_term 0.12.1", - "futures 0.3.8", + "futures 0.3.9", "log", "parity-util-mem", "sc-client-api", @@ -7143,7 +7143,7 @@ version = "2.0.0" dependencies = [ "async-trait", "derive_more", - "futures 0.3.8", + "futures 0.3.9", "futures-util", "hex", "merlin", @@ -7153,7 +7153,7 @@ dependencies = [ "sp-application-crypto", "sp-core", "sp-keystore", - "subtle 2.3.0", + "subtle 2.4.0", "tempfile", ] @@ -7190,7 +7190,7 @@ dependencies = [ "erased-serde", "fnv", "fork-tree", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "futures_codec", "hex", @@ -7214,7 +7214,7 @@ dependencies = [ "serde_json", "slog", "slog_derive", - "smallvec 1.5.0", + "smallvec 1.6.0", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -7240,7 +7240,7 @@ name = "sc-network-gossip" version = "0.8.0" dependencies = [ "async-std", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "libp2p", "log", @@ -7258,7 +7258,7 @@ name = "sc-network-test" version = "0.8.0" dependencies = [ "async-std", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "libp2p", "log", @@ -7286,7 +7286,7 @@ version = "2.0.0" dependencies = [ "bytes 0.5.6", "fnv", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "hyper 0.13.9", "hyper-rustls", @@ -7310,14 +7310,14 @@ dependencies = [ "sp-utils", "substrate-test-runtime-client", "threadpool", - "tokio 0.2.23", + "tokio 0.2.24", ] [[package]] name = "sc-peerset" version = "2.0.0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "libp2p", "log", "rand 0.7.3", @@ -7340,7 +7340,7 @@ version = "2.0.0" dependencies = [ "assert_matches", "futures 0.1.30", - "futures 0.3.8", + "futures 0.3.9", "hash-db", "jsonrpc-core", "jsonrpc-pubsub", @@ -7381,7 +7381,7 @@ name = "sc-rpc-api" version = "0.8.0" dependencies = [ "derive_more", - "futures 0.3.8", + "futures 0.3.9", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -7438,7 +7438,7 @@ dependencies = [ "directories 3.0.1", "exit-future", "futures 0.1.30", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "hash-db", "jsonrpc-core", @@ -7494,7 +7494,7 @@ dependencies = [ "substrate-test-runtime-client", "tempfile", "thiserror", - "tokio 0.2.23", + "tokio 0.2.24", "tracing", "tracing-futures", "wasm-timer", @@ -7506,7 +7506,7 @@ version = "2.0.0" dependencies = [ "fdlimit", "futures 0.1.30", - "futures 0.3.8", + "futures 0.3.9", "hex-literal", "log", "parity-scale-codec", @@ -7573,7 +7573,7 @@ dependencies = [ name = "sc-telemetry" version = "2.0.0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "libp2p", "log", @@ -7619,7 +7619,7 @@ dependencies = [ "assert_matches", "criterion", "derive_more", - "futures 0.3.8", + "futures 0.3.9", "linked-hash-map", "log", "parity-scale-codec", @@ -7642,7 +7642,7 @@ name = "sc-transaction-pool" version = "2.0.0" dependencies = [ "assert_matches", - "futures 0.3.8", + "futures 0.3.9", "futures-diagnose", "hex", "intervalier", @@ -7687,14 +7687,14 @@ checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" dependencies = [ "arrayref", "arrayvec 0.5.2", - "curve25519-dalek 2.1.0", - "getrandom 0.1.15", + "curve25519-dalek 2.1.2", + "getrandom 0.1.16", "merlin", "rand 0.7.3", "rand_core 0.5.1", "serde", "sha2 0.8.2", - "subtle 2.3.0", + "subtle 2.4.0", "zeroize", ] @@ -7796,7 +7796,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver-parser 0.10.1", + "semver-parser 0.10.0", "serde", ] @@ -7808,11 +7808,12 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "semver-parser" -version = "0.10.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428" +checksum = "0e012c6c5380fb91897ba7b9261a0f565e624e869d42fe1a1d03fa0d68a083d5" dependencies = [ "pest", + "pest_derive", ] [[package]] @@ -7829,9 +7830,9 @@ checksum = "930c0acf610d3fdb5e2ab6213019aaa04e227ebe9547b0649ba599b16d788bd7" [[package]] name = "serde" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" dependencies = [ "serde_derive", ] @@ -7848,9 +7849,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", @@ -7859,9 +7860,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.59" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" +checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" dependencies = [ "itoa", "ryu", @@ -7888,7 +7889,7 @@ checksum = "ce3cdf1b5e620a498ee6f2a171885ac7e22f0e12089ec4b3d22b84921792507c" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpuid-bool", + "cpuid-bool 0.1.2", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -7913,7 +7914,7 @@ checksum = "6e7aab86fe2149bad8c507606bdb3f4ef5e7b2380eb92350f56122cca72a42a8" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpuid-bool", + "cpuid-bool 0.1.2", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -7932,12 +7933,11 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4921be914e16899a80adefb821f8ddb7974e3f1250223575a44ed994882127" +checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3" dependencies = [ "lazy_static", - "loom", ] [[package]] @@ -7946,20 +7946,30 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +[[package]] +name = "signal-hook" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729" +dependencies = [ + "libc", + "signal-hook-registry", +] + [[package]] name = "signal-hook-registry" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" dependencies = [ "libc", ] [[package]] name = "signature" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f060a7d147e33490ec10da418795238fd7545bba241504d6b31a409f2e6210" +checksum = "0f0242b8e50dd9accdd56170e94ca1ebd223b098eb9c83539a6e367d0f36ae68" [[package]] name = "simba" @@ -7981,9 +7991,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "slog" -version = "2.5.2" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cc9c640a4adbfbcc11ffb95efe5aa7af7309e002adab54b185507dbf2377b99" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" dependencies = [ "erased-serde", ] @@ -8034,9 +8044,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85" +checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0" [[package]] name = "snow" @@ -8052,19 +8062,18 @@ dependencies = [ "ring", "rustc_version", "sha2 0.9.2", - "subtle 2.3.0", + "subtle 2.4.0", "x25519-dalek", ] [[package]] name = "socket2" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c29947abdee2a218277abeca306f25789c938e500ea5a9d4b12a5a504466902" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", "winapi 0.3.9", ] @@ -8077,7 +8086,7 @@ dependencies = [ "base64 0.12.3", "bytes 0.5.6", "flate2", - "futures 0.3.8", + "futures 0.3.9", "httparse", "log", "rand 0.7.3", @@ -8227,7 +8236,7 @@ dependencies = [ name = "sp-blockchain" version = "2.0.0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "log", "lru", "parity-scale-codec", @@ -8252,7 +8261,7 @@ dependencies = [ name = "sp-consensus" version = "0.8.0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "libp2p", "log", @@ -8346,7 +8355,7 @@ dependencies = [ "criterion", "dyn-clonable", "ed25519-dalek", - "futures 0.3.8", + "futures 0.3.9", "hash-db", "hash256-std-hasher", "hex", @@ -8409,6 +8418,7 @@ dependencies = [ "parity-scale-codec", "sp-arithmetic", "sp-npos-elections", + "sp-runtime", "sp-std", ] @@ -8453,7 +8463,7 @@ dependencies = [ name = "sp-io" version = "2.0.0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "hash-db", "libsecp256k1", "log", @@ -8488,7 +8498,7 @@ version = "0.8.0" dependencies = [ "async-trait", "derive_more", - "futures 0.3.8", + "futures 0.3.9", "merlin", "parity-scale-codec", "parking_lot 0.11.1", @@ -8710,7 +8720,7 @@ dependencies = [ "parking_lot 0.11.1", "pretty_assertions", "rand 0.7.3", - "smallvec 1.5.0", + "smallvec 1.6.0", "sp-core", "sp-externalities", "sp-panic-handler", @@ -8793,7 +8803,7 @@ name = "sp-transaction-pool" version = "2.0.0" dependencies = [ "derive_more", - "futures 0.3.8", + "futures 0.3.9", "log", "parity-scale-codec", "serde", @@ -8825,7 +8835,7 @@ dependencies = [ name = "sp-utils" version = "2.0.0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "futures-core", "futures-timer 3.0.2", "lazy_static", @@ -8907,9 +8917,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.20" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126d630294ec449fae0b16f964e35bf3c74f940da9dca17ee9b905f7b3112eb8" +checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" dependencies = [ "clap", "lazy_static", @@ -8918,9 +8928,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e51c492f9e23a220534971ff5afc14037289de430e3c83f9daf6a1b6ae91e8" +checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" dependencies = [ "heck", "proc-macro-error", @@ -8979,7 +8989,7 @@ dependencies = [ "console_error_panic_hook", "console_log", "futures 0.1.30", - "futures 0.3.8", + "futures 0.3.9", "futures-timer 3.0.2", "getrandom 0.2.1", "js-sys", @@ -9020,14 +9030,14 @@ version = "2.0.0" dependencies = [ "frame-support", "frame-system", - "futures 0.3.8", + "futures 0.3.9", "jsonrpc-client-transports", "jsonrpc-core", "parity-scale-codec", "sc-rpc-api", "serde", "sp-storage", - "tokio 0.2.23", + "tokio 0.2.24", ] [[package]] @@ -9035,7 +9045,7 @@ name = "substrate-frame-rpc-system" version = "2.0.0" dependencies = [ "frame-system-rpc-runtime-api", - "futures 0.3.8", + "futures 0.3.9", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -9065,7 +9075,7 @@ dependencies = [ "hyper 0.13.9", "log", "prometheus", - "tokio 0.2.23", + "tokio 0.2.24", ] [[package]] @@ -9073,7 +9083,7 @@ name = "substrate-test-client" version = "2.0.0" dependencies = [ "futures 0.1.30", - "futures 0.3.8", + "futures 0.3.9", "hash-db", "hex", "parity-scale-codec", @@ -9142,7 +9152,7 @@ dependencies = [ name = "substrate-test-runtime-client" version = "2.0.0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "parity-scale-codec", "sc-block-builder", "sc-client-api", @@ -9163,7 +9173,7 @@ name = "substrate-test-runtime-transaction-pool" version = "2.0.0" dependencies = [ "derive_more", - "futures 0.3.8", + "futures 0.3.9", "parity-scale-codec", "parking_lot 0.11.1", "sc-transaction-graph", @@ -9177,10 +9187,10 @@ dependencies = [ name = "substrate-test-utils" version = "2.0.0" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "sc-service", "substrate-test-utils-derive", - "tokio 0.2.23", + "tokio 0.2.24", "trybuild", ] @@ -9199,7 +9209,7 @@ version = "0.1.0" dependencies = [ "sc-service", "substrate-test-utils", - "tokio 0.2.23", + "tokio 0.2.24", ] [[package]] @@ -9224,9 +9234,9 @@ checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "subtle" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd" +checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" @@ -9279,9 +9289,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf11676eb135389f21fcda654382c4859bbfc1d2f36e4425a2f829bb41b1e20e" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ "winapi-util", ] @@ -9297,18 +9307,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e" +checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56" +checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" dependencies = [ "proc-macro2", "quote", @@ -9317,9 +9327,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" dependencies = [ "lazy_static", ] @@ -9335,12 +9345,11 @@ dependencies = [ [[package]] name = "time" -version = "0.1.44" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ "libc", - "wasi 0.10.0+wasi-snapshot-preview1", "winapi 0.3.9", ] @@ -9373,9 +9382,9 @@ dependencies = [ [[package]] name = "tinytemplate" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f" +checksum = "a2ada8616fad06a2d0c455adc530de4ef57605a8120cc65da9653e0e9623ca74" dependencies = [ "serde", "serde_json", @@ -9383,9 +9392,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b78a366903f506d2ad52ca8dc552102ffdd3e937ba8a227f024dc1d1eae28575" +checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" dependencies = [ "tinyvec_macros", ] @@ -9422,9 +9431,9 @@ dependencies = [ [[package]] name = "tokio" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6d7ad61edd59bfcc7e80dababf0f4aed2e6d5e0ba1659356ae889752dfc12ff" +checksum = "099837d3464c16a808060bb3f02263b412f6fafcb5d01c533d309985fbeebe48" dependencies = [ "bytes 0.5.6", "fnv", @@ -9558,7 +9567,7 @@ checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a" dependencies = [ "futures-core", "rustls 0.18.1", - "tokio 0.2.23", + "tokio 0.2.24", "webpki", ] @@ -9668,14 +9677,14 @@ dependencies = [ "futures-sink", "log", "pin-project-lite 0.1.11", - "tokio 0.2.23", + "tokio 0.2.24", ] [[package]] name = "toml" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ "serde", ] @@ -9694,7 +9703,7 @@ checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" dependencies = [ "cfg-if 1.0.0", "log", - "pin-project-lite 0.2.0", + "pin-project-lite 0.2.1", "tracing-attributes", "tracing-core", ] @@ -9764,7 +9773,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec 1.5.0", + "smallvec 1.6.0", "thread_local", "tracing", "tracing-core", @@ -9804,7 +9813,7 @@ dependencies = [ "hashbrown", "log", "rustc-hex", - "smallvec 1.5.0", + "smallvec 1.6.0", ] [[package]] @@ -9923,9 +9932,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8716a166f290ff49dabc18b44aa407cb7c6dbe1aa0971b44b8a24b0ca35aae" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" [[package]] name = "unicode-width" @@ -9946,7 +9955,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" dependencies = [ "generic-array 0.14.4", - "subtle 2.3.0", + "subtle 2.4.0", ] [[package]] @@ -9992,9 +10001,9 @@ dependencies = [ [[package]] name = "vcpkg" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" +checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" [[package]] name = "vec-arena" @@ -10075,9 +10084,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.10.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" [[package]] name = "wasm-bindgen" @@ -10108,11 +10117,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" +checksum = "1fe9756085a84584ee9457a002b7cdfe0bfff169f45d2591d8be1345a6780e35" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -10149,9 +10158,9 @@ checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" [[package]] name = "wasm-bindgen-test" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34d1cdc8b98a557f24733d50a1199c4b0635e465eecba9c45b214544da197f64" +checksum = "0355fa0c1f9b792a09b6dcb6a8be24d51e71e6d74972f9eb4a44c4c004d24a25" dependencies = [ "console_error_panic_hook", "js-sys", @@ -10163,9 +10172,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8fb9c67be7439ee8ab1b7db502a49c05e51e2835b66796c705134d9b8e1a585" +checksum = "27e07b46b98024c2ba2f9e83a10c2ef0515f057f2da299c1762a2017de80438b" dependencies = [ "proc-macro2", "quote", @@ -10188,7 +10197,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "js-sys", "parking_lot 0.11.1", "pin-utils", @@ -10247,7 +10256,7 @@ dependencies = [ "log", "region", "rustc-demangle", - "smallvec 1.5.0", + "smallvec 1.6.0", "target-lexicon", "wasmparser 0.59.0", "wasmtime-environ", @@ -10380,7 +10389,7 @@ dependencies = [ "lazy_static", "libc", "log", - "memoffset", + "memoffset 0.5.6", "more-asserts", "region", "thiserror", @@ -10390,18 +10399,18 @@ dependencies = [ [[package]] name = "wast" -version = "27.0.0" +version = "30.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c3ef5f6a72dffa44c24d5811123f704e18a1dbc83637d347b1852b41d3835c" +checksum = "9b79907b22f740634810e882d8d1d9d0f9563095a8ab94e786e370242bff5cd2" dependencies = [ "leb128", ] [[package]] name = "wat" -version = "1.0.28" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835cf59c907f67e2bbc20f50157e08f35006fe2a8444d8ec9f5683e22f937045" +checksum = "a8279a02835bf12e61ed2b3c3cbc6ecf9918762fd97e036917c11a09ec20ca44" dependencies = [ "wast", ] @@ -10418,9 +10427,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.21.3" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" dependencies = [ "ring", "untrusted", @@ -10512,7 +10521,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc614d95359fd7afc321b66d2107ede58b246b844cf5d8a0adcca413e439f088" dependencies = [ - "curve25519-dalek 3.0.0", + "curve25519-dalek 3.0.2", "rand_core 0.5.1", "zeroize", ] @@ -10523,7 +10532,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aeb8c4043cac71c3c299dff107171c220d179492350ea198e109a414981b83c" dependencies = [ - "futures 0.3.8", + "futures 0.3.9", "log", "nohash-hasher", "parking_lot 0.11.1", @@ -10554,18 +10563,18 @@ dependencies = [ [[package]] name = "zstd" -version = "0.5.3+zstd.1.4.5" +version = "0.5.4+zstd.1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8" +checksum = "69996ebdb1ba8b1517f61387a883857818a66c8a295f487b1ffd8fd9d2c82910" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "2.0.5+zstd.1.4.5" +version = "2.0.6+zstd.1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055" +checksum = "98aa931fb69ecee256d44589d19754e61851ae4769bf963b385119b1cc37a49e" dependencies = [ "libc", "zstd-sys", @@ -10573,9 +10582,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.4.17+zstd.1.4.5" +version = "1.4.18+zstd.1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b" +checksum = "a1e6e8778706838f43f771d80d37787cb2fe06dafe89dd3aebaf6721b9eaec81" dependencies = [ "cc", "glob", diff --git a/Cargo.toml b/Cargo.toml index 84f5d384e7e1e..72f2b550bb788 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,7 +100,7 @@ members = [ "frame/staking", "frame/staking/fuzzer", "frame/staking/reward-curve", - "frame/election-providers", + "frame/two-phase-election-provider", "frame/sudo", "frame/support", "frame/support/procedural", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 3d39997b809c1..f550fa735b0c2 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -42,7 +42,6 @@ frame-executive = { version = "2.0.0", default-features = false, path = "../../. frame-benchmarking = { version = "2.0.0", default-features = false, path = "../../../frame/benchmarking", optional = true } frame-support = { version = "2.0.0", default-features = false, path = "../../../frame/support" } frame-system = { version = "2.0.0", default-features = false, path = "../../../frame/system" } -frame-election-providers = { version = "2.0.0", default-features = false, path = "../../../frame/election-providers/" } frame-system-benchmarking = { version = "2.0.0", default-features = false, path = "../../../frame/system/benchmarking", optional = true } frame-system-rpc-runtime-api = { version = "2.0.0", default-features = false, path = "../../../frame/system/rpc/runtime-api/" } pallet-assets = { version = "2.0.0", default-features = false, path = "../../../frame/assets" } @@ -73,6 +72,7 @@ pallet-recovery = { version = "2.0.0", default-features = false, path = "../../. pallet-session = { version = "2.0.0", features = ["historical"], path = "../../../frame/session", default-features = false } pallet-session-benchmarking = { version = "2.0.0", path = "../../../frame/session/benchmarking", default-features = false, optional = true } pallet-staking = { version = "2.0.0", default-features = false, path = "../../../frame/staking" } +pallet-two-phase-election-provider = { version = "2.0.0", default-features = false, path = "../../../frame/two-phase-election-provider/" } pallet-staking-reward-curve = { version = "2.0.0", default-features = false, path = "../../../frame/staking/reward-curve" } pallet-scheduler = { version = "2.0.0", default-features = false, path = "../../../frame/scheduler" } pallet-society = { version = "2.0.0", default-features = false, path = "../../../frame/society" } @@ -143,7 +143,7 @@ std = [ "frame-benchmarking/std", "frame-system-rpc-runtime-api/std", "frame-system/std", - "frame-election-providers/std", + "pallet-two-phase-election-provider/std", "pallet-timestamp/std", "pallet-tips/std", "pallet-transaction-payment-rpc-runtime-api/std", @@ -160,7 +160,7 @@ runtime-benchmarks = [ "frame-benchmarking", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "frame-election-providers/runtime-benchmarks", + "pallet-two-phase-election-provider/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-babe/runtime-benchmarks", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 4adbeee367a6e..132f7ee871ec6 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -73,7 +73,6 @@ use pallet_session::{historical as pallet_session_historical}; use sp_inherents::{InherentData, CheckInherentsResult}; use static_assertions::const_assert; use pallet_contracts::WeightInfo; -use frame_election_providers::two_phase as pallet_two_phase_election_provider; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; diff --git a/frame/election-providers/src/lib.rs b/frame/election-providers/src/lib.rs deleted file mode 100644 index 30f8d9fb3a820..0000000000000 --- a/frame/election-providers/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020 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 -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Various implementation for [`sp_election_providers::ElectionProvider`]. -//! -//! Two main election providers are implemented in this crate. -//! -//! 1. [`onchain`]: A `struct` that perform the election onchain (i.e. in the fly). This type is -//! likely to be expensive for most chains and damage the block time. Only use when you are sure -//! that the inputs are bounded and small enough. -//! 2. [`two_phase`]: An individual `pallet` that performs the election in two phases, signed and -//! unsigned. Needless to say, the pallet needs to be included in the final runtime. - -#![cfg_attr(not(feature = "std"), no_std)] - -/// The onchain module. -pub mod onchain; -/// The two-phase module. -pub mod two_phase; - -// re-export only for docs, as it help with intra-crate link resolution. -#[cfg(doc)] -pub use two_phase::*; -#[cfg(doc)] -pub use onchain::*; - -const LOG_TARGET: &'static str = "election-provider"; - -// for the helper macros -#[doc(hidden)] -pub use sp_npos_elections::VoteWeight; -#[doc(hidden)] -pub use sp_runtime::traits::UniqueSaturatedInto; -#[doc(hidden)] -pub use sp_std::convert::TryInto; diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index f1c6dddbd1531..1c6e5c9f950af 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -39,7 +39,6 @@ sp-storage = { version = "2.0.0", path = "../../primitives/storage" } sp-tracing = { version = "2.0.0", path = "../../primitives/tracing" } pallet-balances = { version = "2.0.0", path = "../balances" } pallet-timestamp = { version = "2.0.0", path = "../timestamp" } -frame-election-providers = { version = "2.0.0", path = "../election-providers" } pallet-staking-reward-curve = { version = "2.0.0", path = "../staking/reward-curve" } substrate-test-utils = { version = "2.0.0", path = "../../test-utils" } frame-benchmarking = { version = "2.0.0", path = "../benchmarking" } diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index e637e81125a28..8d22bbd8c81cb 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -36,7 +36,7 @@ use sp_runtime::{ }; use sp_staking::offence::{OffenceDetails, OnOffenceHandler}; use std::{cell::RefCell, collections::HashSet}; -use frame_election_providers::onchain; +use sp_election_providers::onchain; pub const INIT_TIMESTAMP: u64 = 30_000; pub const BLOCK_TIME: u64 = 1000; diff --git a/frame/election-providers/Cargo.toml b/frame/two-phase-election-provider/Cargo.toml similarity index 96% rename from frame/election-providers/Cargo.toml rename to frame/two-phase-election-provider/Cargo.toml index 3de94e73b2f6d..aef5d65072362 100644 --- a/frame/election-providers/Cargo.toml +++ b/frame/two-phase-election-provider/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "frame-election-providers" +name = "pallet-two-phase-election-provider" version = "2.0.0" authors = ["Parity Technologies "] edition = "2018" license = "Apache-2.0" homepage = "https://substrate.dev" repository = "https://github.com/paritytech/substrate/" -description = "FRAME election providers" +description = "PALLET two phase election providers" readme = "README.md" [package.metadata.docs.rs] diff --git a/frame/election-providers/src/two_phase/benchmarking.rs b/frame/two-phase-election-provider/src/benchmarking.rs similarity index 99% rename from frame/election-providers/src/two_phase/benchmarking.rs rename to frame/two-phase-election-provider/src/benchmarking.rs index b1b410a80acde..ce3a031a779e1 100644 --- a/frame/election-providers/src/two_phase/benchmarking.rs +++ b/frame/two-phase-election-provider/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Two phase election pallet benchmarking. use super::*; -use crate::two_phase::{Module as TwoPhase}; +use crate::Module as TwoPhase; pub use frame_benchmarking::{account, benchmarks, whitelist_account, whitelisted_caller}; use frame_support::{assert_ok, traits::OnInitialize}; @@ -311,7 +311,7 @@ benchmarks! { #[cfg(test)] mod test { use super::*; - use crate::two_phase::mock::*; + use crate::mock::*; #[test] fn test_benchmarks() { diff --git a/frame/election-providers/src/two_phase/mod.rs b/frame/two-phase-election-provider/src/lib.rs similarity index 97% rename from frame/election-providers/src/two_phase/mod.rs rename to frame/two-phase-election-provider/src/lib.rs index 3f7b8a58a4770..3d97d17f16b4d 100644 --- a/frame/election-providers/src/two_phase/mod.rs +++ b/frame/two-phase-election-provider/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,10 +36,9 @@ //! ``` //! //! Note that the unsigned phase starts [`pallet::Config::UnsignedPhase`] blocks before the -//! `next_election_prediction`, but only ends when a call to -//! [`pallet::Config::ElectionProvider::elect`] happens. +//! `next_election_prediction`, but only ends when a call to [`ElectionProvider::elect`] happens. //! -//! > Given this, it is rather important for the user of this pallet to ensure it alwasy terminates +//! > Given this, it is rather important for the user of this pallet to ensure it always terminates //! election via `elect` before requesting a new one. //! //! Each of the phases can be disabled by essentially setting their length to zero. If both phases @@ -120,7 +119,7 @@ //! //! 0. **all** of the used indices must be correct. //! 1. present *exactly* correct number of winners. -//! 2. any assignment is checked to match with [`Snapshot::voters`]. +//! 2. any assignment is checked to match with [`RoundSnapshot::voters`]. //! 3. the claimed score is valid, based on the fixed point arithmetic accuracy. //! //! ## Accuracy @@ -163,14 +162,15 @@ //! //! **Recursive Fallback**: Currently, the fallback is a separate enum. A different and fancier way //! of doing this would be to have the fallback be another -//! [`sp_election_provider::ElectionProvider`]. In this case, this pallet can even have the on-chain +//! [`sp_election_providers::ElectionProvider`]. In this case, this pallet can even have the on-chain //! election provider as fallback, or special _noop_ fallback that simply returns an error, thus //! replicating [`FallbackStrategy::Nothing`]. //! //! **Score based on size**: We should always prioritize small solutions over bigger ones, if there //! is a tie. Even more harsh should be to enforce the bound of the `reduce` algorithm. -use crate::onchain::OnChainSequentialPhragmen; +#![cfg_attr(not(feature = "std"), no_std)] + use codec::{Decode, Encode, HasCompact}; use frame_support::{ dispatch::DispatchResultWithPostInfo, @@ -179,7 +179,7 @@ use frame_support::{ weights::Weight, }; use frame_system::{ensure_none, ensure_signed, offchain::SendTransactionTypes}; -use sp_election_providers::{ElectionDataProvider, ElectionProvider}; +use sp_election_providers::{ElectionDataProvider, ElectionProvider, onchain}; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, is_score_better, CompactSolution, ElectionScore, EvaluateSupport, ExtendedBalance, PerThing128, Supports, VoteWeight, @@ -191,7 +191,7 @@ use sp_runtime::{ }, DispatchError, InnerOf, PerThing, Perbill, RuntimeDebug, SaturatedConversion, }; -use sp_std::{convert::TryInto, prelude::*}; +use sp_std::prelude::*; use sp_arithmetic::{ UpperOf, traits::{Zero, CheckedAdd}, @@ -204,6 +204,14 @@ mod mock; #[macro_use] pub(crate) mod macros; +const LOG_TARGET: &'static str = "election-provider"; + +// for the helper macros +#[doc(hidden)] +pub use sp_runtime::traits::UniqueSaturatedInto; +#[doc(hidden)] +pub use sp_std::convert::TryInto; + pub mod signed; pub mod unsigned; pub mod weights; @@ -236,7 +244,7 @@ struct OnChainConfig(sp_std::marker::PhantomData) where ExtendedBalance: From>>, ExtendedBalance: From>>; -impl crate::onchain::Config for OnChainConfig +impl onchain::Config for OnChainConfig where ExtendedBalance: From>>, ExtendedBalance: From>>, @@ -429,7 +437,7 @@ pub enum ElectionError { /// A feasibility error. Feasibility(FeasibilityError), /// An error in the on-chain fallback. - OnChainFallback(crate::onchain::Error), + OnChainFallback(onchain::Error), /// No fallback is configured NoFallbackConfigured, /// An internal error in the NPoS elections crate. @@ -442,8 +450,8 @@ pub enum ElectionError { PoolSubmissionFailed, } -impl From for ElectionError { - fn from(e: crate::onchain::Error) -> Self { +impl From for ElectionError { + fn from(e: onchain::Error) -> Self { ElectionError::OnChainFallback(e) } } @@ -726,7 +734,7 @@ pub mod pallet { /// Submit a solution for the unsigned phase. /// - /// The dispatch origin fo this call must be __signed__. + /// The dispatch origin fo this call must be __none__. /// /// This submission is checked on the fly, thus it is likely yo be more limited and smaller. /// Moreover, this unsigned solution is only validated when submitted to the pool from the @@ -848,23 +856,18 @@ pub mod pallet { log!(error, "unsigned transaction validation failed due to {:?}", err); err }) - .map_err(dispatch_error_to_invalid) - .map(Into::into)?; + .map_err(dispatch_error_to_invalid)?; ValidTransaction::with_tag_prefix("OffchainElection") // The higher the score[0], the better a solution is. .priority( - T::UnsignedPriority::get() - .saturating_add(solution.score[0].saturated_into()), + T::UnsignedPriority::get().saturating_add(solution.score[0].saturated_into()), ) // used to deduplicate unsigned solutions: each validator should produce one // solution per round at most, and solutions are not propagate. .and_provides(solution.round) // transaction should stay in the pool for the duration of the unsigned phase. - .longevity( - TryInto::::try_into(T::UnsignedPhase::get()) - .unwrap_or(crate::two_phase::unsigned::DEFAULT_LONGEVITY), - ) + .longevity(T::UnsignedPhase::get().saturated_into::()) // We don't propagate this. This can never the validated at a remote node. .propagate(false) .build() @@ -949,7 +952,7 @@ where ExtendedBalance: From>>, ExtendedBalance: From>>, { - /// Logic for [`Pallet::on_initialize`] when signed phase is being opened. + /// Logic for `::on_initialize` when signed phase is being opened. /// /// This is decoupled for easy weight calculation. pub fn on_initialize_open_signed() { @@ -958,7 +961,7 @@ where Self::deposit_event(Event::SignedPhaseStarted(Self::round())); } - /// Logic for [`Pallet::on_initialize`] when unsigned phase is being opened. + /// Logic for `>::on_initialize` when unsigned phase is being opened. /// /// This is decoupled for easy weight calculation. Note that the default weight benchmark of /// this function will assume an empty signed queue for `finalize_signed_phase`. @@ -1147,7 +1150,7 @@ where where ExtendedBalance: From<::Inner>, { - > as ElectionProvider< + > as ElectionProvider< T::AccountId, T::BlockNumber, >>::elect() diff --git a/frame/election-providers/src/two_phase/macros.rs b/frame/two-phase-election-provider/src/macros.rs similarity index 73% rename from frame/election-providers/src/two_phase/macros.rs rename to frame/two-phase-election-provider/src/macros.rs index 9dbcccedc604e..834170464d1cd 100644 --- a/frame/election-providers/src/two_phase/macros.rs +++ b/frame/two-phase-election-provider/src/macros.rs @@ -30,11 +30,11 @@ macro_rules! log { #[macro_export] macro_rules! voter_index_fn { ($voters:ident, $acc:ty, $t:ident) => { - |who: &$acc| -> Option<$crate::two_phase::CompactVoterIndexOf<$t>> { + |who: &$acc| -> Option<$crate::CompactVoterIndexOf<$t>> { $voters .iter() .position(|(x, _, _)| x == who) - .and_then(|i| >>::try_into(i).ok()) + .and_then(|i| >>::try_into(i).ok()) } }; } @@ -42,11 +42,11 @@ macro_rules! voter_index_fn { #[macro_export] macro_rules! target_index_fn { ($targets:ident, $acc:ty, $t:ident) => { - |who: &$acc| -> Option<$crate::two_phase::CompactTargetIndexOf<$t>> { + |who: &$acc| -> Option<$crate::CompactTargetIndexOf<$t>> { $targets .iter() .position(|x| x == who) - .and_then(|i| >>::try_into(i).ok()) + .and_then(|i| >>::try_into(i).ok()) } }; } @@ -54,8 +54,8 @@ macro_rules! target_index_fn { #[macro_export] macro_rules! voter_at_fn { ($snap:ident, $acc:ty, $t:ident) => { - |i: $crate::two_phase::CompactVoterIndexOf<$t>| -> Option<$acc> { - <$crate::two_phase::CompactVoterIndexOf<$t> as $crate::TryInto>::try_into(i) + |i: $crate::CompactVoterIndexOf<$t>| -> Option<$acc> { + <$crate::CompactVoterIndexOf<$t> as $crate::TryInto>::try_into(i) .ok() .and_then(|i| $snap .get(i) @@ -69,8 +69,8 @@ macro_rules! voter_at_fn { #[macro_export] macro_rules! target_at_fn { ($snap:ident, $acc:ty, $t:ident) => { - |i: $crate::two_phase::CompactTargetIndexOf<$t>| -> Option<$acc> { - <$crate::two_phase::CompactTargetIndexOf<$t> as $crate::TryInto>::try_into(i) + |i: $crate::CompactTargetIndexOf<$t>| -> Option<$acc> { + <$crate::CompactTargetIndexOf<$t> as $crate::TryInto>::try_into(i) .ok() .and_then(|i| $snap .get(i) diff --git a/frame/election-providers/src/two_phase/mock.rs b/frame/two-phase-election-provider/src/mock.rs similarity index 93% rename from frame/election-providers/src/two_phase/mock.rs rename to frame/two-phase-election-provider/src/mock.rs index 35d15b8853ee8..796f5276be1f2 100644 --- a/frame/election-providers/src/two_phase/mock.rs +++ b/frame/two-phase-election-provider/src/mock.rs @@ -1,5 +1,22 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use super::*; -use crate::two_phase; +use crate as two_phase; pub use frame_support::{assert_noop, assert_ok}; use frame_support::{ parameter_types, @@ -272,7 +289,7 @@ impl two_phase::weights::WeightInfo for DualMockWeightInfo { } } -impl crate::two_phase::Config for Runtime { +impl crate::Config for Runtime { type Event = Event; type Currency = Balances; type SignedPhase = SignedPhase; diff --git a/frame/election-providers/src/two_phase/signed.rs b/frame/two-phase-election-provider/src/signed.rs similarity index 99% rename from frame/election-providers/src/two_phase/signed.rs rename to frame/two-phase-election-provider/src/signed.rs index d86b310da8d38..323113485aa7f 100644 --- a/frame/election-providers/src/two_phase/signed.rs +++ b/frame/two-phase-election-provider/src/signed.rs @@ -17,7 +17,7 @@ //! The signed phase implementation. -use crate::two_phase::*; +use super::*; use codec::Encode; use sp_arithmetic::traits::SaturatedConversion; use sp_npos_elections::{is_score_better, CompactSolution}; diff --git a/frame/election-providers/src/two_phase/unsigned.rs b/frame/two-phase-election-provider/src/unsigned.rs similarity index 99% rename from frame/election-providers/src/two_phase/unsigned.rs rename to frame/two-phase-election-provider/src/unsigned.rs index 68364936c4297..dd209489467e5 100644 --- a/frame/election-providers/src/two_phase/unsigned.rs +++ b/frame/two-phase-election-provider/src/unsigned.rs @@ -17,7 +17,7 @@ //! The unsigned phase implementation. -use crate::two_phase::*; +use crate::*; use frame_support::dispatch::DispatchResult; use frame_system::offchain::SubmitTransaction; use sp_npos_elections::{seq_phragmen, CompactSolution, ElectionResult}; @@ -29,8 +29,6 @@ pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/two-phase-unsigned-election/ /// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice /// within a window of 5 blocks. pub(crate) const OFFCHAIN_REPEAT: u32 = 5; -/// Default number of blocks for which the unsigned transaction should stay in the pool -pub(crate) const DEFAULT_LONGEVITY: u64 = 25; impl Pallet where @@ -357,7 +355,7 @@ mod max_weight { use super::{mock::*, *}; struct TestWeight; - impl crate::two_phase::weights::WeightInfo for TestWeight { + impl crate::weights::WeightInfo for TestWeight { fn on_initialize_nothing() -> Weight { unreachable!() } diff --git a/frame/election-providers/src/two_phase/weights.rs b/frame/two-phase-election-provider/src/weights.rs similarity index 100% rename from frame/election-providers/src/two_phase/weights.rs rename to frame/two-phase-election-provider/src/weights.rs diff --git a/primitives/election-providers/Cargo.toml b/primitives/election-providers/Cargo.toml index c4a7c659f8e0c..65ca0e400958e 100644 --- a/primitives/election-providers/Cargo.toml +++ b/primitives/election-providers/Cargo.toml @@ -14,9 +14,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] } -sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } -sp-arithmetic = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/arithmetic" } -sp-npos-elections = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/npos-elections" } +sp-std = { version = "2.0.0-rc6", default-features = false, path = "../std" } +sp-arithmetic = { version = "2.0.0-rc6", default-features = false, path = "../arithmetic" } +sp-npos-elections = { version = "2.0.0-rc6", default-features = false, path = "../npos-elections" } + +[dev-dependencies] +sp-npos-elections = { version = "2.0.0-rc6", path = "../npos-elections" } +sp-runtime = { version = "2.0.0-rc6", path = "../runtime" } [features] default = ["std"] diff --git a/primitives/election-providers/src/lib.rs b/primitives/election-providers/src/lib.rs index 76cea316b292b..5651ed3b55714 100644 --- a/primitives/election-providers/src/lib.rs +++ b/primitives/election-providers/src/lib.rs @@ -161,6 +161,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +pub mod onchain; use sp_std::prelude::*; /// Re-export some type as they are used in the interface. diff --git a/frame/election-providers/src/onchain.rs b/primitives/election-providers/src/onchain.rs similarity index 93% rename from frame/election-providers/src/onchain.rs rename to primitives/election-providers/src/onchain.rs index f5df77a80d8b4..ec0f677591b48 100644 --- a/frame/election-providers/src/onchain.rs +++ b/primitives/election-providers/src/onchain.rs @@ -15,19 +15,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! An implementation of [`sp_election_providers::ElectionProvider`] that does an on-chain -//! sequential phragmen. +//! An implementation of [`ElectionProvider`] that does an on-chain sequential phragmen. use sp_arithmetic::PerThing; -use sp_election_providers::{ElectionDataProvider, ElectionProvider}; +use crate::{ElectionDataProvider, ElectionProvider}; use sp_npos_elections::{ ElectionResult, ExtendedBalance, IdentifierT, PerThing128, Supports, VoteWeight, }; -use sp_runtime::RuntimeDebug; use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*}; /// Errors of the on-chain election. -#[derive(RuntimeDebug, Eq, PartialEq)] +#[derive(Eq, PartialEq, Debug)] pub enum Error { /// An internal error in the NPoS elections crate. NposElections(sp_npos_elections::Error), @@ -105,7 +103,6 @@ where #[cfg(test)] mod tests { use super::*; - use sp_election_providers::VoteWeight; use sp_npos_elections::Support; use sp_runtime::Perbill; From a922f0b0bdd1a0e413c6d97948e630a573213078 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 8 Jan 2021 17:15:52 +0000 Subject: [PATCH 44/62] Witness -> SoltionSize --- .../src/benchmarking.rs | 20 +++++------ frame/two-phase-election-provider/src/lib.rs | 20 +++++------ frame/two-phase-election-provider/src/mock.rs | 4 +-- .../two-phase-election-provider/src/signed.rs | 10 +++--- .../src/unsigned.rs | 34 +++++++++---------- 5 files changed, 44 insertions(+), 44 deletions(-) diff --git a/frame/two-phase-election-provider/src/benchmarking.rs b/frame/two-phase-election-provider/src/benchmarking.rs index ce3a031a779e1..71362ec3e74fe 100644 --- a/frame/two-phase-election-provider/src/benchmarking.rs +++ b/frame/two-phase-election-provider/src/benchmarking.rs @@ -36,7 +36,7 @@ const SEED: u32 = 0; /// /// The snapshot is also created internally. fn solution_with_size( - witness: WitnessData, + size: SolutionSize, active_voters_count: u32, winners_count: u32, ) -> RawSolution> @@ -45,13 +45,13 @@ where ExtendedBalance: From>>, > as sp_std::convert::TryFrom>::Error: sp_std::fmt::Debug, { - assert!(witness.targets >= winners_count, "must have enough targets"); + assert!(size.targets >= winners_count, "must have enough targets"); assert!( - witness.targets >= (>::LIMIT * 2) as u32, + size.targets >= (>::LIMIT * 2) as u32, "must have enough targets for unique votes." ); assert!( - witness.voters >= active_voters_count, + size.voters >= active_voters_count, "must have enough voters" ); assert!( @@ -63,7 +63,7 @@ where let stake: VoteWeight = ed.max(One::one()).saturating_mul(100); // first generates random targets. - let targets: Vec = (0..witness.targets) + let targets: Vec = (0..size.targets) .map(|i| account("Targets", i, SEED)) .collect(); @@ -96,7 +96,7 @@ where .filter(|t| !winners.contains(t)) .cloned() .collect::>(); - let rest_voters = (active_voters_count..witness.voters) + let rest_voters = (active_voters_count..size.voters) .map(|i| { let votes = (&non_winners) .choose_multiple(&mut rng, >::LIMIT) @@ -112,7 +112,7 @@ where all_voters.shuffle(&mut rng); assert_eq!(active_voters.len() as u32, active_voters_count); - assert_eq!(all_voters.len() as u32, witness.voters); + assert_eq!(all_voters.len() as u32, size.voters); assert_eq!(winners.len() as u32, winners_count); >::put(RoundSnapshotMetadata { @@ -276,7 +276,7 @@ benchmarks! { // number of desired targets. Must be a subset of `t` component. let d in 200 .. 400; - let witness = WitnessData { voters: v, targets: t }; + let witness = SolutionSize { voters: v, targets: t }; let raw_solution = solution_with_size::(witness, a, d); assert!(>::queued_solution().is_none()); @@ -298,8 +298,8 @@ benchmarks! { // number of desired targets. Must be a subset of `t` component. let d in 30 .. 60; - let witness = WitnessData { voters: v, targets: t }; - let raw_solution = solution_with_size::(witness, a, d); + let size = SolutionSize { voters: v, targets: t }; + let raw_solution = solution_with_size::(size, a, d); assert_eq!(raw_solution.compact.voter_count() as u32, a); assert_eq!(raw_solution.compact.unique_targets().len() as u32, d); diff --git a/frame/two-phase-election-provider/src/lib.rs b/frame/two-phase-election-provider/src/lib.rs index 3d97d17f16b4d..bf420009ae861 100644 --- a/frame/two-phase-election-provider/src/lib.rs +++ b/frame/two-phase-election-provider/src/lib.rs @@ -384,11 +384,11 @@ pub struct ReadySolution { compute: ElectionCompute, } -/// Witness data about the size of the election. +/// Solution size of the election. /// /// This is needed for proper weight calculation. #[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, Default)] -pub struct WitnessData { +pub struct SolutionSize { /// Number of all voters. /// /// This must match the on-chain snapshot. @@ -697,14 +697,14 @@ pub mod pallet { // NOTE: this is the only case where having separate snapshot would have been better // because could do just decode_len. But we can create abstractions to do this. - // build witness. Note: this is not needed for weight calc, thus not input. + // build size. Note: this is not needed for weight calc, thus not input. // defensive-only: if phase is signed, snapshot will exist. - let witness = Self::build_witness().unwrap_or_default(); + let size = Self::build_solution_size().unwrap_or_default(); // ensure solution claims is better. let mut signed_submissions = Self::signed_submissions(); let maybe_index = - Self::insert_submission(&who, &mut signed_submissions, solution, witness); + Self::insert_submission(&who, &mut signed_submissions, solution, size); ensure!(maybe_index.is_some(), Error::::QueueFull); let index = maybe_index.expect("Option checked to be `Some`; qed."); @@ -755,7 +755,7 @@ pub mod pallet { pub fn submit_unsigned( origin: OriginFor, solution: RawSolution>, - witness: WitnessData, + witness: SolutionSize, ) -> DispatchResultWithPostInfo { ensure_none(origin)?; let error_message = "Invalid unsigned submission must produce invalid block and \ @@ -827,7 +827,7 @@ pub mod pallet { QueueFull, /// The origin failed to pay the deposit. CannotPayDeposit, - /// WitnessData is invalid. + /// witness data to dispathable is invalid. InvalidWitness, } @@ -1014,10 +1014,10 @@ where >::put(RoundSnapshot { voters, targets }); } - /// Build the witness data from the snapshot metadata, if it exists. Else, returns `None`. - fn build_witness() -> Option { + /// Build the solution size from the snapshot metadata, if it exists. Else, returns `None`. + fn build_solution_size() -> Option { let metadata = Self::snapshot_metadata()?; - Some(WitnessData { + Some(SolutionSize { voters: metadata.voters_len as u32, targets: metadata.targets_len as u32, }) diff --git a/frame/two-phase-election-provider/src/mock.rs b/frame/two-phase-election-provider/src/mock.rs index 796f5276be1f2..b4f6c8723a858 100644 --- a/frame/two-phase-election-provider/src/mock.rs +++ b/frame/two-phase-election-provider/src/mock.rs @@ -143,9 +143,9 @@ pub fn raw_solution() -> RawSolution> { RawSolution { compact, score, round } } -pub fn witness() -> WitnessData { +pub fn witness() -> SolutionSize { TwoPhase::snapshot() - .map(|snap| WitnessData { + .map(|snap| SolutionSize { voters: snap.voters.len() as u32, targets: snap.targets.len() as u32, }) diff --git a/frame/two-phase-election-provider/src/signed.rs b/frame/two-phase-election-provider/src/signed.rs index 323113485aa7f..2c2446c1cffaf 100644 --- a/frame/two-phase-election-provider/src/signed.rs +++ b/frame/two-phase-election-provider/src/signed.rs @@ -146,7 +146,7 @@ where who: &T::AccountId, queue: &mut Vec, CompactOf>>, solution: RawSolution>, - witness: WitnessData, + size: SolutionSize, ) -> Option { // from the last score, compare and see if the current one is better. If none, then the // awarded index is 0. @@ -173,7 +173,7 @@ where } else { // add to the designated spot. If the length is too much, remove one. let reward = Self::reward_for(&solution); - let deposit = Self::deposit_for(&solution, witness); + let deposit = Self::deposit_for(&solution, size); let submission = SignedSubmission { who: who.clone(), deposit, @@ -225,11 +225,11 @@ where /// 1. base deposit, fixed for all submissions. /// 2. a per-byte deposit, for renting the state usage. /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize - pub fn deposit_for(solution: &RawSolution>, witness: WitnessData) -> BalanceOf { + pub fn deposit_for(solution: &RawSolution>, size: SolutionSize) -> BalanceOf { let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); let feasibility_weight = T::WeightInfo::feasibility_check( - witness.voters, - witness.targets, + size.voters, + size.targets, solution.compact.voter_count() as u32, solution.compact.unique_targets().len() as u32, ); diff --git a/frame/two-phase-election-provider/src/unsigned.rs b/frame/two-phase-election-provider/src/unsigned.rs index dd209489467e5..790b228dd70f9 100644 --- a/frame/two-phase-election-provider/src/unsigned.rs +++ b/frame/two-phase-election-provider/src/unsigned.rs @@ -38,7 +38,7 @@ where /// Min a new npos solution. pub fn mine_solution( iters: usize, - ) -> Result<(RawSolution>, WitnessData), ElectionError> { + ) -> Result<(RawSolution>, SolutionSize), ElectionError> { let RoundSnapshot { voters, targets } = Self::snapshot().ok_or(ElectionError::SnapshotUnAvailable)?; let desired_targets = Self::desired_targets().ok_or(ElectionError::SnapshotUnAvailable)?; @@ -66,7 +66,7 @@ where /// Will always reduce the solution as well. pub fn prepare_election_result( election_result: ElectionResult>, - ) -> Result<(RawSolution>, WitnessData), ElectionError> { + ) -> Result<(RawSolution>, SolutionSize), ElectionError> { // storage items. Note: we have already read this from storage, they must be in cache. let RoundSnapshot { voters, targets } = Self::snapshot().ok_or(ElectionError::SnapshotUnAvailable)?; @@ -94,13 +94,13 @@ where let ratio = sp_npos_elections::assignment_staked_to_ratio_normalized(staked)?; let compact = >::from_assignment(ratio, &voter_index, &target_index)?; - let witness = WitnessData { + let size = SolutionSize { voters: voters.len() as u32, targets: targets.len() as u32, }; let maximum_allowed_voters = Self::maximum_voter_for_weight::( desired_targets, - witness, + size, T::MinerMaxWeight::get(), ); log!( @@ -118,7 +118,7 @@ where .score(&winners, stake_of, voter_at, target_at)?; let round = Self::round(); - Ok((RawSolution { compact, score, round }, witness)) + Ok((RawSolution { compact, score, round }, size)) } /// Get a random number of iterations to run the balancing in the OCW. @@ -202,21 +202,21 @@ where /// This only returns a value between zero and `size.nominators`. pub fn maximum_voter_for_weight( desired_winners: u32, - witness: WitnessData, + size: SolutionSize, max_weight: Weight, ) -> u32 { - if witness.voters < 1 { - return witness.voters; + if size.voters < 1 { + return size.voters; } - let max_voters = witness.voters.max(1); + let max_voters = size.voters.max(1); let mut voters = max_voters; // helper closures. let weight_with = |active_voters: u32| -> Weight { W::submit_unsigned( - witness.voters, - witness.targets, + size.voters, + size.targets, active_voters, desired_winners, ) @@ -266,12 +266,12 @@ where } debug_assert!( - weight_with(voters.min(witness.voters)) <= max_weight, + weight_with(voters.min(size.voters)) <= max_weight, "weight_with({}) <= {}", - voters.min(witness.voters), + voters.min(size.voters), max_weight, ); - voters.min(witness.voters) + voters.min(size.voters) } /// Checks if an execution of the offchain worker is permitted at the given block number, or not. @@ -384,7 +384,7 @@ mod max_weight { #[test] fn find_max_voter_binary_search_works() { - let w = WitnessData { + let w = SolutionSize { voters: 10, targets: 0, }; @@ -468,7 +468,7 @@ mod max_weight { 10 ); - let w = WitnessData { + let w = SolutionSize { voters: 1, targets: 0, }; @@ -512,7 +512,7 @@ mod max_weight { 1 ); - let w = WitnessData { + let w = SolutionSize { voters: 2, targets: 0, }; From 6d8247a127f2e99129a15c35c32b087d1b658b51 Mon Sep 17 00:00:00 2001 From: Parity Benchmarking Bot Date: Fri, 8 Jan 2021 17:19:43 +0000 Subject: [PATCH 45/62] cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_two_phase_election_provider --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/two-phase-election-provider/src/weights.rs --template=./.maintain/frame-weight-template.hbs --- .../src/weights.rs | 163 ++++++++---------- 1 file changed, 74 insertions(+), 89 deletions(-) diff --git a/frame/two-phase-election-provider/src/weights.rs b/frame/two-phase-election-provider/src/weights.rs index 58c9aa1d0aa2e..1bc2e8f729b61 100644 --- a/frame/two-phase-election-provider/src/weights.rs +++ b/frame/two-phase-election-provider/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2020 Parity Technologies (UK) Ltd. +// Copyright (C) 2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,37 +18,28 @@ //! Autogenerated weights for pallet_two_phase_election_provider //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 -//! DATE: 2020-12-29, STEPS: [10, ], REPEAT: 5, LOW RANGE: [], HIGH RANGE: [] -//! EXECUTION: Some(Native), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2021-01-08, STEPS: [50, ], REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: // target/release/substrate // benchmark -// --chain -// dev -// --steps -// 10 -// --repeat -// 5 -// --extrinsic -// * -// --execution=native +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_two_phase_election_provider +// --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --output -// . -// --header -// ./HEADER -// --pallet -// pallet_two_phase_election_provider +// --heap-pages=4096 +// --output=./frame/two-phase-election-provider/src/weights.rs // --template=./.maintain/frame-weight-template.hbs + #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{ - traits::Get, - weights::{constants::RocksDbWeight, Weight}, -}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use sp_std::marker::PhantomData; /// Weight functions needed for pallet_two_phase_election_provider. @@ -58,126 +49,120 @@ pub trait WeightInfo { fn on_initialize_open_unsigned() -> Weight; fn finalize_signed_phase_accept_solution() -> Weight; fn finalize_signed_phase_reject_solution() -> Weight; - fn submit(c: u32) -> Weight; - fn submit_unsigned(v: u32, t: u32, a: u32, d: u32) -> Weight; - fn feasibility_check(v: u32, t: u32, a: u32, d: u32) -> Weight; + fn submit(c: u32, ) -> Weight; + fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight; + fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight; } /// Weights for pallet_two_phase_election_provider using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn on_initialize_nothing() -> Weight { - (32_000_000 as Weight).saturating_add(T::DbWeight::get().reads(7 as Weight)) + (30_467_000 as Weight) + .saturating_add(T::DbWeight::get().reads(7 as Weight)) } fn on_initialize_open_signed() -> Weight { - (103_000_000 as Weight) + (97_342_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn on_initialize_open_unsigned() -> Weight { - (107_000_000 as Weight) + (101_084_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn finalize_signed_phase_accept_solution() -> Weight { - (38_000_000 as Weight) + (53_433_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn finalize_signed_phase_reject_solution() -> Weight { - (16_000_000 as Weight) + (23_717_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn submit(c: u32) -> Weight { - (57_926_000 as Weight) - // Standard Error: 153_000 - .saturating_add((1_267_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) + fn submit(c: u32, ) -> Weight { + (73_240_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_939_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32) -> Weight { - (260_195_000 as Weight) - // Standard Error: 1_138_000 - .saturating_add((872_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 1_138_000 - .saturating_add((37_162_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 5_690_000 - .saturating_add((18_018_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(T::DbWeight::get().reads(5 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(d as Weight))) + fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 27_000 + .saturating_add((8_842_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 27_000 + .saturating_add((25_957_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 137_000 + .saturating_add((3_939_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn feasibility_check(v: u32, _t: u32, a: u32, d: u32) -> Weight { - (1_819_529_000 as Weight) - // Standard Error: 1_260_000 - .saturating_add((1_051_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 2_100_000 - .saturating_add((21_722_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 4_201_000 - .saturating_add((10_227_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(T::DbWeight::get().reads(2 as Weight)) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) - .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(d as Weight))) + fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 16_000 + .saturating_add((2_794_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 25_000 + .saturating_add((12_311_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 62_000 + .saturating_add((3_075_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(T::DbWeight::get().reads(3 as Weight)) } } // For backwards compatibility and tests impl WeightInfo for () { fn on_initialize_nothing() -> Weight { - (32_000_000 as Weight).saturating_add(RocksDbWeight::get().reads(7 as Weight)) + (30_467_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(7 as Weight)) } fn on_initialize_open_signed() -> Weight { - (103_000_000 as Weight) + (97_342_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn on_initialize_open_unsigned() -> Weight { - (107_000_000 as Weight) + (101_084_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn finalize_signed_phase_accept_solution() -> Weight { - (38_000_000 as Weight) + (53_433_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn finalize_signed_phase_reject_solution() -> Weight { - (16_000_000 as Weight) + (23_717_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - fn submit(c: u32) -> Weight { - (57_926_000 as Weight) - // Standard Error: 153_000 - .saturating_add((1_267_000 as Weight).saturating_mul(c as Weight)) - .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + fn submit(c: u32, ) -> Weight { + (73_240_000 as Weight) + // Standard Error: 16_000 + .saturating_add((3_939_000 as Weight).saturating_mul(c as Weight)) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32) -> Weight { - (260_195_000 as Weight) - // Standard Error: 1_138_000 - .saturating_add((872_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 1_138_000 - .saturating_add((37_162_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 5_690_000 - .saturating_add((18_018_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(RocksDbWeight::get().reads(5 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(d as Weight))) + fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 27_000 + .saturating_add((8_842_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 27_000 + .saturating_add((25_957_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 137_000 + .saturating_add((3_939_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - fn feasibility_check(v: u32, _t: u32, a: u32, d: u32) -> Weight { - (1_819_529_000 as Weight) - // Standard Error: 1_260_000 - .saturating_add((1_051_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 2_100_000 - .saturating_add((21_722_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 4_201_000 - .saturating_add((10_227_000 as Weight).saturating_mul(d as Weight)) - .saturating_add(RocksDbWeight::get().reads(2 as Weight)) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(a as Weight))) - .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(d as Weight))) + fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 16_000 + .saturating_add((2_794_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 25_000 + .saturating_add((12_311_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 62_000 + .saturating_add((3_075_000 as Weight).saturating_mul(d as Weight)) + .saturating_add(RocksDbWeight::get().reads(3 as Weight)) } } From e9f4437adf2aba11ddd6747eec155f27aa23aed5 Mon Sep 17 00:00:00 2001 From: Parity Benchmarking Bot Date: Fri, 8 Jan 2021 17:35:01 +0000 Subject: [PATCH 46/62] cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_two_phase_election_provider --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/two-phase-election-provider/src/weights.rs --template=./.maintain/frame-weight-template.hbs --- .../src/weights.rs | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/frame/two-phase-election-provider/src/weights.rs b/frame/two-phase-election-provider/src/weights.rs index 1bc2e8f729b61..a36d973e598cc 100644 --- a/frame/two-phase-election-provider/src/weights.rs +++ b/frame/two-phase-election-provider/src/weights.rs @@ -58,55 +58,55 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn on_initialize_nothing() -> Weight { - (30_467_000 as Weight) + (31_115_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) } fn on_initialize_open_signed() -> Weight { - (97_342_000 as Weight) + (97_499_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn on_initialize_open_unsigned() -> Weight { - (101_084_000 as Weight) + (101_226_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn finalize_signed_phase_accept_solution() -> Weight { - (53_433_000 as Weight) + (53_218_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn finalize_signed_phase_reject_solution() -> Weight { - (23_717_000 as Weight) + (23_422_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn submit(c: u32, ) -> Weight { - (73_240_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_939_000 as Weight).saturating_mul(c as Weight)) + (72_484_000 as Weight) + // Standard Error: 14_000 + .saturating_add((3_869_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 27_000 - .saturating_add((8_842_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((8_907_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 27_000 - .saturating_add((25_957_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 137_000 - .saturating_add((3_939_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((26_080_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 138_000 + .saturating_add((4_066_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((2_794_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 25_000 - .saturating_add((12_311_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 62_000 - .saturating_add((3_075_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 17_000 + .saturating_add((2_852_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 28_000 + .saturating_add((12_478_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 69_000 + .saturating_add((3_028_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) } } @@ -114,55 +114,55 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn on_initialize_nothing() -> Weight { - (30_467_000 as Weight) + (31_115_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) } fn on_initialize_open_signed() -> Weight { - (97_342_000 as Weight) + (97_499_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn on_initialize_open_unsigned() -> Weight { - (101_084_000 as Weight) + (101_226_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn finalize_signed_phase_accept_solution() -> Weight { - (53_433_000 as Weight) + (53_218_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn finalize_signed_phase_reject_solution() -> Weight { - (23_717_000 as Weight) + (23_422_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn submit(c: u32, ) -> Weight { - (73_240_000 as Weight) - // Standard Error: 16_000 - .saturating_add((3_939_000 as Weight).saturating_mul(c as Weight)) + (72_484_000 as Weight) + // Standard Error: 14_000 + .saturating_add((3_869_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) // Standard Error: 27_000 - .saturating_add((8_842_000 as Weight).saturating_mul(v as Weight)) + .saturating_add((8_907_000 as Weight).saturating_mul(v as Weight)) // Standard Error: 27_000 - .saturating_add((25_957_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 137_000 - .saturating_add((3_939_000 as Weight).saturating_mul(d as Weight)) + .saturating_add((26_080_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 138_000 + .saturating_add((4_066_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 16_000 - .saturating_add((2_794_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 25_000 - .saturating_add((12_311_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 62_000 - .saturating_add((3_075_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 17_000 + .saturating_add((2_852_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 28_000 + .saturating_add((12_478_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 69_000 + .saturating_add((3_028_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) } } From 02069e1a696f7a6a2412451f26eb6f1d1c8223ef Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 12 Jan 2021 10:34:30 +0000 Subject: [PATCH 47/62] Update frame/session/src/lib.rs --- frame/session/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 83587fe0b2169..de82515b42965 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -164,7 +164,6 @@ impl< + PartialOrd + Saturating + Clone - + sp_std::fmt::Debug, Period: Get, Offset: Get, > EstimateNextSessionRotation for PeriodicSessions From 000ecdc89b512ed83a18573a99de65963888afd4 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 12 Jan 2021 11:52:03 +0000 Subject: [PATCH 48/62] Revamp macros --- .../src/benchmarking.rs | 24 +-- frame/two-phase-election-provider/src/lib.rs | 26 ++-- .../two-phase-election-provider/src/macros.rs | 138 +++++++++++++----- frame/two-phase-election-provider/src/mock.rs | 6 +- .../src/unsigned.rs | 10 +- 5 files changed, 138 insertions(+), 66 deletions(-) diff --git a/frame/two-phase-election-provider/src/benchmarking.rs b/frame/two-phase-election-provider/src/benchmarking.rs index 71362ec3e74fe..8804f7654c372 100644 --- a/frame/two-phase-election-provider/src/benchmarking.rs +++ b/frame/two-phase-election-provider/src/benchmarking.rs @@ -127,11 +127,11 @@ where // write the snapshot to staking or whoever is the data provider. T::DataProvider::put_snapshot(all_voters.clone(), targets.clone()); - let stake_of = crate::stake_of_fn!(all_voters, T::AccountId); - let voter_index = crate::voter_index_fn!(all_voters, T::AccountId, T); - let voter_at = crate::voter_at_fn!(all_voters, T::AccountId, T); - let target_at = crate::target_at_fn!(targets, T::AccountId, T); - let target_index = crate::target_index_fn!(targets, T::AccountId, T); + crate::stake_of_fn!(let stake_of, all_voters, T); + crate::voter_index_fn!(let voter_index, all_voters, T); + crate::voter_at_fn!(let voter_at, all_voters, T); + crate::target_at_fn!(let target_at, targets, T); + crate::target_index_fn!(let target_index, targets, T); let assignments = active_voters .iter() @@ -288,15 +288,15 @@ benchmarks! { // This is checking a valid solution. The worse case is indeed a valid solution. feasibility_check { - // number of voters in snapshot. - let v in 200 .. 300; + // number of votes in snapshot. + let v in 2000 .. 3000; // number of targets in snapshot. - let t in 80 .. 140; - // number of assignments, i.e. compact.voter_count(). This means the active nominators, - // thus must be a subset of `v` component. - let a in 80 .. 140; + let t in 500 .. 800; + // number of assignments, i.e. compact.len(). This means the active nominators, thus must be + // a subset of `v` component. + let a in 500 .. 1500; // number of desired targets. Must be a subset of `t` component. - let d in 30 .. 60; + let d in 200 .. 400; let size = SolutionSize { voters: v, targets: t }; let raw_solution = solution_with_size::(size, a, d); diff --git a/frame/two-phase-election-provider/src/lib.rs b/frame/two-phase-election-provider/src/lib.rs index bf420009ae861..3f4e4e6a0962a 100644 --- a/frame/two-phase-election-provider/src/lib.rs +++ b/frame/two-phase-election-provider/src/lib.rs @@ -210,7 +210,7 @@ const LOG_TARGET: &'static str = "election-provider"; #[doc(hidden)] pub use sp_runtime::traits::UniqueSaturatedInto; #[doc(hidden)] -pub use sp_std::convert::TryInto; +pub use sp_std; pub mod signed; pub mod unsigned; @@ -1064,8 +1064,9 @@ where } = Self::snapshot().ok_or(FeasibilityError::SnapshotUnavailable)?; // ----- Start building. First, we need some closures. - let voter_at = crate::voter_at_fn!(snapshot_voters, T::AccountId, T); - let target_at = crate::target_at_fn!(snapshot_targets, T::AccountId, T); + crate::voter_at_fn!(let voter_at , snapshot_voters, T); + crate::target_at_fn!(let target_at, snapshot_targets, T); + crate::voter_index_fn_usize!(let voter_index, snapshot_voters, T); // first, make sure that all the winners are sane. let winners = winners @@ -1084,14 +1085,15 @@ where .iter() .map(|ref assignment| { // check that assignment.who is actually a voter (defensive-only). - // NOTE: This check is fully defensive as we know that this assignment.who is - // a voter, what we don't know is stake and targets. Essentially, we have lost the - // index after converting `compact` -> `assignment`. This can be optimized in the - // future. - let (_voter, _stake, targets) = snapshot_voters - .iter() - .find(|(v, _, _)| v == &assignment.who) - .ok_or(FeasibilityError::InvalidVoter)?; + // NOTE: while using the index map from `voter_index` is better than a blind linear + // search, this *still* has room for optimization. Note that we had the index when + // we did `compact -> assignment` and we lost it. Ideal is to keep the index around. + + // defensive-only: must exist in the snapshot. + let snapshot_index = voter_index(&assignment.who).ok_or(FeasibilityError::InvalidVoter)?; + // defensive-only: index comes from the snapshot, must exist. + let (_voter, _stake, targets) = snapshot_voters.get(snapshot_index).ok_or(FeasibilityError::InvalidVoter)?; + // check that all of the targets are valid based on the snapshot. if assignment .distribution @@ -1105,7 +1107,7 @@ where .collect::>()?; // ----- Start building support. First, we need some more closures. - let stake_of = stake_of_fn!(snapshot_voters, T::AccountId); + stake_of_fn!(let stake_of, snapshot_voters, T); // This might fail if the normalization fails. Very unlikely. See `integrity_test`. let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) diff --git a/frame/two-phase-election-provider/src/macros.rs b/frame/two-phase-election-provider/src/macros.rs index 834170464d1cd..ed4428d764d66 100644 --- a/frame/two-phase-election-provider/src/macros.rs +++ b/frame/two-phase-election-provider/src/macros.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Some helper macros for this crate. +//! Some helper functions/macros for this crate. #[macro_export] macro_rules! log { @@ -27,69 +27,139 @@ macro_rules! log { }; } +#[deprecated = "May only be used for benchmarking purposes."] #[macro_export] -macro_rules! voter_index_fn { - ($voters:ident, $acc:ty, $t:ident) => { - |who: &$acc| -> Option<$crate::CompactVoterIndexOf<$t>> { +macro_rules! voter_index_fn_linear { + (let $name:ident, $voters:ident, $t:ident) => { + let $name = |who: &<$t as frame_system::Config>::AccountId| -> Option<$crate::CompactVoterIndexOf<$t>> { $voters .iter() .position(|(x, _, _)| x == who) - .and_then(|i| >>::try_into(i).ok()) - } + .and_then(|i| >>::try_into(i).ok()) + }; + }; +} + +#[macro_export] +macro_rules! voter_index_generate_cache { + ($name:ident, $voters:ident, $t:ident) => { + let mut $name: + $crate::sp_std::collections::btree_map::BTreeMap< + <$t as frame_system::Config>::AccountId, + usize + > + = $crate::sp_std::collections::btree_map::BTreeMap::new(); + $voters.iter().enumerate().for_each(|(i, (x, _, _))| { + let _existed = $name.insert(x.clone(), i); + // if a duplicate exists, we only consider the last one. Defensive only, should never happen. + debug_assert!(_existed.is_none()); + }); + }; +} + +#[macro_export] +macro_rules! voter_index_fn { + (let $name:ident, $voters:ident, $t:ident) => { + voter_index_generate_cache!(voters_map, $voters, $t); + let $name = |who: &<$t as frame_system::Config>::AccountId| -> Option> { + voters_map + .get(who) + .and_then(|i| >>::try_into(*i).ok()) + }; + }; +} + +#[macro_export] +macro_rules! voter_index_fn_usize { + (let $name:ident, $voters:ident, $t:ident) => { + voter_index_generate_cache!(voters_map, $voters, $t); + let $name = |who: &<$t as frame_system::Config>::AccountId| -> Option { + voters_map.get(who).cloned() + }; }; } #[macro_export] macro_rules! target_index_fn { - ($targets:ident, $acc:ty, $t:ident) => { - |who: &$acc| -> Option<$crate::CompactTargetIndexOf<$t>> { + (let $name: ident, $targets:ident, $t:ident) => { + let $name = |who: &<$t as frame_system::Config>::AccountId| -> Option<$crate::CompactTargetIndexOf<$t>> { $targets .iter() .position(|x| x == who) - .and_then(|i| >>::try_into(i).ok()) - } + .and_then(|i| + < + usize + as + $crate::sp_std::convert::TryInto<$crate::CompactTargetIndexOf<$t>> + >::try_into(i).ok() + ) + }; }; } #[macro_export] macro_rules! voter_at_fn { - ($snap:ident, $acc:ty, $t:ident) => { - |i: $crate::CompactVoterIndexOf<$t>| -> Option<$acc> { - <$crate::CompactVoterIndexOf<$t> as $crate::TryInto>::try_into(i) - .ok() - .and_then(|i| $snap - .get(i) - .map(|(x, _, _)| x) - .cloned() - ) - } + (let $name:ident, $snap:ident, $t:ident) => { + let $name = |i: $crate::CompactVoterIndexOf<$t>| -> Option<<$t as frame_system::Config>::AccountId> { + <$crate::CompactVoterIndexOf<$t> as $crate::sp_std::convert::TryInto>::try_into(i) + .ok() + .and_then(|i| $snap + .get(i) + .map(|(x, _, _)| x) + .cloned() + ) + }; }; } #[macro_export] macro_rules! target_at_fn { - ($snap:ident, $acc:ty, $t:ident) => { - |i: $crate::CompactTargetIndexOf<$t>| -> Option<$acc> { - <$crate::CompactTargetIndexOf<$t> as $crate::TryInto>::try_into(i) - .ok() - .and_then(|i| $snap - .get(i) - .cloned() - ) - }; + (let $name:ident, $snap:ident, $t:ident) => { + let $name = |i: $crate::CompactTargetIndexOf<$t>| -> Option<<$t as frame_system::Config>::AccountId> { + < + $crate::CompactTargetIndexOf<$t> + as + $crate::sp_std::convert::TryInto + >::try_into(i) + .ok() + .and_then(|i| $snap.get(i).cloned()) + }; }; } -// NOTE: these can use a cache. +#[deprecated = "May only be used for benchmarking purposes."] #[macro_export] -macro_rules! stake_of_fn { - ($voters:ident, $acc:ty) => { - |who: &$acc| -> $crate::VoteWeight { +macro_rules! stake_of_fn_linear { + (let $name:ident, $voters:ident, $t:ty) => { + let $name = |who: &<$t as frame_system::Config>::AccountId| -> $crate::VoteWeight { $voters .iter() .find(|(x, _, _)| x == who) .map(|(_, x, _)| *x) .unwrap_or_default() - } + }; + }; +} + +#[macro_export] +macro_rules! stake_of_fn { + (let $name:ident, $voters:ident, $t:ty) => { + let mut stake_map: + $crate::sp_std::collections::btree_map::BTreeMap< + <$t as frame_system::Config>::AccountId, + VoteWeight, + > + = $crate::sp_std::collections::btree_map::BTreeMap::new(); + $voters.iter().for_each(|(x, y, _)| { + let _existed = stake_map.insert(x.clone(), *y); + // if a duplicate exists, we only consider the last one. Defensive only, should never happen. + debug_assert!(_existed.is_none()); + }); + let $name = |who: &<$t as frame_system::Config>::AccountId| -> $crate::VoteWeight { + stake_map + .get(who) + .cloned() + .unwrap_or_default() + }; }; } diff --git a/frame/two-phase-election-provider/src/mock.rs b/frame/two-phase-election-provider/src/mock.rs index b4f6c8723a858..ece085ba6a611 100644 --- a/frame/two-phase-election-provider/src/mock.rs +++ b/frame/two-phase-election-provider/src/mock.rs @@ -115,9 +115,9 @@ pub fn raw_solution() -> RawSolution> { let desired_targets = TwoPhase::desired_targets().unwrap(); // closures - let voter_index = crate::voter_index_fn!(voters, AccountId, Runtime); - let target_index = crate::target_index_fn!(targets, AccountId, Runtime); - let stake_of = crate::stake_of_fn!(voters, AccountId); + crate::voter_index_fn!(let voter_index, voters, Runtime); + crate::target_index_fn!(let target_index, targets, Runtime); + crate::stake_of_fn!(let stake_of, voters, Runtime); let ElectionResult { winners, diff --git a/frame/two-phase-election-provider/src/unsigned.rs b/frame/two-phase-election-provider/src/unsigned.rs index 790b228dd70f9..522f21be9effa 100644 --- a/frame/two-phase-election-provider/src/unsigned.rs +++ b/frame/two-phase-election-provider/src/unsigned.rs @@ -73,11 +73,11 @@ where let desired_targets = Self::desired_targets().ok_or(ElectionError::SnapshotUnAvailable)?; // closures. - let voter_index = crate::voter_index_fn!(voters, T::AccountId, T); - let target_index = crate::target_index_fn!(targets, T::AccountId, T); - let voter_at = crate::voter_at_fn!(voters, T::AccountId, T); - let target_at = crate::target_at_fn!(targets, T::AccountId, T); - let stake_of = crate::stake_of_fn!(voters, T::AccountId); + crate::voter_index_fn!(let voter_index, voters, T); + crate::target_index_fn!(let target_index, targets, T); + crate::voter_at_fn!(let voter_at, voters, T); + crate::target_at_fn!(let target_at, targets, T); + crate::stake_of_fn!(let stake_of, voters, T); let ElectionResult { assignments, From 88a96a064d36f5561b73c4527a32e4cb1295e1c0 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 12 Jan 2021 14:27:56 +0000 Subject: [PATCH 49/62] Fix build --- frame/session/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index de82515b42965..341968f1ddb41 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -163,7 +163,7 @@ impl< + Zero + PartialOrd + Saturating - + Clone + + Clone, Period: Get, Offset: Get, > EstimateNextSessionRotation for PeriodicSessions From 8a6891556130309d1dced4e9485a929e31987448 Mon Sep 17 00:00:00 2001 From: Parity Benchmarking Bot Date: Tue, 12 Jan 2021 14:47:58 +0000 Subject: [PATCH 50/62] cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_two_phase_election_provider --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/two-phase-election-provider/src/weights.rs --template=./.maintain/frame-weight-template.hbs --- .../src/weights.rs | 92 ++++++++++--------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/frame/two-phase-election-provider/src/weights.rs b/frame/two-phase-election-provider/src/weights.rs index a36d973e598cc..7f8d065099a12 100644 --- a/frame/two-phase-election-provider/src/weights.rs +++ b/frame/two-phase-election-provider/src/weights.rs @@ -17,8 +17,8 @@ //! Autogenerated weights for pallet_two_phase_election_provider //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 -//! DATE: 2021-01-08, STEPS: [50, ], REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.1 +//! DATE: 2021-01-12, STEPS: [50, ], REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -58,55 +58,57 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn on_initialize_nothing() -> Weight { - (31_115_000 as Weight) + (21_412_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) } fn on_initialize_open_signed() -> Weight { - (97_499_000 as Weight) + (74_015_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn on_initialize_open_unsigned() -> Weight { - (101_226_000 as Weight) + (76_338_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn finalize_signed_phase_accept_solution() -> Weight { - (53_218_000 as Weight) + (37_157_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn finalize_signed_phase_reject_solution() -> Weight { - (23_422_000 as Weight) + (16_622_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn submit(c: u32, ) -> Weight { - (72_484_000 as Weight) - // Standard Error: 14_000 - .saturating_add((3_869_000 as Weight).saturating_mul(c as Weight)) + (51_611_000 as Weight) + // Standard Error: 19_000 + .saturating_add((3_355_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 27_000 - .saturating_add((8_907_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 27_000 - .saturating_add((26_080_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 138_000 - .saturating_add((4_066_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 20_000 + .saturating_add((3_164_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 20_000 + .saturating_add((11_299_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 104_000 + .saturating_add((2_664_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } - fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { + fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 17_000 - .saturating_add((2_852_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 28_000 - .saturating_add((12_478_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 69_000 - .saturating_add((3_028_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 11_000 + .saturating_add((3_254_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 38_000 + .saturating_add((567_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 11_000 + .saturating_add((9_628_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 58_000 + .saturating_add((3_731_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) } } @@ -114,55 +116,57 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn on_initialize_nothing() -> Weight { - (31_115_000 as Weight) + (21_412_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) } fn on_initialize_open_signed() -> Weight { - (97_499_000 as Weight) + (74_015_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn on_initialize_open_unsigned() -> Weight { - (101_226_000 as Weight) + (76_338_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn finalize_signed_phase_accept_solution() -> Weight { - (53_218_000 as Weight) + (37_157_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn finalize_signed_phase_reject_solution() -> Weight { - (23_422_000 as Weight) + (16_622_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn submit(c: u32, ) -> Weight { - (72_484_000 as Weight) - // Standard Error: 14_000 - .saturating_add((3_869_000 as Weight).saturating_mul(c as Weight)) + (51_611_000 as Weight) + // Standard Error: 19_000 + .saturating_add((3_355_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 27_000 - .saturating_add((8_907_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 27_000 - .saturating_add((26_080_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 138_000 - .saturating_add((4_066_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 20_000 + .saturating_add((3_164_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 20_000 + .saturating_add((11_299_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 104_000 + .saturating_add((2_664_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } - fn feasibility_check(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { + fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 17_000 - .saturating_add((2_852_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 28_000 - .saturating_add((12_478_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 69_000 - .saturating_add((3_028_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 11_000 + .saturating_add((3_254_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 38_000 + .saturating_add((567_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 11_000 + .saturating_add((9_628_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 58_000 + .saturating_add((3_731_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) } } From c41ecb0d8c39e5083d83a96ccb2cde393160d5eb Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 13 Jan 2021 09:07:28 +0000 Subject: [PATCH 51/62] fix all the tests. --- Cargo.lock | 4 ++++ bin/node/runtime/src/lib.rs | 8 ++++---- client/consensus/babe/src/authorship.rs | 1 + frame/babe/Cargo.toml | 1 + frame/babe/src/mock.rs | 9 +++++++++ frame/grandpa/Cargo.toml | 1 + frame/grandpa/src/mock.rs | 9 +++++++++ frame/offences/benchmarking/Cargo.toml | 2 ++ frame/offences/benchmarking/src/mock.rs | 9 +++++++++ frame/session/benchmarking/Cargo.toml | 2 ++ frame/session/benchmarking/src/mock.rs | 9 +++++++++ frame/staking/src/lib.rs | 2 +- 12 files changed, 52 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f462efa55b929..d36e3e197bbdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4398,6 +4398,7 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-vrf", "sp-core", + "sp-election-providers", "sp-inherents", "sp-io", "sp-runtime", @@ -4658,6 +4659,7 @@ dependencies = [ "serde", "sp-application-crypto", "sp-core", + "sp-election-providers", "sp-finality-grandpa", "sp-io", "sp-keyring", @@ -4847,6 +4849,7 @@ dependencies = [ "parity-scale-codec", "serde", "sp-core", + "sp-election-providers", "sp-io", "sp-runtime", "sp-staking", @@ -4968,6 +4971,7 @@ dependencies = [ "rand 0.7.3", "serde", "sp-core", + "sp-election-providers", "sp-io", "sp-runtime", "sp-session", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 132f7ee871ec6..fcfa8280c73f1 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -504,8 +504,8 @@ impl pallet_staking::Config for Runtime { parameter_types! { // phase durations - pub const SignedPhase: u32 = 5; - pub const UnsignedPhase: u32 = 5; + pub const SignedPhase: u32 = 100; + pub const UnsignedPhase: u32 = 100; // signed configs pub const MaxSignedSubmissions: u32 = 10; @@ -519,7 +519,7 @@ parameter_types! { // unsigned configs pub const TwoPhaseUnsignedPriority: TransactionPriority = StakingUnsignedPriority::get() - 1u64; pub const MaxUnsignedIterations: u32 = 10; - pub SolutionImprovementThreshold: Perbill = Perbill::from_rational_approximation(5u32, 10_000); + pub SolutionImprovementThreshold: Perbill = Perbill::from_rational_approximation(1u32, 10_000); pub MinerMaxWeight: Weight = RuntimeBlockWeights::get() .get(DispatchClass::Normal) .max_extrinsic.expect("Normal extrinsics have a weight limit configured; qed") @@ -1386,7 +1386,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_treasury, Treasury); add_benchmark!(params, batches, pallet_utility, Utility); add_benchmark!(params, batches, pallet_vesting, Vesting); - add_benchmark!(params, batches, pallet_two_phase_election_provider, TwoPhaseElectionProvider); + // add_benchmark!(params, batches, pallet_two_phase_election_provider, TwoPhaseElectionProvider); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 90ad12c4558c8..11bca37feaf3c 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -114,6 +114,7 @@ pub(super) fn secondary_slot_author( return None; } + dbg!((randomness, slot_number).using_encoded(blake2_256)); let rand = U256::from((randomness, slot_number).using_encoded(blake2_256)); let authorities_len = U256::from(authorities.len()); diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index 13ac2e4034c9f..a5e33bbf8f338 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -39,6 +39,7 @@ pallet-offences = { version = "2.0.0", path = "../offences" } pallet-staking = { version = "2.0.0", path = "../staking" } pallet-staking-reward-curve = { version = "2.0.0", path = "../staking/reward-curve" } sp-core = { version = "2.0.0", path = "../../primitives/core" } +sp-election-providers = { version = "2.0.0", path = "../../primitives/election-providers" } [features] default = ["std"] diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 58e2af873fd91..1c5b9f6eadbf7 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -37,6 +37,7 @@ use sp_consensus_babe::{AuthorityId, AuthorityPair, SlotNumber}; use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof}; use sp_staking::SessionIndex; use pallet_staking::EraIndex; +use sp_election_providers::onchain; impl_outer_origin!{ pub enum Origin for Test where system = frame_system {} @@ -179,6 +180,13 @@ parameter_types! { pub const StakingUnsignedPriority: u64 = u64::max_value() / 2; } +impl onchain::Config for Test { + type AccountId = ::AccountId; + type BlockNumber = ::BlockNumber; + type Accuracy = Perbill; + type DataProvider = Staking; +} + impl pallet_staking::Config for Test { type RewardRemainder = (); type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; @@ -201,6 +209,7 @@ impl pallet_staking::Config for Test { type MaxIterations = (); type MinSolutionScoreBump = (); type OffchainSolutionWeightLimit = (); + type ElectionProvider = onchain::OnChainSequentialPhragmen; type WeightInfo = (); } diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index c6a76de23e454..d12eb6060a1a9 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -38,6 +38,7 @@ pallet-offences = { version = "2.0.0", path = "../offences" } pallet-staking = { version = "2.0.0", path = "../staking" } pallet-staking-reward-curve = { version = "2.0.0", path = "../staking/reward-curve" } pallet-timestamp = { version = "2.0.0", path = "../timestamp" } +sp-election-providers = { version = "2.0.0", path = "../../primitives/election-providers" } [features] default = ["std"] diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index bf4ce5a519e7c..2c63424c5abd8 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -40,6 +40,7 @@ use sp_runtime::{ DigestItem, Perbill, }; use sp_staking::SessionIndex; +use sp_election_providers::onchain; impl_outer_origin! { pub enum Origin for Test {} @@ -194,6 +195,13 @@ parameter_types! { pub const StakingUnsignedPriority: u64 = u64::max_value() / 2; } +impl onchain::Config for Test { + type AccountId = ::AccountId; + type BlockNumber = ::BlockNumber; + type Accuracy = Perbill; + type DataProvider = Staking; +} + impl pallet_staking::Config for Test { type RewardRemainder = (); type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; @@ -216,6 +224,7 @@ impl pallet_staking::Config for Test { type MaxIterations = (); type MinSolutionScoreBump = (); type OffchainSolutionWeightLimit = (); + type ElectionProvider = onchain::OnChainSequentialPhragmen; type WeightInfo = (); } diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index 80492288d74bf..ede129ce77228 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -26,6 +26,7 @@ pallet-session = { version = "2.0.0", default-features = false, path = "../../se pallet-staking = { version = "2.0.0", default-features = false, features = ["runtime-benchmarks"], path = "../../staking" } sp-runtime = { version = "2.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "2.0.0", default-features = false, path = "../../../primitives/staking" } +sp-election-providers = { version = "2.0.0", default-features = false, path = "../../../primitives/election-providers" } sp-std = { version = "2.0.0", default-features = false, path = "../../../primitives/std" } [dev-dependencies] @@ -50,6 +51,7 @@ std = [ "pallet-staking/std", "sp-runtime/std", "sp-staking/std", + "sp-election-providers/std", "sp-std/std", "codec/std", ] diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 8e0bb361e15ce..2b2b359d8b64d 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -29,6 +29,7 @@ use sp_runtime::{ traits::{IdentityLookup, Block as BlockT}, testing::{Header, UintAuthorityId}, }; +use sp_election_providers::onchain; type AccountId = u64; @@ -147,6 +148,13 @@ parameter_types! { pub type Extrinsic = sp_runtime::testing::TestXt; +impl onchain::Config for Test { + type AccountId = AccountId; + type BlockNumber = BlockNumber; + type Accuracy = Perbill; + type DataProvider = Staking; +} + impl pallet_staking::Config for Test { type Currency = Balances; type UnixTime = pallet_timestamp::Module; @@ -169,6 +177,7 @@ impl pallet_staking::Config for Test { type MaxIterations = (); type MinSolutionScoreBump = (); type OffchainSolutionWeightLimit = (); + type ElectionProvider = onchain::OnChainSequentialPhragmen; type WeightInfo = (); } diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index fc3099e1b95cb..061af4d28e47b 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] sp-std = { version = "2.0.0", default-features = false, path = "../../../primitives/std" } sp-session = { version = "2.0.0", default-features = false, path = "../../../primitives/session" } sp-runtime = { version = "2.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-election-providers = { version = "2.0.0", default-features = false, path = "../../../primitives/election-providers" } frame-system = { version = "2.0.0", default-features = false, path = "../../system" } frame-benchmarking = { version = "2.0.0", default-features = false, path = "../../benchmarking" } frame-support = { version = "2.0.0", default-features = false, path = "../../support" } @@ -37,6 +38,7 @@ default = ["std"] std = [ "sp-std/std", "sp-session/std", + "sp-election-providers/std", "sp-runtime/std", "frame-system/std", "frame-benchmarking/std", diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 31593b3da54b3..5b145c75debec 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -21,6 +21,7 @@ use sp_runtime::traits::IdentityLookup; use frame_support::{impl_outer_origin, impl_outer_dispatch, parameter_types}; +use sp_election_providers::onchain; type AccountId = u64; type AccountIndex = u32; @@ -154,6 +155,13 @@ impl frame_system::offchain::SendTransactionTypes for Test where type Extrinsic = Extrinsic; } +impl onchain::Config for Test { + type AccountId = AccountId; + type BlockNumber = BlockNumber; + type Accuracy = sp_runtime::Perbill; + type DataProvider = Staking; +} + impl pallet_staking::Config for Test { type Currency = Balances; type UnixTime = pallet_timestamp::Module; @@ -176,6 +184,7 @@ impl pallet_staking::Config for Test { type MaxIterations = (); type MinSolutionScoreBump = (); type OffchainSolutionWeightLimit = (); + type ElectionProvider = onchain::OnChainSequentialPhragmen; type WeightInfo = (); } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 2a973362c2e04..ce72dd1bdaf62 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -796,7 +796,7 @@ pub trait Config: frame_system::Config + SendTransactionTypes> { type ElectionProvider: sp_election_providers::ElectionProvider< Self::AccountId, Self::BlockNumber, - // we only accept an election provider that has staking as data provider + // we only accept an election provider that has staking as data provider. DataProvider = Module, >; From f5e23f9902a793055d3d083284d8e14482c44119 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 13 Jan 2021 15:43:44 +0000 Subject: [PATCH 52/62] Fix the strange issue with cargo lock --- Cargo.lock | 831 +++++++++---------- client/consensus/babe/src/authorship.rs | 1 - frame/two-phase-election-provider/src/lib.rs | 2 +- 3 files changed, 412 insertions(+), 422 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d36e3e197bbdf..cee7e03796be1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,9 +12,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.14.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" dependencies = [ "gimli 0.23.0", ] @@ -55,7 +55,7 @@ dependencies = [ "aes", "block-cipher", "ghash", - "subtle 2.4.0", + "subtle 2.3.0", ] [[package]] @@ -81,9 +81,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.4.7" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" +checksum = "f6789e291be47ace86a60303502173d84af8327e3627ecf334356ee0f87a164c" [[package]] name = "aho-corasick" @@ -114,9 +114,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.37" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee67c11feeac938fae061b232e38e0b6d94f97a9df10e6271319325ac4c56a86" +checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" [[package]] name = "approx" @@ -135,9 +135,9 @@ checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569" [[package]] name = "arc-swap" -version = "0.4.8" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dabe5a181f83789739c194cbe5a897dde195078fac08568d09221fd6137a7ba8" +checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" [[package]] name = "arrayref" @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "assert_cmd" -version = "1.0.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dc1679af9a1ab4bea16f228b05d18f8363f8327b1fa8db00d2760cfafc6b61e" +checksum = "c88b9ca26f9c16ec830350d309397e74ee9abdfd8eb1f71cb6ecc71a3fc818da" dependencies = [ "doc-comment", "predicates", @@ -265,35 +265,17 @@ dependencies = [ "event-listener", ] -[[package]] -name = "async-process" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8cea09c1fb10a317d1b5af8024eeba256d6554763e85ecd90ff8df31c7bbda" -dependencies = [ - "async-io", - "blocking", - "cfg-if 0.1.10", - "event-listener", - "futures-lite", - "once_cell", - "signal-hook", - "winapi 0.3.9", -] - [[package]] name = "async-std" -version = "1.8.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f9f84f1280a2b436a2c77c2582602732b6c2f4321d5494d6e799e6c367859a8" +checksum = "a7e82538bc65a25dbdff70e4c5439d52f068048ab97cdea0acd73f131594caa1" dependencies = [ - "async-channel", "async-global-executor", "async-io", "async-mutex", - "async-process", "blocking", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.0", "futures-channel", "futures-core", "futures-io", @@ -304,7 +286,7 @@ dependencies = [ "memchr", "num_cpus", "once_cell", - "pin-project-lite 0.2.1", + "pin-project-lite 0.1.11", "pin-utils", "slab", "wasm-bindgen-futures", @@ -331,9 +313,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.42" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" +checksum = "b246867b8b3b6ae56035f1eb1ed557c1d8eae97f0d53696138a50fa0e3a3b8c0" dependencies = [ "proc-macro2", "quote", @@ -380,9 +362,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.55" +version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" +checksum = "2baad346b2d4e94a24347adeee9c7a93f412ee94b9cc26e5b59dea23848e9f28" dependencies = [ "addr2line", "cfg-if 1.0.0", @@ -599,9 +581,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.4.0" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffea412272c01cbee45e0d34f71c54af698d48f7d404a61fb46b71f48e3f30db" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "bytes" @@ -628,12 +610,11 @@ checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" [[package]] name = "cargo_metadata" -version = "0.12.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83f95cf4bf0dda0ac2e65371ae7215d0dce3c187613a9dbf23aaa9374186f97a" +checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345" dependencies = [ "semver 0.11.0", - "semver-parser 0.10.0", "serde", "serde_json", ] @@ -649,9 +630,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.66" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40" dependencies = [ "jobserver", ] @@ -782,6 +763,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "cloudabi" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" +dependencies = [ + "bitflags", +] + [[package]] name = "concurrent-queue" version = "1.2.2" @@ -813,9 +803,9 @@ dependencies = [ [[package]] name = "const_fn" -version = "0.4.5" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" +checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab" [[package]] name = "constant_time_eq" @@ -845,12 +835,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" -[[package]] -name = "cpuid-bool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" - [[package]] name = "cranelift-bforest" version = "0.66.0" @@ -875,7 +859,7 @@ dependencies = [ "log", "regalloc", "serde", - "smallvec 1.6.0", + "smallvec 1.5.0", "target-lexicon", "thiserror", ] @@ -913,7 +897,7 @@ checksum = "2ef419efb4f94ecc02e5d9fbcc910d2bb7f0040e2de570e63a454f883bc891d6" dependencies = [ "cranelift-codegen", "log", - "smallvec 1.6.0", + "smallvec 1.5.0", "target-lexicon", ] @@ -995,7 +979,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.0", ] [[package]] @@ -1016,8 +1000,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ "cfg-if 1.0.0", - "crossbeam-epoch 0.9.1", - "crossbeam-utils 0.8.1", + "crossbeam-epoch 0.9.0", + "crossbeam-utils 0.8.0", ] [[package]] @@ -1031,21 +1015,21 @@ dependencies = [ "crossbeam-utils 0.7.2", "lazy_static", "maybe-uninit", - "memoffset 0.5.6", + "memoffset", "scopeguard", ] [[package]] name = "crossbeam-epoch" -version = "0.9.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" +checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f" dependencies = [ "cfg-if 1.0.0", "const_fn", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.0", "lazy_static", - "memoffset 0.6.1", + "memoffset", "scopeguard", ] @@ -1073,12 +1057,13 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5" dependencies = [ "autocfg 1.0.1", "cfg-if 1.0.0", + "const_fn", "lazy_static", ] @@ -1105,14 +1090,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array 0.14.4", - "subtle 2.4.0", + "subtle 2.3.0", ] [[package]] name = "csv" -version = "1.1.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d58633299b24b515ac72a3f869f8b91306a3cec616a602843a383acd6f9e97" +checksum = "fc4666154fd004af3fd6f1da2e81a96fd5a81927fe8ddb6ecc79e2aa6e138b54" dependencies = [ "bstr", "csv-core", @@ -1141,9 +1126,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.17" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c88d9506e2e9230f6107701b7d8425f4cb3f6df108ec3042a26e936666da5" +checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484" dependencies = [ "quote", "syn", @@ -1162,27 +1147,27 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "2.1.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434e1720189a637d44fe464f4df1e6eb900b4835255b14354497c78af37d9bb8" +checksum = "5d85653f070353a16313d0046f173f70d1aadd5b42600a14de626f0dfb3473a5" dependencies = [ "byteorder", "digest 0.8.1", "rand_core 0.5.1", - "subtle 2.4.0", + "subtle 2.3.0", "zeroize", ] [[package]] name = "curve25519-dalek" -version = "3.0.2" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f627126b946c25a4638eec0ea634fc52506dea98db118aae985118ce7c3d723f" +checksum = "c8492de420e9e60bc9a1d66e2dbb91825390b738a388606600663fc529b4b307" dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", - "subtle 2.4.0", + "subtle 2.3.0", "zeroize", ] @@ -1302,9 +1287,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" +checksum = "d55796afa1b20c2945ca8eabfc421839f2b766619209f1ede813cf2484f31804" [[package]] name = "ed25519" @@ -1321,7 +1306,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek 3.0.2", + "curve25519-dalek 3.0.0", "ed25519", "rand 0.7.3", "serde", @@ -1389,9 +1374,9 @@ checksum = "6576a1755ddffd988788025e75bce9e74b018f7cc226198fe931d077911c6d7e" [[package]] name = "erased-serde" -version = "0.3.13" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0465971a8cc1fa2455c8465aaa377131e1f1cf4983280f474a13e68793aa770c" +checksum = "6ca8b296792113e1500fd935ae487be6e00ce318952a6880555554824d6ebf38" dependencies = [ "serde", ] @@ -1429,7 +1414,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", ] [[package]] @@ -1501,7 +1486,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8feb87a63249689640ac9c011742c33139204e3c134293d3054022276869133b" dependencies = [ "either", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 2.0.2", "log", "num-traits", @@ -1650,7 +1635,7 @@ dependencies = [ "paste 0.1.18", "pretty_assertions", "serde", - "smallvec 1.6.0", + "smallvec 1.5.0", "sp-api", "sp-arithmetic", "sp-core", @@ -1803,9 +1788,9 @@ checksum = "4c7e4c2612746b0df8fed4ce0c69156021b704c9aefa360311c04e6e9e002eed" [[package]] name = "futures" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70be434c505aee38639abccb918163b63158a4b4bb791b45b7023044bdc3c9c" +checksum = "309f13e3f4be6d5917178c84db67c0b9a09177ac16d4f9a7313a767a68adaa77" dependencies = [ "futures-channel", "futures-core", @@ -1818,9 +1803,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f01c61843314e95f96cc9245702248733a3a3d744e43e2e755e3c7af8348a0a9" +checksum = "7a3b03bd32f6ec7885edeb99acd1e47e20e34fd4dfd3c6deed6fcac8a9d28f6a" dependencies = [ "futures-core", "futures-sink", @@ -1828,9 +1813,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8d3b0917ff63a2a96173133c02818fac4a746b0a57569d3baca9ec0e945e08" +checksum = "ed8aeae2b6ab243ebabe6f54cd4cf53054d98883d5d326128af7d57a9ca5cd3d" [[package]] name = "futures-cpupool" @@ -1849,7 +1834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdcef58a173af8148b182684c9f2d5250875adbcaff7b5794073894f9d8634a9" dependencies = [ "futures 0.1.30", - "futures 0.3.9", + "futures 0.3.10", "lazy_static", "log", "parking_lot 0.9.0", @@ -1860,9 +1845,9 @@ dependencies = [ [[package]] name = "futures-executor" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee9ca2f7eb4475772cf39dd1cd06208dce2670ad38f4d9c7262b3e15f127068" +checksum = "3f7836b36b7533d16fd5937311d98ba8965ab81030de8b0024c299dd5d51fb9b" dependencies = [ "futures-core", "futures-task", @@ -1872,30 +1857,30 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37c1a51b037b80922864b8eed90692c5cd8abd4c71ce49b77146caa47f3253b" +checksum = "d41234e71d5e8ca73d01563974ef6f50e516d71e18f1a2f1184742e31f5d469f" [[package]] name = "futures-lite" -version = "1.11.3" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb" +checksum = "5e6c079abfac3ab269e2927ec048dabc89d009ebfdda6b8ee86624f30c689658" dependencies = [ "fastrand", "futures-core", "futures-io", "memchr", "parking", - "pin-project-lite 0.2.1", + "pin-project-lite 0.1.11", "waker-fn", ] [[package]] name = "futures-macro" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8719ca0e1f3c5e34f3efe4570ef2c0610ca6da85ae7990d472e9cbfba13664" +checksum = "3520e0eb4e704e88d771b92d51273ee212997f0d8282f17f5d8ff1cb39104e42" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -1905,15 +1890,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6adabac1290109cfa089f79192fb6244ad2c3f1cc2281f3e1dd987592b71feb" +checksum = "c72d188479368953c6c8c7140e40d7a4401674ab3b98a41e60e515d6cbdbe5de" [[package]] name = "futures-task" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92a0843a2ff66823a8f7c77bffe9a09be2b64e533562c412d63075643ec0038" +checksum = "08944cea9021170d383287169859c0ca8147d9ec285978393109954448f33cc7" dependencies = [ "once_cell", ] @@ -1936,9 +1921,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "036a2107cdeb57f6d7322f1b6c363dad67cd63ca3b7d1b925bdf75bd5d96cda9" +checksum = "d3dd206efbe2ca683b2ce138ccdf61e1b0a63f5816dcedc9d8654c500ba0cea6" dependencies = [ "futures 0.1.30", "futures-channel", @@ -1948,7 +1933,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.1", + "pin-project-lite 0.2.4", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -1962,7 +1947,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce54d63f8b0c75023ed920d46fd71d0cbbb830b0ee012726b5b4f506fb6dea5b" dependencies = [ "bytes 0.5.6", - "futures 0.3.9", + "futures 0.3.10", "memchr", "pin-project 0.4.27", ] @@ -1973,6 +1958,19 @@ version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +[[package]] +name = "generator" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc" +dependencies = [ + "cc", + "libc", + "log", + "rustc_version", + "winapi 0.3.9", +] + [[package]] name = "generic-array" version = "0.12.3" @@ -2003,12 +2001,11 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.16" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ - "cfg-if 1.0.0", - "js-sys", + "cfg-if 0.1.10", "libc", "wasi 0.9.0+wasi-snapshot-preview1", "wasm-bindgen", @@ -2023,17 +2020,16 @@ dependencies = [ "cfg-if 1.0.0", "js-sys", "libc", - "wasi 0.10.1+wasi-snapshot-preview1", + "wasi 0.10.0+wasi-snapshot-preview1", "wasm-bindgen", ] [[package]] name = "ghash" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +checksum = "d6e27f0689a6e15944bdce7e45425efb87eaa8ab0c6e87f11d0987a9133e2531" dependencies = [ - "opaque-debug 0.3.0", "polyval", ] @@ -2115,10 +2111,10 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.2", + "http 0.2.1", "indexmap", "slab", - "tokio 0.2.24", + "tokio 0.2.23", "tokio-util", "tracing", "tracing-futures", @@ -2132,9 +2128,9 @@ checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" [[package]] name = "handlebars" -version = "3.5.2" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "964d0e99a61fe9b1b347389b77ebf8b7e1587b70293676aaca7d27e59b9073b2" +checksum = "2764f9796c0ddca4b82c07f25dd2cb3db30b9a8f47940e78e1c883d9e95c3db9" dependencies = [ "log", "pest", @@ -2170,9 +2166,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" dependencies = [ "unicode-segmentation", ] @@ -2259,9 +2255,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84129d298a6d57d246960ff8eb831ca4af3f96d29e2e28848dae275408658e26" +checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" dependencies = [ "bytes 0.5.6", "fnv", @@ -2287,7 +2283,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" dependencies = [ "bytes 0.5.6", - "http 0.2.2", + "http 0.2.1", ] [[package]] @@ -2352,14 +2348,14 @@ dependencies = [ "futures-core", "futures-util", "h2 0.2.7", - "http 0.2.2", + "http 0.2.1", "http-body 0.3.1", "httparse", "httpdate", "itoa", - "pin-project 1.0.3", + "pin-project 1.0.2", "socket2", - "tokio 0.2.24", + "tokio 0.2.23", "tower-service", "tracing", "want 0.3.0", @@ -2378,7 +2374,7 @@ dependencies = [ "log", "rustls 0.18.1", "rustls-native-certs", - "tokio 0.2.24", + "tokio 0.2.23", "tokio-rustls", "webpki", ] @@ -2433,7 +2429,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16d7c5e361e6b05c882b4847dd98992534cebc6fcde7f4bc98225bcf10fd6d0d" dependencies = [ "async-io", - "futures 0.3.9", + "futures 0.3.10", "futures-lite", "if-addrs", "ipnet", @@ -2484,9 +2480,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" +checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" dependencies = [ "autocfg 1.0.1", "hashbrown", @@ -2495,9 +2491,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.9" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -2520,7 +2516,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64fa110ec7b8f493f416eed552740d10e7030ad5f63b2308f82c9608ec2df275" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "futures-timer 2.0.2", ] @@ -2565,9 +2561,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "jobserver" @@ -2753,7 +2749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92312348daade49976a6dc59263ad39ed54f840aacb5664874f7c9aa16e5f848" dependencies = [ "parity-util-mem", - "smallvec 1.6.0", + "smallvec 1.5.0", ] [[package]] @@ -2782,7 +2778,7 @@ dependencies = [ "parking_lot 0.11.1", "regex", "rocksdb", - "smallvec 1.6.0", + "smallvec 1.5.0", ] [[package]] @@ -2791,7 +2787,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7bfe11b3202691673766b1224c432996f6b8047db17ceb743675bef3404e714" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "js-sys", "kvdb", "kvdb-memorydb", @@ -2823,9 +2819,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.82" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" [[package]] name = "libloading" @@ -2851,7 +2847,7 @@ checksum = "2e17c636b5fe5ff900ccc2840b643074bfac321551d821243a781d0d46f06588" dependencies = [ "atomic", "bytes 0.5.6", - "futures 0.3.9", + "futures 0.3.10", "lazy_static", "libp2p-core", "libp2p-core-derive", @@ -2876,8 +2872,8 @@ dependencies = [ "libp2p-yamux", "parity-multiaddr", "parking_lot 0.11.1", - "pin-project 1.0.3", - "smallvec 1.6.0", + "pin-project 1.0.2", + "smallvec 1.5.0", "wasm-timer", ] @@ -2892,7 +2888,7 @@ dependencies = [ "ed25519-dalek", "either", "fnv", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "lazy_static", "libsecp256k1", @@ -2901,14 +2897,14 @@ dependencies = [ "multistream-select", "parity-multiaddr", "parking_lot 0.11.1", - "pin-project 1.0.3", + "pin-project 1.0.2", "prost", "prost-build", "rand 0.7.3", "ring", "rw-stream-sink", "sha2 0.9.2", - "smallvec 1.6.0", + "smallvec 1.5.0", "thiserror", "unsigned-varint", "void", @@ -2932,7 +2928,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3257a41f376aa23f237231971fee7e350e4d8353cfcf233aef34d6d6b638f0c" dependencies = [ "flate2", - "futures 0.3.9", + "futures 0.3.10", "libp2p-core", ] @@ -2942,7 +2938,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e09bab25af01326b4ed9486d31325911437448edda30bc57681502542d49f20" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "libp2p-core", "log", ] @@ -2955,14 +2951,14 @@ checksum = "6fd8cdd5ef1dd0b7346975477216d752de976b92e43051bc8bd808c372ea6cec" dependencies = [ "cuckoofilter", "fnv", - "futures 0.3.9", + "futures 0.3.10", "libp2p-core", "libp2p-swarm", "log", "prost", "prost-build", "rand 0.7.3", - "smallvec 1.6.0", + "smallvec 1.5.0", ] [[package]] @@ -2975,7 +2971,7 @@ dependencies = [ "byteorder", "bytes 0.5.6", "fnv", - "futures 0.3.9", + "futures 0.3.10", "futures_codec", "hex_fmt", "libp2p-core", @@ -2986,7 +2982,7 @@ dependencies = [ "prost-build", "rand 0.7.3", "sha2 0.9.2", - "smallvec 1.6.0", + "smallvec 1.5.0", "unsigned-varint", "wasm-timer", ] @@ -2997,13 +2993,13 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43bc51a9bc3780288c526615ba0f5f8216820ea6dcc02b89e8daee526c5fccb" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "libp2p-core", "libp2p-swarm", "log", "prost", "prost-build", - "smallvec 1.6.0", + "smallvec 1.5.0", "wasm-timer", ] @@ -3017,7 +3013,7 @@ dependencies = [ "bytes 0.5.6", "either", "fnv", - "futures 0.3.9", + "futures 0.3.10", "futures_codec", "libp2p-core", "libp2p-swarm", @@ -3026,7 +3022,7 @@ dependencies = [ "prost-build", "rand 0.7.3", "sha2 0.9.2", - "smallvec 1.6.0", + "smallvec 1.5.0", "uint 0.8.5", "unsigned-varint", "void", @@ -3042,14 +3038,14 @@ dependencies = [ "async-io", "data-encoding", "dns-parser", - "futures 0.3.9", + "futures 0.3.10", "if-watch", "lazy_static", "libp2p-core", "libp2p-swarm", "log", "rand 0.7.3", - "smallvec 1.6.0", + "smallvec 1.5.0", "socket2", "void", ] @@ -3061,14 +3057,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce3200fbe6608e623bd9efa459cc8bafa0e4efbb0a2dfcdd0e1387ff4181264b" dependencies = [ "bytes 0.5.6", - "futures 0.3.9", + "futures 0.3.10", "futures_codec", "libp2p-core", "log", "nohash-hasher", "parking_lot 0.11.1", "rand 0.7.3", - "smallvec 1.6.0", + "smallvec 1.5.0", "unsigned-varint", ] @@ -3079,8 +3075,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0580e0d18019d254c9c349c03ff7b22e564b6f2ada70c045fc39738e144f2139" dependencies = [ "bytes 0.5.6", - "curve25519-dalek 3.0.2", - "futures 0.3.9", + "curve25519-dalek 3.0.0", + "futures 0.3.10", "lazy_static", "libp2p-core", "log", @@ -3100,7 +3096,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50b2ec86a18cbf09d7df440e7786a2409640c774e476e9a3b4d031382c3d7588" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "libp2p-core", "libp2p-swarm", "log", @@ -3116,7 +3112,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a7b1bdcbe46a3a2159c231601ed29645282653c0a96ce3a2ad8352c9fbe6800" dependencies = [ "bytes 0.5.6", - "futures 0.3.9", + "futures 0.3.10", "futures_codec", "libp2p-core", "log", @@ -3132,9 +3128,9 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce3374f3b28162db9d3442c9347c4f14cb01e8290052615c7d341d40eae0599" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "log", - "pin-project 1.0.3", + "pin-project 1.0.2", "rand 0.7.3", "salsa20", "sha3", @@ -3148,14 +3144,14 @@ checksum = "620e2950decbf77554b5aed3824f7d0e2c04923f28c70f9bff1a402c47ef6b1e" dependencies = [ "async-trait", "bytes 0.5.6", - "futures 0.3.9", + "futures 0.3.10", "libp2p-core", "libp2p-swarm", "log", "lru", "minicbor", "rand 0.7.3", - "smallvec 1.6.0", + "smallvec 1.5.0", "unsigned-varint", "wasm-timer", ] @@ -3167,11 +3163,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf5894ee1ee63a38aa58d58a16e3dcf7ede6b59ea7b22302c00c1a41d7aec41" dependencies = [ "either", - "futures 0.3.9", + "futures 0.3.10", "libp2p-core", "log", "rand 0.7.3", - "smallvec 1.6.0", + "smallvec 1.5.0", "void", "wasm-timer", ] @@ -3183,7 +3179,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d2113a7dab2b502c55fe290910cd7399a2aa04fe70a2f5a415a87a1db600c0e" dependencies = [ "async-std", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "if-addrs", "ipnet", @@ -3199,7 +3195,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af05fe92c2a3aa320bc82a308ddb7b33bef3b060154c5a4b9fb0b01f15385fc0" dependencies = [ "async-std", - "futures 0.3.9", + "futures 0.3.10", "libp2p-core", "log", ] @@ -3210,7 +3206,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37cd44ea05a4523f40183f60ab6e6a80e400a5ddfc98b0df1c55edeb85576cd9" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "js-sys", "libp2p-core", "parity-send-wrapper", @@ -3226,7 +3222,7 @@ checksum = "270c80528e21089ea25b41dd1ab8fd834bdf093ebee422fed3b68699a857a083" dependencies = [ "async-tls", "either", - "futures 0.3.9", + "futures 0.3.10", "libp2p-core", "log", "quicksink", @@ -3244,7 +3240,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36799de9092c35782f080032eddbc8de870f94a0def87cf9f8883efccd5cacf0" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "libp2p-core", "parking_lot 0.11.1", "thiserror", @@ -3275,7 +3271,7 @@ dependencies = [ "hmac-drbg", "rand 0.7.3", "sha2 0.8.2", - "subtle 2.4.0", + "subtle 2.3.0", "typenum", ] @@ -3360,20 +3356,33 @@ dependencies = [ "cfg-if 0.1.10", ] +[[package]] +name = "loom" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed" +dependencies = [ + "cfg-if 0.1.10", + "generator", + "scoped-tls", + "serde", + "serde_json", +] + [[package]] name = "lru" -version = "0.6.3" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aae342b73d57ad0b8b364bd12584819f2c1fe9114285dfcf8b0722607671635" +checksum = "be716eb6878ca2263eb5d00a781aa13264a794f519fe6af4fbb2668b2d5441c0" dependencies = [ "hashbrown", ] [[package]] name = "lru_time_cache" -version = "0.11.3" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc2beb26938dfd9988fc368548b70bcdfaf955f55aa788e1682198de794a451" +checksum = "ebac060fafad3adedd0c66a80741a92ff4bc8e94a273df2ba3770ab206f2e29a" [[package]] name = "mach" @@ -3407,9 +3416,9 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "matrixmultiply" -version = "0.2.4" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916806ba0031cd542105d916a97c8572e1fa6dd79c9c51e7eb43a09ec2dd84c1" +checksum = "d4f7ec66360130972f34830bfad9ef05c6610a43938a467bcc9ab9369ab3478f" dependencies = [ "rawpointer", ] @@ -3445,15 +3454,6 @@ dependencies = [ "autocfg 1.0.1", ] -[[package]] -name = "memoffset" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" -dependencies = [ - "autocfg 1.0.1", -] - [[package]] name = "memory-db" version = "0.25.0" @@ -3515,9 +3515,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.23" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" dependencies = [ "cfg-if 0.1.10", "fuchsia-zircon", @@ -3526,7 +3526,7 @@ dependencies = [ "kernel32-sys", "libc", "log", - "miow 0.2.2", + "miow 0.2.1", "net2", "slab", "winapi 0.2.8", @@ -3569,9 +3569,9 @@ dependencies = [ [[package]] name = "miow" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" dependencies = [ "kernel32-sys", "net2", @@ -3597,9 +3597,9 @@ checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" [[package]] name = "multihash" -version = "0.13.2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dac63698b887d2d929306ea48b63760431ff8a24fac40ddb22f9c7f49fb7cab" +checksum = "fb63389ee5fcd4df3f8727600f4a0c3df53c541f0ed4e8b50a9ae51a80fc1efe" dependencies = [ "digest 0.9.0", "generic-array 0.14.4", @@ -3610,9 +3610,9 @@ dependencies = [ [[package]] name = "multihash-derive" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85ee3c48cb9d9b275ad967a0e96715badc13c6029adb92f34fa17b9ff28fd81f" +checksum = "2f5653449cd45d502a53480ee08d7a599e8f4893d2bacb33c63d65bc20af6c1a" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -3635,10 +3635,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dda822043bba2d6da31c4e14041f9794f8fb130a5959289038d0b809d8888614" dependencies = [ "bytes 0.5.6", - "futures 0.3.9", + "futures 0.3.10", "log", - "pin-project 1.0.3", - "smallvec 1.6.0", + "pin-project 1.0.2", + "smallvec 1.5.0", "unsigned-varint", ] @@ -3681,9 +3681,9 @@ dependencies = [ [[package]] name = "net2" -version = "0.2.37" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853" dependencies = [ "cfg-if 0.1.10", "libc", @@ -3709,7 +3709,7 @@ version = "0.8.0" dependencies = [ "derive_more", "fs_extra", - "futures 0.3.9", + "futures 0.3.10", "hash-db", "hex", "kvdb", @@ -3745,7 +3745,7 @@ dependencies = [ name = "node-browser-testing" version = "2.0.0" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "jsonrpc-core", "libp2p", @@ -3766,7 +3766,7 @@ dependencies = [ "frame-benchmarking-cli", "frame-support", "frame-system", - "futures 0.3.9", + "futures 0.3.10", "hex-literal", "log", "nix", @@ -4096,7 +4096,7 @@ dependencies = [ "frame-support", "frame-system", "fs_extra", - "futures 0.3.9", + "futures 0.3.10", "log", "node-executor", "node-primitives", @@ -4251,9 +4251,9 @@ dependencies = [ [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c" [[package]] name = "opaque-debug" @@ -4475,7 +4475,7 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "parity-wasm 0.41.0", - "paste 1.0.4", + "paste 1.0.3", "pretty_assertions", "pwasm-utils 0.16.0", "rand 0.7.3", @@ -5130,7 +5130,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", "serde", - "smallvec 1.6.0", + "smallvec 1.5.0", "sp-core", "sp-io", "sp-runtime", @@ -5197,7 +5197,7 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "parking_lot 0.11.1", - "paste 1.0.4", + "paste 1.0.3", "rand 0.7.3", "serde", "sp-arithmetic", @@ -5263,9 +5263,9 @@ dependencies = [ [[package]] name = "parity-multiaddr" -version = "0.10.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180cd097078b337d2ba6400c6a67b181b38b611273cb1d8d12f3d8d5d8eaaacb" +checksum = "2f51a30667591b14f96068b2d12f1306d07a41ebd98239d194356d4d9707ac16" dependencies = [ "arrayref", "bs58", @@ -5341,7 +5341,7 @@ dependencies = [ "parity-util-mem-derive", "parking_lot 0.11.1", "primitive-types", - "smallvec 1.6.0", + "smallvec 1.5.0", "winapi 0.3.9", ] @@ -5424,7 +5424,7 @@ checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ "instant", "lock_api 0.4.2", - "parking_lot_core 0.8.2", + "parking_lot_core 0.8.0", ] [[package]] @@ -5434,7 +5434,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" dependencies = [ "cfg-if 0.1.10", - "cloudabi", + "cloudabi 0.0.3", "libc", "redox_syscall", "rustc_version", @@ -5449,24 +5449,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" dependencies = [ "cfg-if 0.1.10", - "cloudabi", + "cloudabi 0.0.3", "libc", "redox_syscall", - "smallvec 1.6.0", + "smallvec 1.5.0", "winapi 0.3.9", ] [[package]] name = "parking_lot_core" -version = "0.8.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" +checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", + "cloudabi 0.1.0", "instant", "libc", "redox_syscall", - "smallvec 1.6.0", + "smallvec 1.5.0", "winapi 0.3.9", ] @@ -5482,9 +5483,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" +checksum = "7151b083b0664ed58ed669fcdd92f01c3d2fdbf10af4931a301474950b52bfa9" [[package]] name = "paste-impl" @@ -5602,11 +5603,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a83804639aad6ba65345661744708855f9fbcb71176ea8d28d05aeb11d975e7" +checksum = "9ccc2237c2c489783abd8c4c80e5450fc0e98644555b1364da68cc29aa151ca7" dependencies = [ - "pin-project-internal 1.0.3", + "pin-project-internal 1.0.2", ] [[package]] @@ -5622,9 +5623,9 @@ dependencies = [ [[package]] name = "pin-project-internal" -version = "1.0.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7bcc46b8f73443d15bc1c5fecbb315718491fa9187fa483f0e359323cde8b3a" +checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f" dependencies = [ "proc-macro2", "quote", @@ -5639,9 +5640,9 @@ checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" [[package]] name = "pin-project-lite" -version = "0.2.1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36743d754ccdf9954c2e352ce2d4b106e024c814f6499c2dadff80da9a442d8" +checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" [[package]] name = "pin-utils" @@ -5688,22 +5689,20 @@ dependencies = [ [[package]] name = "poly1305" -version = "0.6.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7456bc1ad2d4cf82b3a016be4c2ac48daf11bf990c1603ebd447fe6f30fca8" +checksum = "22ce46de8e53ee414ca4d02bfefac75d8c12fba948b76622a40b4be34dfce980" dependencies = [ - "cpuid-bool 0.2.0", "universal-hash", ] [[package]] name = "polyval" -version = "0.4.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" +checksum = "a5884790f1ce3553ad55fec37b5aaac5882e0e845a2612df744d6c85c9bf046c" dependencies = [ - "cpuid-bool 0.2.0", - "opaque-debug 0.3.0", + "cfg-if 0.1.10", "universal-hash", ] @@ -5715,9 +5714,9 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "predicates" -version = "1.0.6" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73dd9b7b200044694dfede9edf907c1ca19630908443e9447e624993700c6932" +checksum = "96bfead12e90dccead362d62bb2c90a5f6fc4584963645bc7f71a735e0b0735a" dependencies = [ "difference", "predicates-core", @@ -5725,15 +5724,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3dbeaaf793584e29c58c7e3a82bbb3c7c06b63cea68d13b0e3cddc124104dc" +checksum = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178" [[package]] name = "predicates-tree" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee95d988ee893cb35c06b148c80ed2cd52c8eea927f50ba7a0be1a786aeab73" +checksum = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124" dependencies = [ "predicates-core", "treeline", @@ -5941,9 +5940,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.8" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ "proc-macro2", ] @@ -6002,7 +6001,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.16", + "getrandom 0.1.15", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", @@ -6072,7 +6071,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.16", + "getrandom 0.1.15", ] [[package]] @@ -6137,7 +6136,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" dependencies = [ - "cloudabi", + "cloudabi 0.0.3", "fuchsia-cprng", "libc", "rand_core 0.4.2", @@ -6175,9 +6174,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "7.0.4" +version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb71f708fe39b2c5e98076204c3cc094ee5a4c12c4cdb119a2b72dc34164f41" +checksum = "b4a349ca83373cfa5d6dbb66fd76e58b2cca08da71a5f6400de0a0a6a9bceeaf" dependencies = [ "bitflags", "cc", @@ -6210,7 +6209,7 @@ checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ "crossbeam-channel", "crossbeam-deque 0.8.0", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.0", "lazy_static", "num_cpus", ] @@ -6236,25 +6235,25 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom 0.1.16", + "getrandom 0.1.15", "redox_syscall", "rust-argon2", ] [[package]] name = "ref-cast" -version = "1.0.6" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300f2a835d808734ee295d45007adacb9ebb29dd3ae2424acfa17930cae541da" +checksum = "e17626b2f4bcf35b84bf379072a66e28cfe5c3c6ae58b38e4914bb8891dabece" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.6" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2" +checksum = "0c523ccaed8ac4b0288948849a350b37d3035827413c458b6a40ddb614bb4f72" dependencies = [ "proc-macro2", "quote", @@ -6269,7 +6268,7 @@ checksum = "b9ba8aaf5fe7cf307c6dbdaeed85478961d29e25e3bee5169e11b92fa9f027a8" dependencies = [ "log", "rustc-hash", - "smallvec 1.6.0", + "smallvec 1.5.0", ] [[package]] @@ -6329,9 +6328,9 @@ checksum = "53552c6c49e1e13f1a203ef0080ab3bbef0beb570a528993e83df057a9d9bba1" [[package]] name = "ring" -version = "0.16.19" +version = "0.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226" +checksum = "b72b84d47e8ec5a4f2872e8262b8f8256c5be1c938a7d6d3a867a3ba8f722f74" dependencies = [ "cc", "libc", @@ -6364,14 +6363,14 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" +checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" dependencies = [ - "base64 0.13.0", + "base64 0.12.3", "blake2b_simd", "constant_time_eq", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.7.2", ] [[package]] @@ -6451,7 +6450,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "pin-project 0.4.27", "static_assertions", ] @@ -6496,7 +6495,7 @@ dependencies = [ "async-trait", "derive_more", "either", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "libp2p", "log", @@ -6524,7 +6523,7 @@ dependencies = [ name = "sc-basic-authorship" version = "0.8.1" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -6601,7 +6600,7 @@ dependencies = [ "atty", "chrono", "fdlimit", - "futures 0.3.9", + "futures 0.3.10", "hex", "libp2p", "log", @@ -6631,7 +6630,7 @@ dependencies = [ "tempfile", "thiserror", "tiny-bip39", - "tokio 0.2.24", + "tokio 0.2.23", "tracing", "tracing-log", "tracing-subscriber", @@ -6653,7 +6652,7 @@ version = "2.0.1" dependencies = [ "derive_more", "fnv", - "futures 0.3.9", + "futures 0.3.10", "hash-db", "kvdb", "kvdb-memorydb", @@ -6733,7 +6732,7 @@ name = "sc-consensus-aura" version = "0.8.1" dependencies = [ "derive_more", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "getrandom 0.2.1", "log", @@ -6774,7 +6773,7 @@ version = "0.8.1" dependencies = [ "derive_more", "fork-tree", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "log", "merlin", @@ -6827,7 +6826,7 @@ name = "sc-consensus-babe-rpc" version = "0.8.1" dependencies = [ "derive_more", - "futures 0.3.9", + "futures 0.3.10", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -6869,7 +6868,7 @@ version = "0.8.1" dependencies = [ "assert_matches", "derive_more", - "futures 0.3.9", + "futures 0.3.10", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -6897,7 +6896,7 @@ dependencies = [ "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", "tempfile", - "tokio 0.2.24", + "tokio 0.2.23", ] [[package]] @@ -6905,7 +6904,7 @@ name = "sc-consensus-pow" version = "0.8.1" dependencies = [ "derive_more", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -6927,7 +6926,7 @@ dependencies = [ name = "sc-consensus-slots" version = "0.8.1" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -7057,7 +7056,7 @@ dependencies = [ "derive_more", "finality-grandpa", "fork-tree", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "log", "parity-scale-codec", @@ -7091,7 +7090,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", - "tokio 0.2.24", + "tokio 0.2.23", ] [[package]] @@ -7100,7 +7099,7 @@ version = "0.8.1" dependencies = [ "derive_more", "finality-grandpa", - "futures 0.3.9", + "futures 0.3.10", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -7129,7 +7128,7 @@ name = "sc-informant" version = "0.8.1" dependencies = [ "ansi_term 0.12.1", - "futures 0.3.9", + "futures 0.3.10", "log", "parity-util-mem", "sc-client-api", @@ -7147,7 +7146,7 @@ version = "2.0.1" dependencies = [ "async-trait", "derive_more", - "futures 0.3.9", + "futures 0.3.10", "futures-util", "hex", "merlin", @@ -7157,7 +7156,7 @@ dependencies = [ "sp-application-crypto", "sp-core", "sp-keystore", - "subtle 2.4.0", + "subtle 2.3.0", "tempfile", ] @@ -7194,7 +7193,7 @@ dependencies = [ "erased-serde", "fnv", "fork-tree", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "futures_codec", "hex", @@ -7218,7 +7217,7 @@ dependencies = [ "serde_json", "slog", "slog_derive", - "smallvec 1.6.0", + "smallvec 1.5.0", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -7244,7 +7243,7 @@ name = "sc-network-gossip" version = "0.8.1" dependencies = [ "async-std", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "libp2p", "log", @@ -7263,7 +7262,7 @@ name = "sc-network-test" version = "0.8.0" dependencies = [ "async-std", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "libp2p", "log", @@ -7291,7 +7290,7 @@ version = "2.0.1" dependencies = [ "bytes 0.5.6", "fnv", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "hyper 0.13.9", "hyper-rustls", @@ -7315,14 +7314,14 @@ dependencies = [ "sp-utils", "substrate-test-runtime-client", "threadpool", - "tokio 0.2.24", + "tokio 0.2.23", ] [[package]] name = "sc-peerset" version = "2.0.1" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "libp2p", "log", "rand 0.7.3", @@ -7345,7 +7344,7 @@ version = "2.0.1" dependencies = [ "assert_matches", "futures 0.1.30", - "futures 0.3.9", + "futures 0.3.10", "hash-db", "jsonrpc-core", "jsonrpc-pubsub", @@ -7386,7 +7385,7 @@ name = "sc-rpc-api" version = "0.8.1" dependencies = [ "derive_more", - "futures 0.3.9", + "futures 0.3.10", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -7443,7 +7442,7 @@ dependencies = [ "directories 3.0.1", "exit-future", "futures 0.1.30", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "hash-db", "jsonrpc-core", @@ -7499,7 +7498,7 @@ dependencies = [ "substrate-test-runtime-client", "tempfile", "thiserror", - "tokio 0.2.24", + "tokio 0.2.23", "tracing", "tracing-futures", "wasm-timer", @@ -7511,7 +7510,7 @@ version = "2.0.0" dependencies = [ "fdlimit", "futures 0.1.30", - "futures 0.3.9", + "futures 0.3.10", "hex-literal", "log", "parity-scale-codec", @@ -7578,7 +7577,7 @@ dependencies = [ name = "sc-telemetry" version = "2.0.1" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "libp2p", "log", @@ -7624,7 +7623,7 @@ dependencies = [ "assert_matches", "criterion", "derive_more", - "futures 0.3.9", + "futures 0.3.10", "linked-hash-map", "log", "parity-scale-codec", @@ -7647,7 +7646,7 @@ name = "sc-transaction-pool" version = "2.0.1" dependencies = [ "assert_matches", - "futures 0.3.9", + "futures 0.3.10", "futures-diagnose", "hex", "intervalier", @@ -7692,14 +7691,14 @@ checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" dependencies = [ "arrayref", "arrayvec 0.5.2", - "curve25519-dalek 2.1.2", - "getrandom 0.1.16", + "curve25519-dalek 2.1.0", + "getrandom 0.1.15", "merlin", "rand 0.7.3", "rand_core 0.5.1", "serde", "sha2 0.8.2", - "subtle 2.4.0", + "subtle 2.3.0", "zeroize", ] @@ -7801,7 +7800,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver-parser 0.10.0", + "semver-parser 0.10.1", "serde", ] @@ -7813,12 +7812,11 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "semver-parser" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e012c6c5380fb91897ba7b9261a0f565e624e869d42fe1a1d03fa0d68a083d5" +checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428" dependencies = [ "pest", - "pest_derive", ] [[package]] @@ -7835,9 +7833,9 @@ checksum = "930c0acf610d3fdb5e2ab6213019aaa04e227ebe9547b0649ba599b16d788bd7" [[package]] name = "serde" -version = "1.0.119" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bdd36f49e35b61d49efd8aa7fc068fd295961fd2286d0b2ee9a4c7a14e99cc3" +checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" dependencies = [ "serde_derive", ] @@ -7854,9 +7852,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.119" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552954ce79a059ddd5fd68c271592374bd15cab2274970380c000118aeffe1cd" +checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" dependencies = [ "proc-macro2", "quote", @@ -7865,9 +7863,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.61" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" dependencies = [ "itoa", "ryu", @@ -7894,7 +7892,7 @@ checksum = "ce3cdf1b5e620a498ee6f2a171885ac7e22f0e12089ec4b3d22b84921792507c" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpuid-bool 0.1.2", + "cpuid-bool", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -7919,7 +7917,7 @@ checksum = "6e7aab86fe2149bad8c507606bdb3f4ef5e7b2380eb92350f56122cca72a42a8" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpuid-bool 0.1.2", + "cpuid-bool", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -7938,11 +7936,12 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3" +checksum = "7b4921be914e16899a80adefb821f8ddb7974e3f1250223575a44ed994882127" dependencies = [ "lazy_static", + "loom", ] [[package]] @@ -7951,30 +7950,20 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" -[[package]] -name = "signal-hook" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" -version = "1.3.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" dependencies = [ "libc", ] [[package]] name = "signature" -version = "1.3.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0242b8e50dd9accdd56170e94ca1ebd223b098eb9c83539a6e367d0f36ae68" +checksum = "29f060a7d147e33490ec10da418795238fd7545bba241504d6b31a409f2e6210" [[package]] name = "simba" @@ -7996,9 +7985,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "slog" -version = "2.7.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" +checksum = "1cc9c640a4adbfbcc11ffb95efe5aa7af7309e002adab54b185507dbf2377b99" dependencies = [ "erased-serde", ] @@ -8049,9 +8038,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.6.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0" +checksum = "7acad6f34eb9e8a259d3283d1e8c1d34d7415943d4895f65cc73813c7396fc85" [[package]] name = "snow" @@ -8067,18 +8056,19 @@ dependencies = [ "ring", "rustc_version", "sha2 0.9.2", - "subtle 2.4.0", + "subtle 2.3.0", "x25519-dalek", ] [[package]] name = "socket2" -version = "0.3.19" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +checksum = "2c29947abdee2a218277abeca306f25789c938e500ea5a9d4b12a5a504466902" dependencies = [ "cfg-if 1.0.0", "libc", + "redox_syscall", "winapi 0.3.9", ] @@ -8091,7 +8081,7 @@ dependencies = [ "base64 0.12.3", "bytes 0.5.6", "flate2", - "futures 0.3.9", + "futures 0.3.10", "httparse", "log", "rand 0.7.3", @@ -8241,7 +8231,7 @@ dependencies = [ name = "sp-blockchain" version = "2.0.1" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "log", "lru", "parity-scale-codec", @@ -8266,7 +8256,7 @@ dependencies = [ name = "sp-consensus" version = "0.8.1" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "libp2p", "log", @@ -8360,7 +8350,7 @@ dependencies = [ "criterion", "dyn-clonable", "ed25519-dalek", - "futures 0.3.9", + "futures 0.3.10", "hash-db", "hash256-std-hasher", "hex", @@ -8468,7 +8458,7 @@ dependencies = [ name = "sp-io" version = "2.0.1" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "hash-db", "libsecp256k1", "log", @@ -8503,7 +8493,7 @@ version = "0.8.0" dependencies = [ "async-trait", "derive_more", - "futures 0.3.9", + "futures 0.3.10", "merlin", "parity-scale-codec", "parking_lot 0.11.1", @@ -8725,7 +8715,7 @@ dependencies = [ "parking_lot 0.11.1", "pretty_assertions", "rand 0.7.3", - "smallvec 1.6.0", + "smallvec 1.5.0", "sp-core", "sp-externalities", "sp-panic-handler", @@ -8808,7 +8798,7 @@ name = "sp-transaction-pool" version = "2.0.1" dependencies = [ "derive_more", - "futures 0.3.9", + "futures 0.3.10", "log", "parity-scale-codec", "serde", @@ -8840,7 +8830,7 @@ dependencies = [ name = "sp-utils" version = "2.0.1" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "futures-core", "futures-timer 3.0.2", "lazy_static", @@ -8922,9 +8912,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.21" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" +checksum = "126d630294ec449fae0b16f964e35bf3c74f940da9dca17ee9b905f7b3112eb8" dependencies = [ "clap", "lazy_static", @@ -8933,9 +8923,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.14" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +checksum = "65e51c492f9e23a220534971ff5afc14037289de430e3c83f9daf6a1b6ae91e8" dependencies = [ "heck", "proc-macro-error", @@ -8994,7 +8984,7 @@ dependencies = [ "console_error_panic_hook", "console_log", "futures 0.1.30", - "futures 0.3.9", + "futures 0.3.10", "futures-timer 3.0.2", "getrandom 0.2.1", "js-sys", @@ -9035,14 +9025,14 @@ version = "2.0.1" dependencies = [ "frame-support", "frame-system", - "futures 0.3.9", + "futures 0.3.10", "jsonrpc-client-transports", "jsonrpc-core", "parity-scale-codec", "sc-rpc-api", "serde", "sp-storage", - "tokio 0.2.24", + "tokio 0.2.23", ] [[package]] @@ -9050,7 +9040,7 @@ name = "substrate-frame-rpc-system" version = "2.0.1" dependencies = [ "frame-system-rpc-runtime-api", - "futures 0.3.9", + "futures 0.3.10", "jsonrpc-core", "jsonrpc-core-client", "jsonrpc-derive", @@ -9080,7 +9070,7 @@ dependencies = [ "hyper 0.13.9", "log", "prometheus", - "tokio 0.2.24", + "tokio 0.2.23", ] [[package]] @@ -9088,7 +9078,7 @@ name = "substrate-test-client" version = "2.0.1" dependencies = [ "futures 0.1.30", - "futures 0.3.9", + "futures 0.3.10", "hash-db", "hex", "parity-scale-codec", @@ -9157,7 +9147,7 @@ dependencies = [ name = "substrate-test-runtime-client" version = "2.0.0" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "parity-scale-codec", "sc-block-builder", "sc-client-api", @@ -9178,7 +9168,7 @@ name = "substrate-test-runtime-transaction-pool" version = "2.0.0" dependencies = [ "derive_more", - "futures 0.3.9", + "futures 0.3.10", "parity-scale-codec", "parking_lot 0.11.1", "sc-transaction-graph", @@ -9192,10 +9182,10 @@ dependencies = [ name = "substrate-test-utils" version = "2.0.1" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "sc-service", "substrate-test-utils-derive", - "tokio 0.2.24", + "tokio 0.2.23", "trybuild", ] @@ -9214,7 +9204,7 @@ version = "0.1.0" dependencies = [ "sc-service", "substrate-test-utils", - "tokio 0.2.24", + "tokio 0.2.23", ] [[package]] @@ -9239,9 +9229,9 @@ checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "subtle" -version = "2.4.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" +checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd" [[package]] name = "syn" @@ -9294,9 +9284,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "bf11676eb135389f21fcda654382c4859bbfc1d2f36e4425a2f829bb41b1e20e" dependencies = [ "winapi-util", ] @@ -9312,18 +9302,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.23" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" +checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.23" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" +checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56" dependencies = [ "proc-macro2", "quote", @@ -9332,9 +9322,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" dependencies = [ "lazy_static", ] @@ -9350,11 +9340,12 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi 0.3.9", ] @@ -9387,9 +9378,9 @@ dependencies = [ [[package]] name = "tinytemplate" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ada8616fad06a2d0c455adc530de4ef57605a8120cc65da9653e0e9623ca74" +checksum = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f" dependencies = [ "serde", "serde_json", @@ -9397,9 +9388,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.1.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +checksum = "b78a366903f506d2ad52ca8dc552102ffdd3e937ba8a227f024dc1d1eae28575" dependencies = [ "tinyvec_macros", ] @@ -9436,9 +9427,9 @@ dependencies = [ [[package]] name = "tokio" -version = "0.2.24" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099837d3464c16a808060bb3f02263b412f6fafcb5d01c533d309985fbeebe48" +checksum = "a6d7ad61edd59bfcc7e80dababf0f4aed2e6d5e0ba1659356ae889752dfc12ff" dependencies = [ "bytes 0.5.6", "fnv", @@ -9572,7 +9563,7 @@ checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a" dependencies = [ "futures-core", "rustls 0.18.1", - "tokio 0.2.24", + "tokio 0.2.23", "webpki", ] @@ -9682,14 +9673,14 @@ dependencies = [ "futures-sink", "log", "pin-project-lite 0.1.11", - "tokio 0.2.24", + "tokio 0.2.23", ] [[package]] name = "toml" -version = "0.5.8" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" dependencies = [ "serde", ] @@ -9708,7 +9699,7 @@ checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" dependencies = [ "cfg-if 1.0.0", "log", - "pin-project-lite 0.2.1", + "pin-project-lite 0.2.4", "tracing-attributes", "tracing-core", ] @@ -9778,7 +9769,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec 1.6.0", + "smallvec 1.5.0", "thread_local", "tracing", "tracing-core", @@ -9818,7 +9809,7 @@ dependencies = [ "hashbrown", "log", "rustc-hex", - "smallvec 1.6.0", + "smallvec 1.5.0", ] [[package]] @@ -9937,9 +9928,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "db8716a166f290ff49dabc18b44aa407cb7c6dbe1aa0971b44b8a24b0ca35aae" [[package]] name = "unicode-width" @@ -9960,7 +9951,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" dependencies = [ "generic-array 0.14.4", - "subtle 2.4.0", + "subtle 2.3.0", ] [[package]] @@ -10006,9 +9997,9 @@ dependencies = [ [[package]] name = "vcpkg" -version = "0.2.11" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" +checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" [[package]] name = "vec-arena" @@ -10089,9 +10080,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.1+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" @@ -10122,11 +10113,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.19" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe9756085a84584ee9457a002b7cdfe0bfff169f45d2591d8be1345a6780e35" +checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", "js-sys", "wasm-bindgen", "web-sys", @@ -10163,9 +10154,9 @@ checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" [[package]] name = "wasm-bindgen-test" -version = "0.3.19" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0355fa0c1f9b792a09b6dcb6a8be24d51e71e6d74972f9eb4a44c4c004d24a25" +checksum = "34d1cdc8b98a557f24733d50a1199c4b0635e465eecba9c45b214544da197f64" dependencies = [ "console_error_panic_hook", "js-sys", @@ -10177,9 +10168,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.19" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e07b46b98024c2ba2f9e83a10c2ef0515f057f2da299c1762a2017de80438b" +checksum = "e8fb9c67be7439ee8ab1b7db502a49c05e51e2835b66796c705134d9b8e1a585" dependencies = [ "proc-macro2", "quote", @@ -10202,7 +10193,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "js-sys", "parking_lot 0.11.1", "pin-utils", @@ -10261,7 +10252,7 @@ dependencies = [ "log", "region", "rustc-demangle", - "smallvec 1.6.0", + "smallvec 1.5.0", "target-lexicon", "wasmparser 0.59.0", "wasmtime-environ", @@ -10394,7 +10385,7 @@ dependencies = [ "lazy_static", "libc", "log", - "memoffset 0.5.6", + "memoffset", "more-asserts", "region", "thiserror", @@ -10404,18 +10395,18 @@ dependencies = [ [[package]] name = "wast" -version = "30.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b79907b22f740634810e882d8d1d9d0f9563095a8ab94e786e370242bff5cd2" +checksum = "c2c3ef5f6a72dffa44c24d5811123f704e18a1dbc83637d347b1852b41d3835c" dependencies = [ "leb128", ] [[package]] name = "wat" -version = "1.0.31" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8279a02835bf12e61ed2b3c3cbc6ecf9918762fd97e036917c11a09ec20ca44" +checksum = "835cf59c907f67e2bbc20f50157e08f35006fe2a8444d8ec9f5683e22f937045" dependencies = [ "wast", ] @@ -10432,9 +10423,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.21.4" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +checksum = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae" dependencies = [ "ring", "untrusted", @@ -10526,7 +10517,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc614d95359fd7afc321b66d2107ede58b246b844cf5d8a0adcca413e439f088" dependencies = [ - "curve25519-dalek 3.0.2", + "curve25519-dalek 3.0.0", "rand_core 0.5.1", "zeroize", ] @@ -10537,7 +10528,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aeb8c4043cac71c3c299dff107171c220d179492350ea198e109a414981b83c" dependencies = [ - "futures 0.3.9", + "futures 0.3.10", "log", "nohash-hasher", "parking_lot 0.11.1", @@ -10568,18 +10559,18 @@ dependencies = [ [[package]] name = "zstd" -version = "0.5.4+zstd.1.4.7" +version = "0.5.3+zstd.1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69996ebdb1ba8b1517f61387a883857818a66c8a295f487b1ffd8fd9d2c82910" +checksum = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "2.0.6+zstd.1.4.7" +version = "2.0.5+zstd.1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98aa931fb69ecee256d44589d19754e61851ae4769bf963b385119b1cc37a49e" +checksum = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055" dependencies = [ "libc", "zstd-sys", @@ -10587,9 +10578,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.4.18+zstd.1.4.7" +version = "1.4.17+zstd.1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e6e8778706838f43f771d80d37787cb2fe06dafe89dd3aebaf6721b9eaec81" +checksum = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b" dependencies = [ "cc", "glob", diff --git a/client/consensus/babe/src/authorship.rs b/client/consensus/babe/src/authorship.rs index 11bca37feaf3c..90ad12c4558c8 100644 --- a/client/consensus/babe/src/authorship.rs +++ b/client/consensus/babe/src/authorship.rs @@ -114,7 +114,6 @@ pub(super) fn secondary_slot_author( return None; } - dbg!((randomness, slot_number).using_encoded(blake2_256)); let rand = U256::from((randomness, slot_number).using_encoded(blake2_256)); let authorities_len = U256::from(authorities.len()); diff --git a/frame/two-phase-election-provider/src/lib.rs b/frame/two-phase-election-provider/src/lib.rs index 3f4e4e6a0962a..4c0a53f417f0c 100644 --- a/frame/two-phase-election-provider/src/lib.rs +++ b/frame/two-phase-election-provider/src/lib.rs @@ -1182,7 +1182,7 @@ where }) .map_err(|err| { Self::deposit_event(Event::ElectionFinalized(None)); - log!(error, "Failed to finalize election round. Error = {:?}", err); + log!(warn, "Failed to finalize election round. reason {:?}", err); err }) } From 56bb93c415a7f8439b71ab35e9f04c9922d87a57 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 14 Jan 2021 11:02:53 +0000 Subject: [PATCH 53/62] revamp closures. --- frame/staking/src/lib.rs | 12 +- .../src/benchmarking.rs | 11 +- .../src/helpers.rs | 208 ++++++++++++++++++ frame/two-phase-election-provider/src/lib.rs | 22 +- .../two-phase-election-provider/src/macros.rs | 165 -------------- frame/two-phase-election-provider/src/mock.rs | 7 +- .../src/unsigned.rs | 11 +- 7 files changed, 245 insertions(+), 191 deletions(-) create mode 100644 frame/two-phase-election-provider/src/helpers.rs delete mode 100644 frame/two-phase-election-provider/src/macros.rs diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index ce72dd1bdaf62..a01694f13864d 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -1083,37 +1083,37 @@ decl_storage! { /// Snapshot of validators at the beginning of the current election window. This should only /// have a value when [`EraElectionStatus`] == `ElectionStatus::Open(_)`. /// - /// DEPRECATED. + /// TODO: TWO_PHASE: should be removed once we switch to two-phase. pub SnapshotValidators get(fn snapshot_validators): Option>; /// Snapshot of nominators at the beginning of the current election window. This should only /// have a value when [`EraElectionStatus`] == `ElectionStatus::Open(_)`. /// - /// DEPRECATED. + /// TODO: TWO_PHASE: should be removed once we switch to two-phase. pub SnapshotNominators get(fn snapshot_nominators): Option>; /// The next validator set. At the end of an era, if this is available (potentially from the /// result of an offchain worker), it is immediately used. Otherwise, the on-chain election /// is executed. /// - /// DEPRECATED. + /// TODO: TWO_PHASE: should be removed once we switch to two-phase. pub QueuedElected get(fn queued_elected): Option>>; /// The score of the current [`QueuedElected`]. /// - /// DEPRECATED. + /// TODO: TWO_PHASE: should be removed once we switch to two-phase. pub QueuedScore get(fn queued_score): Option; /// Flag to control the execution of the offchain election. When `Open(_)`, we accept /// solutions to be submitted. /// - /// DEPRECATED. + /// TODO: TWO_PHASE: should be removed once we switch to two-phase. pub EraElectionStatus get(fn era_election_status): ElectionStatus; /// True if the current **planned** session is final. Note that this does not take era /// forcing into account. /// - /// DEPRECATED. + /// TODO: TWO_PHASE: should be removed once we switch to two-phase. pub IsCurrentSessionFinal get(fn is_current_session_final): bool = false; /// True if network has been upgraded to this version. diff --git a/frame/two-phase-election-provider/src/benchmarking.rs b/frame/two-phase-election-provider/src/benchmarking.rs index 8804f7654c372..c10ee172a8328 100644 --- a/frame/two-phase-election-provider/src/benchmarking.rs +++ b/frame/two-phase-election-provider/src/benchmarking.rs @@ -127,11 +127,12 @@ where // write the snapshot to staking or whoever is the data provider. T::DataProvider::put_snapshot(all_voters.clone(), targets.clone()); - crate::stake_of_fn!(let stake_of, all_voters, T); - crate::voter_index_fn!(let voter_index, all_voters, T); - crate::voter_at_fn!(let voter_at, all_voters, T); - crate::target_at_fn!(let target_at, targets, T); - crate::target_index_fn!(let target_index, targets, T); + let cache = helpers::generate_voter_cache::(&all_voters); + let stake_of = helpers::stake_of_fn::(&all_voters, &cache); + let voter_index = helpers::voter_index_fn::(&cache); + let target_index = helpers::target_index_fn_linear::(&targets); + let voter_at = helpers::voter_at_fn::(&all_voters); + let target_at = helpers::target_at_fn::(&targets); let assignments = active_voters .iter() diff --git a/frame/two-phase-election-provider/src/helpers.rs b/frame/two-phase-election-provider/src/helpers.rs new file mode 100644 index 0000000000000..10f7cf9605c38 --- /dev/null +++ b/frame/two-phase-election-provider/src/helpers.rs @@ -0,0 +1,208 @@ +// This file is part of Substrate. + +// Copyright (C) 2020 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 +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Some helper functions/macros for this crate. + +use super::{ + Config, VoteWeight, CompactVoterIndexOf, CompactTargetIndexOf, CompactAccuracyOf, + OnChainAccuracyOf, ExtendedBalance, +}; +use sp_runtime::InnerOf; +use sp_std::{collections::btree_map::BTreeMap, convert::TryInto}; + +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + frame_support::debug::$level!( + target: $crate::LOG_TARGET, + concat!("🏦 ", $patter) $(, $values)* + ) + }; +} + +/// Generate a btree-map cache of the voters and their indices. +/// +/// This can be used to efficiently build index getter closures. +pub fn generate_voter_cache( + snapshot: &Vec<(T::AccountId, VoteWeight, Vec)>, +) -> BTreeMap +where + ExtendedBalance: From>>, + ExtendedBalance: From>>, +{ + let mut cache: BTreeMap = BTreeMap::new(); + snapshot.iter().enumerate().for_each(|(i, (x, _, _))| { + let _existed = cache.insert(x.clone(), i); + // if a duplicate exists, we only consider the last one. Defensive only, should never happen. + debug_assert!(_existed.is_none()); + }); + + cache +} + +/// Create a function the returns the index a voter in the snapshot. +/// +/// The returning index type is the same as the one defined in [`T::CompactSolution::Voter`]. +/// +/// ## Warning +/// +/// The snapshot must be the same is the one used to create `cache`. +pub fn voter_index_fn( + cache: &BTreeMap, +) -> Box Option> + '_> +where + ExtendedBalance: From>>, + ExtendedBalance: From>>, +{ + Box::new(move |who| { + cache + .get(who) + .and_then(|i| >>::try_into(*i).ok()) + }) +} + +/// Same as [`voter_index_fn`], but the returning index is converted into usize, if possible. +/// +/// ## Warning +/// +/// The snapshot must be the same is the one used to create `cache`. +pub fn voter_index_fn_usize( + cache: &BTreeMap, +) -> Box Option + '_> +where + ExtendedBalance: From>>, + ExtendedBalance: From>>, +{ + Box::new(move |who| cache.get(who).cloned()) +} + +/// A non-optimized, linear version of [`voter_index_fn`] that does not need a cache and does a +/// linear search. +/// +/// ## Warning +/// +/// Not meant to be used in production. +pub fn voter_index_fn_linear( + snapshot: &Vec<(T::AccountId, VoteWeight, Vec)>, +) -> Box Option> + '_> +where + ExtendedBalance: From>>, + ExtendedBalance: From>>, +{ + Box::new(move |who| { + snapshot + .iter() + .position(|(x, _, _)| x == who) + .and_then(|i| >>::try_into(i).ok()) + }) +} + +/// Create a function the returns the index a targets in the snapshot. +/// +/// The returning index type is the same as the one defined in [`T::CompactSolution::Target`]. +pub fn target_index_fn_linear( + snapshot: &Vec, +) -> Box Option> + '_> +where + ExtendedBalance: From>>, + ExtendedBalance: From>>, +{ + Box::new(move |who| { + snapshot + .iter() + .position(|x| x == who) + .and_then(|i| >>::try_into(i).ok()) + }) +} + +/// Create a function that can map a voter index ([`CompactVoterIndexOf`]) to the actual voter +/// account using a linearly indexible snapshot. +pub fn voter_at_fn( + snapshot: &Vec<(T::AccountId, VoteWeight, Vec)>, +) -> Box) -> Option + '_> +where + ExtendedBalance: From>>, + ExtendedBalance: From>>, +{ + Box::new(move |i| { + as TryInto>::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 +/// account using a linearly indexible snapshot. +pub fn target_at_fn( + snapshot: &Vec, +) -> Box) -> Option + '_> +where + ExtendedBalance: From>>, + ExtendedBalance: From>>, +{ + Box::new(move |i| { + as TryInto>::try_into(i) + .ok() + .and_then(|i| snapshot.get(i).cloned()) + }) +} + +/// Create a function to get the stake of a voter. +/// +/// This is not optimized and uses a linear search. +pub fn stake_of_fn_linear( + snapshot: &Vec<(T::AccountId, VoteWeight, Vec)>, +) -> Box VoteWeight + '_> +where + ExtendedBalance: From>>, + ExtendedBalance: From>>, +{ + Box::new(move |who| { + snapshot + .iter() + .find(|(x, _, _)| x == who) + .map(|(_, x, _)| *x) + .unwrap_or_default() + }) +} + +/// Create a function to get the stake of a voter. +/// +/// ## Warning +/// +/// The cache need must be derived from the same snapshot. Zero is returned if a voter is +/// non-existent. +pub fn stake_of_fn<'a, T: Config>( + snapshot: &'a Vec<(T::AccountId, VoteWeight, Vec)>, + cache: &'a BTreeMap, +) -> Box VoteWeight + 'a> +where + ExtendedBalance: From>>, + ExtendedBalance: From>>, +{ + Box::new(move |who| { + if let Some(index) = cache.get(who) { + snapshot + .get(*index) + .map(|(_, x, _)| x) + .cloned() + .unwrap_or_default() + } else { + 0 + } + }) +} diff --git a/frame/two-phase-election-provider/src/lib.rs b/frame/two-phase-election-provider/src/lib.rs index 4c0a53f417f0c..3cd9794d8b8a0 100644 --- a/frame/two-phase-election-provider/src/lib.rs +++ b/frame/two-phase-election-provider/src/lib.rs @@ -202,7 +202,7 @@ mod benchmarking; #[cfg(test)] mod mock; #[macro_use] -pub(crate) mod macros; +pub mod helpers; const LOG_TARGET: &'static str = "election-provider"; @@ -634,8 +634,15 @@ pub mod pallet { } fn integrity_test() { - let max_vote: usize = as CompactSolution>::LIMIT; + use sp_std::mem::size_of; + // The index type of both voters and targets need to be smaller than that of usize (very + // unlikely to be the case, but anyhow). + assert!(size_of::>() <= size_of::()); + assert!(size_of::>() <= size_of::()); + + // ---------------------------- // based on the requirements of [`sp_npos_elections::Assignment::try_normalize`]. + let max_vote: usize = as CompactSolution>::LIMIT; // 1. Maximum sum of [ChainAccuracy; 16] must fit into `UpperOf`.. let maximum_chain_accuracy: Vec>> = (0..max_vote) @@ -1064,9 +1071,10 @@ where } = Self::snapshot().ok_or(FeasibilityError::SnapshotUnavailable)?; // ----- Start building. First, we need some closures. - crate::voter_at_fn!(let voter_at , snapshot_voters, T); - crate::target_at_fn!(let target_at, snapshot_targets, T); - crate::voter_index_fn_usize!(let voter_index, snapshot_voters, T); + let cache = helpers::generate_voter_cache::(&snapshot_voters); + let voter_at = helpers::voter_at_fn::(&snapshot_voters); + let target_at = helpers::target_at_fn::(&snapshot_targets); + let voter_index = helpers::voter_index_fn_usize::(&cache); // first, make sure that all the winners are sane. let winners = winners @@ -1106,8 +1114,8 @@ where }) .collect::>()?; - // ----- Start building support. First, we need some more closures. - stake_of_fn!(let stake_of, snapshot_voters, T); + // ----- Start building support. First, we need one more closure. + let stake_of = helpers::stake_of_fn::(&snapshot_voters, &cache); // This might fail if the normalization fails. Very unlikely. See `integrity_test`. let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) diff --git a/frame/two-phase-election-provider/src/macros.rs b/frame/two-phase-election-provider/src/macros.rs deleted file mode 100644 index ed4428d764d66..0000000000000 --- a/frame/two-phase-election-provider/src/macros.rs +++ /dev/null @@ -1,165 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2020 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 -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Some helper functions/macros for this crate. - -#[macro_export] -macro_rules! log { - ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { - frame_support::debug::$level!( - target: $crate::LOG_TARGET, - concat!("🏦 ", $patter) $(, $values)* - ) - }; -} - -#[deprecated = "May only be used for benchmarking purposes."] -#[macro_export] -macro_rules! voter_index_fn_linear { - (let $name:ident, $voters:ident, $t:ident) => { - let $name = |who: &<$t as frame_system::Config>::AccountId| -> Option<$crate::CompactVoterIndexOf<$t>> { - $voters - .iter() - .position(|(x, _, _)| x == who) - .and_then(|i| >>::try_into(i).ok()) - }; - }; -} - -#[macro_export] -macro_rules! voter_index_generate_cache { - ($name:ident, $voters:ident, $t:ident) => { - let mut $name: - $crate::sp_std::collections::btree_map::BTreeMap< - <$t as frame_system::Config>::AccountId, - usize - > - = $crate::sp_std::collections::btree_map::BTreeMap::new(); - $voters.iter().enumerate().for_each(|(i, (x, _, _))| { - let _existed = $name.insert(x.clone(), i); - // if a duplicate exists, we only consider the last one. Defensive only, should never happen. - debug_assert!(_existed.is_none()); - }); - }; -} - -#[macro_export] -macro_rules! voter_index_fn { - (let $name:ident, $voters:ident, $t:ident) => { - voter_index_generate_cache!(voters_map, $voters, $t); - let $name = |who: &<$t as frame_system::Config>::AccountId| -> Option> { - voters_map - .get(who) - .and_then(|i| >>::try_into(*i).ok()) - }; - }; -} - -#[macro_export] -macro_rules! voter_index_fn_usize { - (let $name:ident, $voters:ident, $t:ident) => { - voter_index_generate_cache!(voters_map, $voters, $t); - let $name = |who: &<$t as frame_system::Config>::AccountId| -> Option { - voters_map.get(who).cloned() - }; - }; -} - -#[macro_export] -macro_rules! target_index_fn { - (let $name: ident, $targets:ident, $t:ident) => { - let $name = |who: &<$t as frame_system::Config>::AccountId| -> Option<$crate::CompactTargetIndexOf<$t>> { - $targets - .iter() - .position(|x| x == who) - .and_then(|i| - < - usize - as - $crate::sp_std::convert::TryInto<$crate::CompactTargetIndexOf<$t>> - >::try_into(i).ok() - ) - }; - }; -} - -#[macro_export] -macro_rules! voter_at_fn { - (let $name:ident, $snap:ident, $t:ident) => { - let $name = |i: $crate::CompactVoterIndexOf<$t>| -> Option<<$t as frame_system::Config>::AccountId> { - <$crate::CompactVoterIndexOf<$t> as $crate::sp_std::convert::TryInto>::try_into(i) - .ok() - .and_then(|i| $snap - .get(i) - .map(|(x, _, _)| x) - .cloned() - ) - }; - }; -} - -#[macro_export] -macro_rules! target_at_fn { - (let $name:ident, $snap:ident, $t:ident) => { - let $name = |i: $crate::CompactTargetIndexOf<$t>| -> Option<<$t as frame_system::Config>::AccountId> { - < - $crate::CompactTargetIndexOf<$t> - as - $crate::sp_std::convert::TryInto - >::try_into(i) - .ok() - .and_then(|i| $snap.get(i).cloned()) - }; - }; -} - -#[deprecated = "May only be used for benchmarking purposes."] -#[macro_export] -macro_rules! stake_of_fn_linear { - (let $name:ident, $voters:ident, $t:ty) => { - let $name = |who: &<$t as frame_system::Config>::AccountId| -> $crate::VoteWeight { - $voters - .iter() - .find(|(x, _, _)| x == who) - .map(|(_, x, _)| *x) - .unwrap_or_default() - }; - }; -} - -#[macro_export] -macro_rules! stake_of_fn { - (let $name:ident, $voters:ident, $t:ty) => { - let mut stake_map: - $crate::sp_std::collections::btree_map::BTreeMap< - <$t as frame_system::Config>::AccountId, - VoteWeight, - > - = $crate::sp_std::collections::btree_map::BTreeMap::new(); - $voters.iter().for_each(|(x, y, _)| { - let _existed = stake_map.insert(x.clone(), *y); - // if a duplicate exists, we only consider the last one. Defensive only, should never happen. - debug_assert!(_existed.is_none()); - }); - let $name = |who: &<$t as frame_system::Config>::AccountId| -> $crate::VoteWeight { - stake_map - .get(who) - .cloned() - .unwrap_or_default() - }; - }; -} diff --git a/frame/two-phase-election-provider/src/mock.rs b/frame/two-phase-election-provider/src/mock.rs index ece085ba6a611..e2c37fbcd1b4a 100644 --- a/frame/two-phase-election-provider/src/mock.rs +++ b/frame/two-phase-election-provider/src/mock.rs @@ -115,9 +115,10 @@ pub fn raw_solution() -> RawSolution> { let desired_targets = TwoPhase::desired_targets().unwrap(); // closures - crate::voter_index_fn!(let voter_index, voters, Runtime); - crate::target_index_fn!(let target_index, targets, Runtime); - crate::stake_of_fn!(let stake_of, voters, Runtime); + let cache = helpers::generate_voter_cache::(&voters); + let voter_index = helpers::voter_index_fn_linear::(&voters); + let target_index = helpers::target_index_fn_linear::(&targets); + let stake_of = helpers::stake_of_fn::(&voters, &cache); let ElectionResult { winners, diff --git a/frame/two-phase-election-provider/src/unsigned.rs b/frame/two-phase-election-provider/src/unsigned.rs index 522f21be9effa..3713ba080dc94 100644 --- a/frame/two-phase-election-provider/src/unsigned.rs +++ b/frame/two-phase-election-provider/src/unsigned.rs @@ -73,11 +73,12 @@ where let desired_targets = Self::desired_targets().ok_or(ElectionError::SnapshotUnAvailable)?; // closures. - crate::voter_index_fn!(let voter_index, voters, T); - crate::target_index_fn!(let target_index, targets, T); - crate::voter_at_fn!(let voter_at, voters, T); - crate::target_at_fn!(let target_at, targets, T); - crate::stake_of_fn!(let stake_of, voters, T); + let cache = helpers::generate_voter_cache::(&voters); + let voter_index = helpers::voter_index_fn::(&cache); + let target_index = helpers::target_index_fn_linear::(&targets); + let voter_at = helpers::voter_at_fn::(&voters); + let target_at = helpers::target_at_fn::(&targets); + let stake_of = helpers::stake_of_fn::(&voters, &cache); let ElectionResult { assignments, From 257795c618cf02a82a5bee206f1cb166b51a7550 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 14 Jan 2021 13:54:58 +0000 Subject: [PATCH 54/62] Update frame/two-phase-election-provider/src/benchmarking.rs Co-authored-by: Shawn Tabrizi --- frame/two-phase-election-provider/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/two-phase-election-provider/src/benchmarking.rs b/frame/two-phase-election-provider/src/benchmarking.rs index c10ee172a8328..bab11a0dfb576 100644 --- a/frame/two-phase-election-provider/src/benchmarking.rs +++ b/frame/two-phase-election-provider/src/benchmarking.rs @@ -243,7 +243,7 @@ benchmarks! { let c in 1 .. (T::MaxSignedSubmissions::get() - 1); // the solution will be worse than all of them meaning the score need to be checked against all. - let solution = RawSolution { score: [(1000_0000u128 - 1).into(), 0, 0], ..Default::default() }; + let solution = RawSolution { score: [(10_000_000u128 - 1).into(), 0, 0], ..Default::default() }; >::put(Phase::Signed); >::put(1); From 1ac97f5c69cb77dd65429efaf4faaee019e04744 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 14 Jan 2021 17:19:49 +0000 Subject: [PATCH 55/62] Some review grumbles. --- bin/node/runtime/src/lib.rs | 4 ++- frame/staking/Cargo.toml | 2 +- frame/staking/src/lib.rs | 21 ++++++----- frame/staking/src/tests.rs | 2 -- .../src/benchmarking.rs | 30 +++++++--------- frame/two-phase-election-provider/src/lib.rs | 35 ++++++++++++++++--- frame/two-phase-election-provider/src/mock.rs | 1 + .../two-phase-election-provider/src/signed.rs | 21 ++--------- 8 files changed, 61 insertions(+), 55 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index fcfa8280c73f1..3e45e6bd9b161 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -514,7 +514,8 @@ parameter_types! { pub const SignedDepositByte: Balance = 1 * CENTS; // fallback: no need to do on-chain phragmen initially. - pub const Fallback: pallet_two_phase_election_provider::FallbackStrategy = pallet_two_phase_election_provider::FallbackStrategy::Nothing; + pub const Fallback: pallet_two_phase_election_provider::FallbackStrategy = + pallet_two_phase_election_provider::FallbackStrategy::Nothing; // unsigned configs pub const TwoPhaseUnsignedPriority: TransactionPriority = StakingUnsignedPriority::get() - 1u64; @@ -549,6 +550,7 @@ impl pallet_two_phase_election_provider::Config for Runtime { type CompactSolution = pallet_staking::CompactAssignments; type Fallback = Fallback; type WeightInfo = pallet_two_phase_election_provider::weights::SubstrateWeight; + type BenchmarkingConfig = (); } parameter_types! { diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 7df188759153f..93ec34025bd1e 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -17,7 +17,7 @@ static_assertions = "1.1.0" serde = { version = "1.0.101", optional = true } codec = { package = "parity-scale-codec", version = "1.3.6", default-features = false, features = ["derive"] } sp-std = { version = "2.0.0", default-features = false, path = "../../primitives/std" } -# TODO: TWO_PHASE:: ideally we should be able to get rid of this. +# TWO_PHASE_NOTE:: ideally we should be able to get rid of this. sp-npos-elections = { version = "2.0.0", default-features = false, path = "../../primitives/npos-elections" } sp-io ={ version = "2.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "2.0.0", default-features = false, path = "../../primitives/runtime" } diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index a01694f13864d..3ba210b6e2612 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -1077,43 +1077,42 @@ decl_storage! { /// The last planned session scheduled by the session pallet. /// /// This is basically in sync with the call to [`SessionManager::new_session`]. - /// TODO: TWO_PHASE: needs care to set the initial value upon migration. pub CurrentPlannedSession get(fn current_planned_session): SessionIndex; /// Snapshot of validators at the beginning of the current election window. This should only /// have a value when [`EraElectionStatus`] == `ElectionStatus::Open(_)`. /// - /// TODO: TWO_PHASE: should be removed once we switch to two-phase. + /// TWO_PHASE_NOTE: should be removed once we switch to two-phase. pub SnapshotValidators get(fn snapshot_validators): Option>; /// Snapshot of nominators at the beginning of the current election window. This should only /// have a value when [`EraElectionStatus`] == `ElectionStatus::Open(_)`. /// - /// TODO: TWO_PHASE: should be removed once we switch to two-phase. + /// TWO_PHASE_NOTE: should be removed once we switch to two-phase. pub SnapshotNominators get(fn snapshot_nominators): Option>; /// The next validator set. At the end of an era, if this is available (potentially from the /// result of an offchain worker), it is immediately used. Otherwise, the on-chain election /// is executed. /// - /// TODO: TWO_PHASE: should be removed once we switch to two-phase. + /// TWO_PHASE_NOTE: should be removed once we switch to two-phase. pub QueuedElected get(fn queued_elected): Option>>; /// The score of the current [`QueuedElected`]. /// - /// TODO: TWO_PHASE: should be removed once we switch to two-phase. + /// TWO_PHASE_NOTE: should be removed once we switch to two-phase. pub QueuedScore get(fn queued_score): Option; /// Flag to control the execution of the offchain election. When `Open(_)`, we accept /// solutions to be submitted. /// - /// TODO: TWO_PHASE: should be removed once we switch to two-phase. + /// TWO_PHASE_NOTE: should be removed once we switch to two-phase. pub EraElectionStatus get(fn era_election_status): ElectionStatus; /// True if the current **planned** session is final. Note that this does not take era /// forcing into account. /// - /// TODO: TWO_PHASE: should be removed once we switch to two-phase. + /// TWO_PHASE_NOTE: should be removed once we switch to two-phase. pub IsCurrentSessionFinal get(fn is_current_session_final): bool = false; /// True if network has been upgraded to this version. @@ -3028,7 +3027,7 @@ impl Module { /// /// Returns `Err(())` if less than [`MinimumValidatorCount`] validators have been elected, `Ok` /// otherwise. - #[allow(dead_code)] // TODO: TWO_PHASE + #[allow(dead_code)] // TWO_PHASE_NOTE pub fn process_election( flat_supports: sp_npos_elections::Supports, current_era: EraIndex, @@ -3076,7 +3075,7 @@ impl Module { } // emit event - // TODO: TWO_PHASE: remove the inner value. + // TWO_PHASE_NOTE: remove the inner value. Self::deposit_event(RawEvent::StakingElection(ElectionCompute::Signed)); log!( @@ -3099,7 +3098,7 @@ impl Module { "Experimental election provider outputted {:?}", outcome ); - // TODO: TWO_PHASE: This code path shall not return anything for now. Later on, redirect the + // TWO_PHASE_NOTE: This code path shall not return anything for now. Later on, redirect the // results to `process_election`. None } @@ -3578,7 +3577,7 @@ where } fn can_report() -> bool { - // TODO: TWO_PHASE: we can get rid of this API + // TWO_PHASE_NOTE: we can get rid of this API Self::era_election_status().is_closed() } } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 92b24d35ed2c7..495964a15c388 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -5036,7 +5036,6 @@ mod election_data_provider { 45 ); assert_eq!(staking_events().len(), 1); - // TODO: TWO_PHASE: remove the internal value. assert_eq!(*staking_events().last().unwrap(), RawEvent::StakingElection(ElectionCompute::OnChain)); for b in 21..45 { @@ -5054,7 +5053,6 @@ mod election_data_provider { 70 ); assert_eq!(staking_events().len(), 3); - // TODO: TWO_PHASE: remove the internal value. assert_eq!(*staking_events().last().unwrap(), RawEvent::StakingElection(ElectionCompute::OnChain)); }) } diff --git a/frame/two-phase-election-provider/src/benchmarking.rs b/frame/two-phase-election-provider/src/benchmarking.rs index c10ee172a8328..c95ffd2db1b57 100644 --- a/frame/two-phase-election-provider/src/benchmarking.rs +++ b/frame/two-phase-election-provider/src/benchmarking.rs @@ -216,7 +216,7 @@ benchmarks! { finalize_signed_phase_reject_solution { let receiver = account("receiver", 0, SEED); - let initial_balance = T::Currency::minimum_balance() * 10u32.into(); + let initial_balance = T::Currency::minimum_balance().max(One::one()) * 10u32.into(); let deposit: BalanceOf = 10u32.into(); T::Currency::make_free_balance_be(&receiver, initial_balance); assert_ok!(T::Currency::reserve(&receiver, deposit)); @@ -243,14 +243,14 @@ benchmarks! { let c in 1 .. (T::MaxSignedSubmissions::get() - 1); // the solution will be worse than all of them meaning the score need to be checked against all. - let solution = RawSolution { score: [(1000_0000u128 - 1).into(), 0, 0], ..Default::default() }; + let solution = RawSolution { score: [(1_0000_000u128 - 1).into(), 0, 0], ..Default::default() }; >::put(Phase::Signed); >::put(1); for i in 0..c { >::mutate(|queue| { - let solution = RawSolution { score: [(1000_0000 + i).into(), 0, 0], ..Default::default() }; + let solution = RawSolution { score: [(1_0000_000 + i).into(), 0, 0], ..Default::default() }; let signed_submission = SignedSubmission { solution, ..Default::default() }; // note: this is quite tricky: we know that the queue will stay sorted here. The // last will be best. @@ -268,14 +268,14 @@ benchmarks! { submit_unsigned { // number of votes in snapshot. - let v in 2000 .. 3000; + let v in 2000 .. T::BenchmarkingConfig::VOTERS[1]; // number of targets in snapshot. - let t in 500 .. 800; + let t in 500 .. T::BenchmarkingConfig::TARGETS[1]; // number of assignments, i.e. compact.len(). This means the active nominators, thus must be // a subset of `v` component. - let a in 500 .. 1500; + let a in 500 .. T::BenchmarkingConfig::ACTIVE_VOTERS[1]; // number of desired targets. Must be a subset of `t` component. - let d in 200 .. 400; + let d in 200 .. T::BenchmarkingConfig::DESIRED_TARGETS[1]; let witness = SolutionSize { voters: v, targets: t }; let raw_solution = solution_with_size::(witness, a, d); @@ -290,14 +290,14 @@ benchmarks! { // This is checking a valid solution. The worse case is indeed a valid solution. feasibility_check { // number of votes in snapshot. - let v in 2000 .. 3000; + let v in 2000 .. T::BenchmarkingConfig::VOTERS[1]; // number of targets in snapshot. - let t in 500 .. 800; + let t in 500 .. T::BenchmarkingConfig::TARGETS[1]; // number of assignments, i.e. compact.len(). This means the active nominators, thus must be // a subset of `v` component. - let a in 500 .. 1500; + let a in 500 .. T::BenchmarkingConfig::ACTIVE_VOTERS[1]; // number of desired targets. Must be a subset of `t` component. - let d in 200 .. 400; + let d in 200 .. T::BenchmarkingConfig::DESIRED_TARGETS[1]; let size = SolutionSize { voters: v, targets: t }; let raw_solution = solution_with_size::(size, a, d); @@ -341,15 +341,11 @@ mod test { }); ExtBuilder::default().build_and_execute(|| { - assert_ok!(test_benchmark_finalize_signed_phase_accept_solution::< - Runtime, - >()); + assert_ok!(test_benchmark_finalize_signed_phase_accept_solution::()); }); ExtBuilder::default().build_and_execute(|| { - assert_ok!(test_benchmark_finalize_signed_phase_reject_solution::< - Runtime, - >()); + assert_ok!(test_benchmark_finalize_signed_phase_reject_solution::()); }); ExtBuilder::default().build_and_execute(|| { diff --git a/frame/two-phase-election-provider/src/lib.rs b/frame/two-phase-election-provider/src/lib.rs index 3cd9794d8b8a0..d52177a580853 100644 --- a/frame/two-phase-election-provider/src/lib.rs +++ b/frame/two-phase-election-provider/src/lib.rs @@ -255,6 +255,25 @@ where type DataProvider = T::DataProvider; } +/// Configuration for the benchmarks of the pallet. +pub trait BenchmarkingConfig { + /// Range of voters. + const VOTERS: [u32; 2]; + /// Range of targets. + const TARGETS: [u32; 2]; + /// Range of active voters. + const ACTIVE_VOTERS: [u32; 2]; + /// Range of desired targets. + const DESIRED_TARGETS: [u32; 2]; +} + +impl BenchmarkingConfig for () { + const VOTERS: [u32; 2] = [2000, 3000]; + const TARGETS: [u32; 2] = [500, 800]; + const ACTIVE_VOTERS: [u32; 2] = [500, 1500]; + const DESIRED_TARGETS: [u32; 2] = [200, 400]; +} + /// Current phase of the pallet. #[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] pub enum Phase { @@ -580,6 +599,9 @@ pub mod pallet { /// Configuration for the fallback type Fallback: Get; + /// The configuration of benchmarking. + type BenchmarkingConfig: BenchmarkingConfig; + /// The weight of the pallet. type WeightInfo: WeightInfo; } @@ -710,10 +732,8 @@ pub mod pallet { // ensure solution claims is better. let mut signed_submissions = Self::signed_submissions(); - let maybe_index = - Self::insert_submission(&who, &mut signed_submissions, solution, size); - ensure!(maybe_index.is_some(), Error::::QueueFull); - let index = maybe_index.expect("Option checked to be `Some`; qed."); + let index = Self::insert_submission(&who, &mut signed_submissions, solution, size) + .ok_or(Error::::QueueFull)?; // collect deposit. Thereafter, the function cannot fail. // Defensive -- index is valid. @@ -723,8 +743,12 @@ pub mod pallet { .unwrap_or_default(); T::Currency::reserve(&who, deposit).map_err(|_| Error::::CannotPayDeposit)?; - // store the new signed submission. + // Remove the weakest, if needed. + if signed_submissions.len() as u32 > T::MaxSignedSubmissions::get() { + Self::remove_weakest(&mut signed_submissions); + } debug_assert!(signed_submissions.len() as u32 <= T::MaxSignedSubmissions::get()); + log!( info, "queued signed solution with (claimed) score {:?}", @@ -734,6 +758,7 @@ pub mod pallet { .unwrap_or_default() ); + // store the new signed submission. >::put(signed_submissions); Self::deposit_event(Event::SolutionStored(ElectionCompute::Signed)); Ok(None.into()) diff --git a/frame/two-phase-election-provider/src/mock.rs b/frame/two-phase-election-provider/src/mock.rs index e2c37fbcd1b4a..352a0fbcf6572 100644 --- a/frame/two-phase-election-provider/src/mock.rs +++ b/frame/two-phase-election-provider/src/mock.rs @@ -310,6 +310,7 @@ impl crate::Config for Runtime { type UnsignedPriority = UnsignedPriority; type DataProvider = StakingMock; type WeightInfo = DualMockWeightInfo; + type BenchmarkingConfig = (); type OnChainAccuracy = Perbill; type Fallback = Fallback; type CompactSolution = TestCompact; diff --git a/frame/two-phase-election-provider/src/signed.rs b/frame/two-phase-election-provider/src/signed.rs index 2c2446c1cffaf..e670c5265830b 100644 --- a/frame/two-phase-election-provider/src/signed.rs +++ b/frame/two-phase-election-provider/src/signed.rs @@ -136,10 +136,6 @@ where /// solution quality. If insertion was successful, `Some(index)` is returned where index is the /// index of the newly inserted item. /// - /// The length of the queue will always be kept less than or equal to `T::MaxSignedSubmissions`. - /// - /// If a solution is removed, their bond is unreserved. - /// /// Invariant: The returned index is always a valid index in `queue` and can safely be used to /// inspect the newly inserted element. pub fn insert_submission( @@ -184,23 +180,12 @@ where // It is either 0 (in which case `0 <= queue.len()`) or one of the queue indices // + 1. The biggest queue index is `queue.len() - 1`, thus `at <= queue.len()`. queue.insert(at, submission); - // if length has exceeded the limit, eject the weakest, return shifted index. - if queue.len() as u32 > T::MaxSignedSubmissions::get() { - Self::remove_weakest(queue); - // Invariant: at > 0 - // Proof by contradiction: Assume at is 0 and this will underflow. Then the - // previous length of the queue must have been `T::MaxSignedSubmissions` so - // that `queue.len() + 1` (for the newly inserted one) is more than - // `T::MaxSignedSubmissions`. But this would have been detected by the first - // if branch; qed. - Some(at - 1) - } else { - Some(at) - } + Some(at) } }); - debug_assert!(queue.len() as u32 <= T::MaxSignedSubmissions::get()); + // If the call site is sane and removes the weakest, then this must always be correct. + debug_assert!(queue.len() as u32 <= T::MaxSignedSubmissions::get() + 1); outcome } From 5d206ab7a96d1c0804ada0f5c56d7613b157cc2e Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 14 Jan 2021 17:31:20 +0000 Subject: [PATCH 56/62] Fix build --- frame/two-phase-election-provider/src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/two-phase-election-provider/src/helpers.rs b/frame/two-phase-election-provider/src/helpers.rs index 10f7cf9605c38..cf821422ce0ae 100644 --- a/frame/two-phase-election-provider/src/helpers.rs +++ b/frame/two-phase-election-provider/src/helpers.rs @@ -22,7 +22,7 @@ use super::{ OnChainAccuracyOf, ExtendedBalance, }; use sp_runtime::InnerOf; -use sp_std::{collections::btree_map::BTreeMap, convert::TryInto}; +use sp_std::{collections::btree_map::BTreeMap, convert::TryInto, boxed::Box, prelude::*}; #[macro_export] macro_rules! log { From ea193c75d2b206af59212fe815fc38630966d6f1 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 14 Jan 2021 17:37:06 +0000 Subject: [PATCH 57/62] Bring back benches --- bin/node/runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index d8d1678df6589..5f71a509d1778 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -1391,7 +1391,7 @@ impl_runtime_apis! { add_benchmark!(params, batches, pallet_treasury, Treasury); add_benchmark!(params, batches, pallet_utility, Utility); add_benchmark!(params, batches, pallet_vesting, Vesting); - // add_benchmark!(params, batches, pallet_two_phase_election_provider, TwoPhaseElectionProvider); + add_benchmark!(params, batches, pallet_two_phase_election_provider, TwoPhaseElectionProvider); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) From 60e57d718ca2016aeabd837475ad74c37fe8a81c Mon Sep 17 00:00:00 2001 From: Parity Benchmarking Bot Date: Thu, 14 Jan 2021 17:55:47 +0000 Subject: [PATCH 58/62] cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_two_phase_election_provider --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/two-phase-election-provider/src/weights.rs --template=./.maintain/frame-weight-template.hbs --- .../src/weights.rs | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/frame/two-phase-election-provider/src/weights.rs b/frame/two-phase-election-provider/src/weights.rs index 7f8d065099a12..cca949965e562 100644 --- a/frame/two-phase-election-provider/src/weights.rs +++ b/frame/two-phase-election-provider/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_two_phase_election_provider //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.1 -//! DATE: 2021-01-12, STEPS: [50, ], REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] +//! DATE: 2021-01-14, STEPS: [50, ], REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -58,57 +58,57 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn on_initialize_nothing() -> Weight { - (21_412_000 as Weight) + (21_280_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) } fn on_initialize_open_signed() -> Weight { - (74_015_000 as Weight) + (74_221_000 as Weight) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn on_initialize_open_unsigned() -> Weight { - (76_338_000 as Weight) + (76_100_000 as Weight) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn finalize_signed_phase_accept_solution() -> Weight { - (37_157_000 as Weight) + (38_088_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn finalize_signed_phase_reject_solution() -> Weight { - (16_622_000 as Weight) + (17_124_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn submit(c: u32, ) -> Weight { - (51_611_000 as Weight) - // Standard Error: 19_000 - .saturating_add((3_355_000 as Weight).saturating_mul(c as Weight)) + (52_370_000 as Weight) + // Standard Error: 17_000 + .saturating_add((3_395_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 20_000 - .saturating_add((3_164_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 20_000 - .saturating_add((11_299_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 104_000 - .saturating_add((2_664_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 21_000 + .saturating_add((2_606_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 21_000 + .saturating_add((11_405_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 108_000 + .saturating_add((2_651_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_000 - .saturating_add((3_254_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 38_000 - .saturating_add((567_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 11_000 - .saturating_add((9_628_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 58_000 - .saturating_add((3_731_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 12_000 + .saturating_add((2_788_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 41_000 + .saturating_add((601_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 12_000 + .saturating_add((9_722_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 61_000 + .saturating_add((3_706_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(3 as Weight)) } } @@ -116,57 +116,57 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn on_initialize_nothing() -> Weight { - (21_412_000 as Weight) + (21_280_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) } fn on_initialize_open_signed() -> Weight { - (74_015_000 as Weight) + (74_221_000 as Weight) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn on_initialize_open_unsigned() -> Weight { - (76_338_000 as Weight) + (76_100_000 as Weight) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn finalize_signed_phase_accept_solution() -> Weight { - (37_157_000 as Weight) + (38_088_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn finalize_signed_phase_reject_solution() -> Weight { - (16_622_000 as Weight) + (17_124_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn submit(c: u32, ) -> Weight { - (51_611_000 as Weight) - // Standard Error: 19_000 - .saturating_add((3_355_000 as Weight).saturating_mul(c as Weight)) + (52_370_000 as Weight) + // Standard Error: 17_000 + .saturating_add((3_395_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 20_000 - .saturating_add((3_164_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 20_000 - .saturating_add((11_299_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 104_000 - .saturating_add((2_664_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 21_000 + .saturating_add((2_606_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 21_000 + .saturating_add((11_405_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 108_000 + .saturating_add((2_651_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight { (0 as Weight) - // Standard Error: 11_000 - .saturating_add((3_254_000 as Weight).saturating_mul(v as Weight)) - // Standard Error: 38_000 - .saturating_add((567_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 11_000 - .saturating_add((9_628_000 as Weight).saturating_mul(a as Weight)) - // Standard Error: 58_000 - .saturating_add((3_731_000 as Weight).saturating_mul(d as Weight)) + // Standard Error: 12_000 + .saturating_add((2_788_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 41_000 + .saturating_add((601_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 12_000 + .saturating_add((9_722_000 as Weight).saturating_mul(a as Weight)) + // Standard Error: 61_000 + .saturating_add((3_706_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(3 as Weight)) } } From 77f53a392a0ebf235bf60258bef798a8f5937c14 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 15 Jan 2021 09:12:42 +0000 Subject: [PATCH 59/62] Add a bunch of more fixes: signed weight check, tests etc. --- .../src/benchmarking.rs | 29 +- frame/two-phase-election-provider/src/lib.rs | 140 +++++--- frame/two-phase-election-provider/src/mock.rs | 26 +- .../two-phase-election-provider/src/signed.rs | 302 ++++++++++-------- .../src/unsigned.rs | 128 ++++---- 5 files changed, 351 insertions(+), 274 deletions(-) diff --git a/frame/two-phase-election-provider/src/benchmarking.rs b/frame/two-phase-election-provider/src/benchmarking.rs index 2fa10ec927fa6..653af5358c4ac 100644 --- a/frame/two-phase-election-provider/src/benchmarking.rs +++ b/frame/two-phase-election-provider/src/benchmarking.rs @@ -38,14 +38,14 @@ const SEED: u32 = 0; fn solution_with_size( size: SolutionSize, active_voters_count: u32, - winners_count: u32, + desired_targets: u32, ) -> RawSolution> where ExtendedBalance: From>>, ExtendedBalance: From>>, > as sp_std::convert::TryFrom>::Error: sp_std::fmt::Debug, { - assert!(size.targets >= winners_count, "must have enough targets"); + assert!(size.targets >= desired_targets, "must have enough targets"); assert!( size.targets >= (>::LIMIT * 2) as u32, "must have enough targets for unique votes." @@ -55,7 +55,7 @@ where "must have enough voters" ); assert!( - (>::LIMIT as u32) < winners_count, + (>::LIMIT as u32) < desired_targets, "must have enough winners to give them votes." ); @@ -72,7 +72,7 @@ where // decide who are the winners. let winners = targets .as_slice() - .choose_multiple(&mut rng, winners_count as usize) + .choose_multiple(&mut rng, desired_targets as usize) .cloned() .collect::>(); @@ -113,17 +113,18 @@ where assert_eq!(active_voters.len() as u32, active_voters_count); assert_eq!(all_voters.len() as u32, size.voters); - assert_eq!(winners.len() as u32, winners_count); + assert_eq!(winners.len() as u32, desired_targets); >::put(RoundSnapshotMetadata { voters_len: all_voters.len() as u32, targets_len: targets.len() as u32, }); - >::put(winners_count); + >::put(desired_targets); >::put(RoundSnapshot { voters: all_voters.clone(), targets: targets.clone(), }); + // write the snapshot to staking or whoever is the data provider. T::DataProvider::put_snapshot(all_voters.clone(), targets.clone()); @@ -268,14 +269,14 @@ benchmarks! { submit_unsigned { // number of votes in snapshot. - let v in 2000 .. T::BenchmarkingConfig::VOTERS[1]; + let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1]; // number of targets in snapshot. - let t in 500 .. T::BenchmarkingConfig::TARGETS[1]; + 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 // a subset of `v` component. - let a in 500 .. T::BenchmarkingConfig::ACTIVE_VOTERS[1]; + let a in (T::BenchmarkingConfig::ACTIVE_VOTERS[0]) .. T::BenchmarkingConfig::ACTIVE_VOTERS[1]; // number of desired targets. Must be a subset of `t` component. - let d in 200 .. T::BenchmarkingConfig::DESIRED_TARGETS[1]; + let d in (T::BenchmarkingConfig::DESIRED_TARGETS[0]) .. T::BenchmarkingConfig::DESIRED_TARGETS[1]; let witness = SolutionSize { voters: v, targets: t }; let raw_solution = solution_with_size::(witness, a, d); @@ -290,14 +291,14 @@ benchmarks! { // This is checking a valid solution. The worse case is indeed a valid solution. feasibility_check { // number of votes in snapshot. - let v in 2000 .. T::BenchmarkingConfig::VOTERS[1]; + let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1]; // number of targets in snapshot. - let t in 500 .. T::BenchmarkingConfig::TARGETS[1]; + 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 // a subset of `v` component. - let a in 500 .. T::BenchmarkingConfig::ACTIVE_VOTERS[1]; + let a in (T::BenchmarkingConfig::ACTIVE_VOTERS[0]) .. T::BenchmarkingConfig::ACTIVE_VOTERS[1]; // number of desired targets. Must be a subset of `t` component. - let d in 200 .. T::BenchmarkingConfig::DESIRED_TARGETS[1]; + let d in (T::BenchmarkingConfig::DESIRED_TARGETS[0]) .. T::BenchmarkingConfig::DESIRED_TARGETS[1]; let size = SolutionSize { voters: v, targets: t }; let raw_solution = solution_with_size::(size, a, d); diff --git a/frame/two-phase-election-provider/src/lib.rs b/frame/two-phase-election-provider/src/lib.rs index d52177a580853..b285909a8d6f7 100644 --- a/frame/two-phase-election-provider/src/lib.rs +++ b/frame/two-phase-election-provider/src/lib.rs @@ -268,10 +268,10 @@ pub trait BenchmarkingConfig { } impl BenchmarkingConfig for () { - const VOTERS: [u32; 2] = [2000, 3000]; - const TARGETS: [u32; 2] = [500, 800]; - const ACTIVE_VOTERS: [u32; 2] = [500, 1500]; - const DESIRED_TARGETS: [u32; 2] = [200, 400]; + const VOTERS: [u32; 2] = [4000, 6000]; + const TARGETS: [u32; 2] = [1000, 1600]; + const ACTIVE_VOTERS: [u32; 2] = [1000, 3000]; + const DESIRED_TARGETS: [u32; 2] = [400, 800]; } /// Current phase of the pallet. @@ -546,19 +546,31 @@ pub mod pallet { #[pallet::constant] type MaxSignedSubmissions: Get; + /// Base reward for a signed solution #[pallet::constant] type SignedRewardBase: Get>; + /// Per-score reward for a signed solution. #[pallet::constant] type SignedRewardFactor: Get; + /// Maximum cap for a signed solution. #[pallet::constant] type SignedRewardMax: Get>>; + /// Base deposit for a signed solution. #[pallet::constant] type SignedDepositBase: Get>; + /// Per-byte deposit for a signed solution. #[pallet::constant] type SignedDepositByte: Get>; + /// Per-weight deposit for a signed solution. #[pallet::constant] type SignedDepositWeight: Get>; + /// Maximum weight of a signed solution. + /// + /// This should probably be similar to [`Config::MinerMaxWeight`]. + #[pallet::constant] + type SignedMaxWeight: Get; + /// The minimum amount of improvement to the solution score that defines a solution as /// "better". @@ -730,6 +742,12 @@ pub mod pallet { // defensive-only: if phase is signed, snapshot will exist. let size = Self::build_solution_size().unwrap_or_default(); + // NOTE: we compute this function once in `insert_submission` as well, could optimize. + ensure!( + Self::feasibility_weight_of(&solution, size) < T::SignedMaxWeight::get(), + Error::::TooMuchWeight, + ); + // ensure solution claims is better. let mut signed_submissions = Self::signed_submissions(); let index = Self::insert_submission(&who, &mut signed_submissions, solution, size) @@ -853,14 +871,18 @@ pub mod pallet { pub enum Error { /// Submission was too early. EarlySubmission, + /// Wrong number of winners presented. + WrongWinnerCount, /// Submission was too weak, score-wise. WeakSubmission, /// The queue was full, and the solution was not better than any of the existing ones. QueueFull, /// The origin failed to pay the deposit. CannotPayDeposit, - /// witness data to dispathable is invalid. + /// witness data to dispatchable is invalid. InvalidWitness, + /// The signed submission consumes too much weight + TooMuchWeight, } #[pallet::origin] @@ -1080,10 +1102,12 @@ where // winners are not directly encoded in the solution. let winners = compact.unique_targets(); - // TODO: this can probably checked ahead of time, both in signed and unsigned story. let desired_targets = Self::desired_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; + // NOTE: this is a bit of duplicate, but we keep it around for veracity. The unsigned path + // already checked this in `unsigned_per_dispatch_checks`. The signed path *could* check it + // upon arrival. ensure!( winners.len() as u32 == desired_targets, FeasibilityError::WrongWinnerCount, @@ -1154,7 +1178,6 @@ where let known_score = (&supports).evaluate(); ensure!(known_score == score, FeasibilityError::InvalidScore); - // let supports = supports.flatten(); Ok(ReadySolution { supports, compute, @@ -1471,7 +1494,10 @@ mod tests { roll_to(25); assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); - assert_eq!(two_phase_events(), vec![Event::SignedPhaseStarted(1), Event::UnsignedPhaseStarted(1)]); + assert_eq!( + two_phase_events(), + vec![Event::SignedPhaseStarted(1), Event::UnsignedPhaseStarted(1)], + ); assert!(TwoPhase::snapshot().is_some()); roll_to(29); @@ -1608,53 +1634,67 @@ mod tests { #[test] fn fallback_strategy_works() { - ExtBuilder::default() - .fallabck(FallbackStrategy::OnChain) - .build_and_execute(|| { - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Signed); + ExtBuilder::default().fallabck(FallbackStrategy::OnChain).build_and_execute(|| { + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); - roll_to(25); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); + roll_to(25); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); - // zilch solutions thus far. - let supports = TwoPhase::elect().unwrap(); + // zilch solutions thus far. + let supports = TwoPhase::elect().unwrap(); - assert_eq!( - supports, - vec![ - ( - 30, - Support { - total: 40, - voters: vec![(2, 5), (4, 5), (30, 30)] - } - ), - ( - 40, - Support { - total: 60, - voters: vec![(2, 5), (3, 10), (4, 5), (40, 40)] - } - ) - ] - ) - }); + assert_eq!( + supports, + vec![ + ( + 30, + Support { + total: 40, + voters: vec![(2, 5), (4, 5), (30, 30)] + } + ), + ( + 40, + Support { + total: 60, + voters: vec![(2, 5), (3, 10), (4, 5), (40, 40)] + } + ) + ] + ) + }); - ExtBuilder::default() - .fallabck(FallbackStrategy::Nothing) - .build_and_execute(|| { - roll_to(15); - assert_eq!(TwoPhase::current_phase(), Phase::Signed); + ExtBuilder::default().fallabck(FallbackStrategy::Nothing).build_and_execute(|| { + roll_to(15); + assert_eq!(TwoPhase::current_phase(), Phase::Signed); - roll_to(25); - assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); + roll_to(25); + assert_eq!(TwoPhase::current_phase(), Phase::Unsigned((true, 25))); - // zilch solutions thus far. - assert_eq!( - TwoPhase::elect().unwrap_err(), - ElectionError::NoFallbackConfigured - ); - }) + // zilch solutions thus far. + assert_eq!( + TwoPhase::elect().unwrap_err(), + ElectionError::NoFallbackConfigured + ); + }) + } + + #[test] + fn number_of_voters_allowed_2sec_block() { + // Just a rough estimate with the substrate weights. + assert!(!MockWeightInfo::get()); + + let all_voters: u32 = 100_000; + let all_targets: u32 = 2_000; + let desired: u32 = 1_000; + let weight_with = |active| ::WeightInfo::submit_unsigned(all_voters, all_targets, active, desired); + + let mut active = 1; + while weight_with(active) <= ::BlockWeights::get().max_block { + active += 1; + } + + println!("can support {} voters to yield a weight of {}", active, weight_with(active)); } } diff --git a/frame/two-phase-election-provider/src/mock.rs b/frame/two-phase-election-provider/src/mock.rs index 352a0fbcf6572..39e648c2b9b84 100644 --- a/frame/two-phase-election-provider/src/mock.rs +++ b/frame/two-phase-election-provider/src/mock.rs @@ -169,7 +169,7 @@ impl frame_system::Config for Runtime { type BlockHashCount = (); type DbWeight = (); type BlockLength = (); - type BlockWeights = (); + type BlockWeights = BlockWeights; type Version = (); type PalletInfo = (); type AccountData = pallet_balances::AccountData; @@ -196,9 +196,6 @@ impl pallet_balances::Config for Runtime { } parameter_types! { - pub static SignedPhase: u64 = 10; - pub static UnsignedPhase: u64 = 5; - pub static MaxSignedSubmissions: u32 = 5; pub static Targets: Vec = vec![10, 20, 30, 40]; pub static Voters: Vec<(AccountId, VoteWeight, Vec)> = vec![ (1, 10, vec![10, 20]), @@ -211,20 +208,28 @@ parameter_types! { (30, 30, vec![30]), (40, 40, vec![40]), ]; + + pub static Fallback: FallbackStrategy = FallbackStrategy::OnChain; pub static DesiredTargets: u32 = 2; + pub static SignedPhase: u64 = 10; + pub static UnsignedPhase: u64 = 5; + pub static MaxSignedSubmissions: u32 = 5; pub static SignedDepositBase: Balance = 5; pub static SignedDepositByte: Balance = 0; pub static SignedDepositWeight: Balance = 0; pub static SignedRewardBase: Balance = 7; pub static SignedRewardFactor: Perbill = Perbill::zero(); pub static SignedRewardMax: Balance = 10; + pub static SignedMaxWeight: Weight = BlockWeights::get().max_block; + pub static MinerMaxIterations: u32 = 5; pub static UnsignedPriority: u64 = 100; pub static SolutionImprovementThreshold: Perbill = Perbill::zero(); pub static MinerMaxWeight: Weight = BlockWeights::get().max_block; - pub static EpochLength: u64 = 30; - pub static Fallback: FallbackStrategy = FallbackStrategy::OnChain; pub static MockWeightInfo: bool = false; + + + pub static EpochLength: u64 = 30; } // Hopefully this won't be too much of a hassle to maintain. @@ -283,7 +288,9 @@ impl two_phase::weights::WeightInfo for DualMockWeightInfo { } fn feasibility_check(v: u32, t: u32, a: u32, d: u32) -> Weight { if MockWeightInfo::get() { - Zero::zero() + // 10 base + // 5 per edge. + (10 as Weight).saturating_add((5 as Weight).saturating_mul(a as Weight)) } else { <() as two_phase::weights::WeightInfo>::feasibility_check(v, t, a, d) } @@ -307,6 +314,7 @@ impl crate::Config for Runtime { type RewardHandler = (); type MinerMaxIterations = MinerMaxIterations; type MinerMaxWeight = MinerMaxWeight; + type SignedMaxWeight = SignedMaxWeight; type UnsignedPriority = UnsignedPriority; type DataProvider = StakingMock; type WeightInfo = DualMockWeightInfo; @@ -383,6 +391,10 @@ impl ExtBuilder { ::set(weight); self } + pub fn signed_weight(self, weight: Weight) -> Self { + ::set(weight); + self + } pub fn mock_weight_info(self, mock: bool) -> Self { ::set(mock); self diff --git a/frame/two-phase-election-provider/src/signed.rs b/frame/two-phase-election-provider/src/signed.rs index e670c5265830b..145f6adba1758 100644 --- a/frame/two-phase-election-provider/src/signed.rs +++ b/frame/two-phase-election-provider/src/signed.rs @@ -203,6 +203,16 @@ where } } + /// The feasibility weight of the given raw solution. + pub fn feasibility_weight_of(solution: &RawSolution>, size: SolutionSize) -> Weight { + T::WeightInfo::feasibility_check( + size.voters, + size.targets, + solution.compact.voter_count() as u32, + solution.compact.unique_targets().len() as u32, + ) + } + /// Collect sufficient deposit to store this solution this chain. /// /// The deposit is composed of 3 main elements: @@ -212,12 +222,7 @@ where /// 3. a per-weight deposit, for the potential weight usage in an upcoming on_initialize pub fn deposit_for(solution: &RawSolution>, size: SolutionSize) -> BalanceOf { let encoded_len: BalanceOf = solution.using_encoded(|e| e.len() as u32).into(); - let feasibility_weight = T::WeightInfo::feasibility_check( - size.voters, - size.targets, - solution.compact.voter_count() as u32, - solution.compact.unique_targets().len() as u32, - ); + let feasibility_weight = Self::feasibility_weight_of(solution, size); let len_deposit = T::SignedDepositByte::get() * encoded_len; let weight_deposit = T::SignedDepositWeight::get() * feasibility_weight.saturated_into(); @@ -328,41 +333,37 @@ mod tests { #[test] fn reward_is_capped() { - ExtBuilder::default() - .reward(5, Perbill::from_percent(25), 10) - .build_and_execute(|| { - roll_to(15); - assert!(TwoPhase::current_phase().is_signed()); + ExtBuilder::default().reward(5, Perbill::from_percent(25), 10).build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); - let solution = raw_solution(); - assert_eq!(solution.score[0], 40); - assert_eq!(balances(&99), (100, 0)); + let solution = raw_solution(); + assert_eq!(solution.score[0], 40); + assert_eq!(balances(&99), (100, 0)); - assert_ok!(submit_with_witness(Origin::signed(99), solution)); - assert_eq!(balances(&99), (95, 5)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_eq!(balances(&99), (95, 5)); - assert!(TwoPhase::finalize_signed_phase().0); - // expected reward is 5 + 10 - assert_eq!(balances(&99), (100 + 10, 0)); - }); + assert!(TwoPhase::finalize_signed_phase().0); + // expected reward is 5 + 10 + assert_eq!(balances(&99), (100 + 10, 0)); + }); - ExtBuilder::default() - .reward(5, Perbill::from_percent(25), 20) - .build_and_execute(|| { - roll_to(15); - assert!(TwoPhase::current_phase().is_signed()); + ExtBuilder::default().reward(5, Perbill::from_percent(25), 20).build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); - let solution = raw_solution(); - assert_eq!(solution.score[0], 40); - assert_eq!(balances(&99), (100, 0)); + let solution = raw_solution(); + assert_eq!(solution.score[0], 40); + assert_eq!(balances(&99), (100, 0)); - assert_ok!(submit_with_witness(Origin::signed(99), solution)); - assert_eq!(balances(&99), (95, 5)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_eq!(balances(&99), (95, 5)); - assert!(TwoPhase::finalize_signed_phase().0); - // expected reward is 5 + 10 - assert_eq!(balances(&99), (100 + 15, 0)); - }); + assert!(TwoPhase::finalize_signed_phase().0); + // expected reward is 5 + 10 + assert_eq!(balances(&99), (100 + 15, 0)); + }); } #[test] @@ -534,134 +535,128 @@ mod tests { #[test] fn early_ejected_solution_gets_bond_back() { - ExtBuilder::default() - .signed_deposit(2, 0, 0) - .build_and_execute(|| { - roll_to(15); - assert!(TwoPhase::current_phase().is_signed()); - - for s in 0..MaxSignedSubmissions::get() { - // score is always getting better - let solution = RawSolution { - score: [(5 + s).into(), 0, 0], - ..Default::default() - }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); - } - - assert_eq!(balances(&99).1, 2 * 5); - assert_eq!(balances(&999).1, 0); + ExtBuilder::default().signed_deposit(2, 0, 0).build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); - // better. + for s in 0..MaxSignedSubmissions::get() { + // score is always getting better let solution = RawSolution { - score: [20, 0, 0], + score: [(5 + s).into(), 0, 0], ..Default::default() }; - assert_ok!(submit_with_witness(Origin::signed(999), solution)); + assert_ok!(submit_with_witness(Origin::signed(99), solution)); + } - // got one bond back. - assert_eq!(balances(&99).1, 2 * 4); - assert_eq!(balances(&999).1, 2); - }) + assert_eq!(balances(&99).1, 2 * 5); + assert_eq!(balances(&999).1, 0); + + // better. + let solution = RawSolution { + score: [20, 0, 0], + ..Default::default() + }; + assert_ok!(submit_with_witness(Origin::signed(999), solution)); + + // got one bond back. + assert_eq!(balances(&99).1, 2 * 4); + assert_eq!(balances(&999).1, 2); + }) } #[test] fn equally_good_solution_is_not_accepted() { - ExtBuilder::default() - .max_signed_submission(3) - .build_and_execute(|| { - roll_to(15); - assert!(TwoPhase::current_phase().is_signed()); - - for i in 0..MaxSignedSubmissions::get() { - let solution = RawSolution { - score: [(5 + i).into(), 0, 0], - ..Default::default() - }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); - } - assert_eq!( - TwoPhase::signed_submissions() - .into_iter() - .map(|s| s.solution.score[0]) - .collect::>(), - vec![5, 6, 7] - ); - - // 5 is not accepted. This will only cause processing with no benefit. + ExtBuilder::default().max_signed_submission(3).build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); + + for i in 0..MaxSignedSubmissions::get() { let solution = RawSolution { - score: [5, 0, 0], + score: [(5 + i).into(), 0, 0], ..Default::default() }; - assert_noop!( - submit_with_witness(Origin::signed(99), solution), - Error::::QueueFull, - ); - }) + assert_ok!(submit_with_witness(Origin::signed(99), solution)); + } + assert_eq!( + TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(), + vec![5, 6, 7] + ); + + // 5 is not accepted. This will only cause processing with no benefit. + let solution = RawSolution { + score: [5, 0, 0], + ..Default::default() + }; + assert_noop!( + submit_with_witness(Origin::signed(99), solution), + Error::::QueueFull, + ); + }) } #[test] fn solutions_are_always_sorted() { - ExtBuilder::default() - .max_signed_submission(3) - .build_and_execute(|| { - let scores = || TwoPhase::signed_submissions() - .into_iter() - .map(|s| s.solution.score[0]) - .collect::>(); + ExtBuilder::default().max_signed_submission(3).build_and_execute(|| { + let scores = || TwoPhase::signed_submissions() + .into_iter() + .map(|s| s.solution.score[0]) + .collect::>(); - roll_to(15); - assert!(TwoPhase::current_phase().is_signed()); + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); - let solution = RawSolution { - score: [5, 0, 0], - ..Default::default() - }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); - assert_eq!(scores(), vec![5]); + let solution = RawSolution { + score: [5, 0, 0], + ..Default::default() + }; + assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_eq!(scores(), vec![5]); - let solution = RawSolution { - score: [8, 0, 0], - ..Default::default() - }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); - assert_eq!(scores(), vec![5, 8]); + let solution = RawSolution { + score: [8, 0, 0], + ..Default::default() + }; + assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_eq!(scores(), vec![5, 8]); - let solution = RawSolution { - score: [3, 0, 0], - ..Default::default() - }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); - assert_eq!(scores(), vec![3, 5, 8]); + let solution = RawSolution { + score: [3, 0, 0], + ..Default::default() + }; + assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_eq!(scores(), vec![3, 5, 8]); - let solution = RawSolution { - score: [6, 0, 0], - ..Default::default() - }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); - assert_eq!(scores(), vec![5, 6, 8]); + let solution = RawSolution { + score: [6, 0, 0], + ..Default::default() + }; + assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_eq!(scores(), vec![5, 6, 8]); - let solution = RawSolution { - score: [6, 0, 0], - ..Default::default() - }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); - assert_eq!(scores(), vec![6, 6, 8]); + let solution = RawSolution { + score: [6, 0, 0], + ..Default::default() + }; + assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_eq!(scores(), vec![6, 6, 8]); - let solution = RawSolution { - score: [10, 0, 0], - ..Default::default() - }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); - assert_eq!(scores(), vec![6, 8, 10]); + let solution = RawSolution { + score: [10, 0, 0], + ..Default::default() + }; + assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_eq!(scores(), vec![6, 8, 10]); - let solution = RawSolution { - score: [12, 0, 0], - ..Default::default() - }; - assert_ok!(submit_with_witness(Origin::signed(99), solution)); - assert_eq!(scores(), vec![8, 10, 12]); - }) + let solution = RawSolution { + score: [12, 0, 0], + ..Default::default() + }; + assert_ok!(submit_with_witness(Origin::signed(99), solution)); + assert_eq!(scores(), vec![8, 10, 12]); + }) } #[test] @@ -709,4 +704,35 @@ mod tests { assert_eq!(balances(&9999), (100, 0)); }) } + + #[test] + fn cannot_consume_too_much_future_weight() { + ExtBuilder::default().signed_weight(40).mock_weight_info(true).build_and_execute(|| { + roll_to(15); + assert!(TwoPhase::current_phase().is_signed()); + + let (solution, witness) = TwoPhase::mine_solution(2).unwrap(); + let solution_weight = ::WeightInfo::feasibility_check( + witness.voters, + witness.targets, + solution.compact.voter_count() as u32, + solution.compact.unique_targets().len() as u32, + ); + // default solution will have 5 edges (5 * 5 + 10) + assert_eq!(solution_weight, 35); + assert_eq!(solution.compact.voter_count(), 5); + assert_eq!(::SignedMaxWeight::get(), 40); + + assert_ok!(submit_with_witness(Origin::signed(99), solution.clone())); + + ::set(30); + + // note: resubmitting the same solution is technically okay as long as the queue has + // space. + assert_noop!( + submit_with_witness(Origin::signed(99), solution), + Error::::TooMuchWeight, + ); + }) + } } diff --git a/frame/two-phase-election-provider/src/unsigned.rs b/frame/two-phase-election-provider/src/unsigned.rs index 3713ba080dc94..2ddc4d7f3a442 100644 --- a/frame/two-phase-election-provider/src/unsigned.rs +++ b/frame/two-phase-election-provider/src/unsigned.rs @@ -336,6 +336,12 @@ where Error::::EarlySubmission ); + // ensure correct number of winners. + ensure!( + Self::desired_targets() == solution.compact.unique_targets().len() as u32, + Error::::WrongWinnerCount, + ); + // ensure score is being improved. Panic henceforth. ensure!( Self::queued_solution().map_or(true, |q: ReadySolution<_>| is_score_better::( @@ -655,29 +661,27 @@ mod tests { #[test] fn priority_is_set() { - ExtBuilder::default() - .unsigned_priority(20) - .build_and_execute(|| { - roll_to(25); - assert!(TwoPhase::current_phase().is_unsigned()); + ExtBuilder::default().unsigned_priority(20).build_and_execute(|| { + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); - let solution = RawSolution:: { - score: [5, 0, 0], - ..Default::default() - }; - let call = Call::submit_unsigned(solution.clone(), witness()); - - // initial - assert_eq!( - ::validate_unsigned( - TransactionSource::Local, - &call - ) - .unwrap() - .priority, - 25 - ); - }) + let solution = RawSolution:: { + score: [5, 0, 0], + ..Default::default() + }; + let call = Call::submit_unsigned(solution.clone(), witness()); + + // initial + assert_eq!( + ::validate_unsigned( + TransactionSource::Local, + &call + ) + .unwrap() + .priority, + 25 + ); + }) } #[test] @@ -747,54 +751,49 @@ mod tests { #[test] fn miner_trims_weight() { - ExtBuilder::default() - .miner_weight(100) - .mock_weight_info(true) - .build_and_execute(|| { - roll_to(25); - assert!(TwoPhase::current_phase().is_unsigned()); + ExtBuilder::default().miner_weight(100).mock_weight_info(true).build_and_execute(|| { + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); - let (solution, witness) = TwoPhase::mine_solution(2).unwrap(); - let solution_weight = ::WeightInfo::submit_unsigned( - witness.voters, - witness.targets, - solution.compact.voter_count() as u32, - solution.compact.unique_targets().len() as u32, - ); - // default solution will have 5 edges (5 * 5 + 10) - assert_eq!(solution_weight, 35); - assert_eq!(solution.compact.voter_count(), 5); - - // now reduce the max weight - ::set(25); - - let (solution, witness) = TwoPhase::mine_solution(2).unwrap(); - let solution_weight = ::WeightInfo::submit_unsigned( - witness.voters, - witness.targets, - solution.compact.voter_count() as u32, - solution.compact.unique_targets().len() as u32, - ); - // default solution will have 5 edges (5 * 5 + 10) - assert_eq!(solution_weight, 25); - assert_eq!(solution.compact.voter_count(), 3); - }) + let (solution, witness) = TwoPhase::mine_solution(2).unwrap(); + let solution_weight = ::WeightInfo::submit_unsigned( + witness.voters, + witness.targets, + solution.compact.voter_count() as u32, + solution.compact.unique_targets().len() as u32, + ); + // default solution will have 5 edges (5 * 5 + 10) + assert_eq!(solution_weight, 35); + assert_eq!(solution.compact.voter_count(), 5); + + // now reduce the max weight + ::set(25); + + let (solution, witness) = TwoPhase::mine_solution(2).unwrap(); + let solution_weight = ::WeightInfo::submit_unsigned( + witness.voters, + witness.targets, + solution.compact.voter_count() as u32, + solution.compact.unique_targets().len() as u32, + ); + // default solution will have 5 edges (5 * 5 + 10) + assert_eq!(solution_weight, 25); + assert_eq!(solution.compact.voter_count(), 3); + }) } #[test] fn miner_will_not_submit_if_not_enough_winners() { - ExtBuilder::default() - .desired_targets(8) - .build_and_execute(|| { - roll_to(25); - assert!(TwoPhase::current_phase().is_unsigned()); + ExtBuilder::default().desired_targets(8).build_and_execute(|| { + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); - // mine seq_phragmen solution with 2 iters. - assert_eq!( - TwoPhase::mine_solution(2).unwrap_err(), - ElectionError::Feasibility(FeasibilityError::WrongWinnerCount), - ); - }) + // mine seq_phragmen solution with 2 iters. + assert_eq!( + TwoPhase::mine_solution(2).unwrap_err(), + ElectionError::Feasibility(FeasibilityError::WrongWinnerCount), + ); + }) } #[test] @@ -805,7 +804,6 @@ mod tests { .add_voter(8, 5, vec![10]) .solution_improvement_threshold(Perbill::from_percent(50)) .build_and_execute(|| { - roll_to(25); assert!(TwoPhase::current_phase().is_unsigned()); assert_eq!(TwoPhase::desired_targets().unwrap(), 1); From b30dfb3fc17471edac658a3d8639bb9a02ccf405 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 15 Jan 2021 09:15:54 +0000 Subject: [PATCH 60/62] Fix build --- frame/two-phase-election-provider/src/unsigned.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/two-phase-election-provider/src/unsigned.rs b/frame/two-phase-election-provider/src/unsigned.rs index 2ddc4d7f3a442..9d2bc9ee15730 100644 --- a/frame/two-phase-election-provider/src/unsigned.rs +++ b/frame/two-phase-election-provider/src/unsigned.rs @@ -338,7 +338,7 @@ where // ensure correct number of winners. ensure!( - Self::desired_targets() == solution.compact.unique_targets().len() as u32, + Self::desired_targets().unwrap_or_default() == solution.compact.unique_targets().len() as u32, Error::::WrongWinnerCount, ); From a066e4a1dde72b8d9a4141338d99c36df3d827d1 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 15 Jan 2021 13:32:47 +0000 Subject: [PATCH 61/62] Last small tweaks --- frame/staking/src/lib.rs | 12 +++++------- frame/staking/src/testing_utils.rs | 1 - frame/support/src/traits.rs | 31 +++++++++++++++--------------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 3ba210b6e2612..ab7e8a5b94df3 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -748,8 +748,7 @@ pub trait SessionInterface: frame_system::Config { fn prune_historical_up_to(up_to: SessionIndex); } -impl SessionInterface<::AccountId> for T -where +impl SessionInterface<::AccountId> for T where T: pallet_session::Config::AccountId>, T: pallet_session::historical::Config< FullIdentification = Exposure<::AccountId, BalanceOf>, @@ -757,10 +756,8 @@ where >, T::SessionHandler: pallet_session::SessionHandler<::AccountId>, T::SessionManager: pallet_session::SessionManager<::AccountId>, - T::ValidatorIdOf: Convert< - ::AccountId, - Option<::AccountId>, - >, + T::ValidatorIdOf: + Convert<::AccountId, Option<::AccountId>>, { fn disable_validator(validator: &::AccountId) -> Result { >::disable(validator) @@ -3027,7 +3024,8 @@ impl Module { /// /// Returns `Err(())` if less than [`MinimumValidatorCount`] validators have been elected, `Ok` /// otherwise. - #[allow(dead_code)] // TWO_PHASE_NOTE + // TWO_PHASE_NOTE: the deadcode + #[allow(dead_code)] pub fn process_election( flat_supports: sp_npos_elections::Supports, current_era: EraIndex, diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index 4daed16c88a68..a71c68577657a 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -393,4 +393,3 @@ pub fn create_assignments_for_offchain( Ok((winners, assignments)) } - diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index eabe93d2ae008..d4dbdbf5ef115 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -347,23 +347,22 @@ impl Happened for () { /// be the default value), or where the account is being removed or reset back to the default value /// where previously it did exist (though may have been in a default state). This works well with /// system module's `CallOnCreatedAccount` and `CallKillAccount`. -pub struct StorageMapShim( - sp_std::marker::PhantomData<(S, Created, Removed, K, T)>, -); +pub struct StorageMapShim< + S, + Created, + Removed, + K, + T +>(sp_std::marker::PhantomData<(S, Created, Removed, K, T)>); impl< - S: StorageMap, - Created: Happened, - Removed: Happened, - K: FullCodec, - T: FullCodec, - > StoredMap for StorageMapShim -{ - fn get(k: &K) -> T { - S::get(k) - } - fn is_explicit(k: &K) -> bool { - S::contains_key(k) - } + S: StorageMap, + Created: Happened, + Removed: Happened, + K: FullCodec, + T: FullCodec, +> StoredMap for StorageMapShim { + fn get(k: &K) -> T { S::get(k) } + fn is_explicit(k: &K) -> bool { S::contains_key(k) } fn insert(k: &K, t: T) { let existed = S::contains_key(&k); S::insert(k, t); From 10f6e7b98b57aa872b8bf06ad3b38b904e4773fb Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 15 Jan 2021 13:51:46 +0000 Subject: [PATCH 62/62] Fix all tests. --- frame/two-phase-election-provider/src/lib.rs | 27 ++++----------- .../two-phase-election-provider/src/signed.rs | 15 ++++++++ .../src/unsigned.rs | 34 +++++++++++++++---- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/frame/two-phase-election-provider/src/lib.rs b/frame/two-phase-election-provider/src/lib.rs index b285909a8d6f7..38670a331c6b8 100644 --- a/frame/two-phase-election-provider/src/lib.rs +++ b/frame/two-phase-election-provider/src/lib.rs @@ -32,7 +32,6 @@ //! + <--T::SignedPhase--> + <--T::UnsignedPhase--> + //! +-------------------------------------------------------------------+ //! Phase::Off + Phase::Signed + Phase::Unsigned + -//! //! ``` //! //! Note that the unsigned phase starts [`pallet::Config::UnsignedPhase`] blocks before the @@ -162,9 +161,9 @@ //! //! **Recursive Fallback**: Currently, the fallback is a separate enum. A different and fancier way //! of doing this would be to have the fallback be another -//! [`sp_election_providers::ElectionProvider`]. In this case, this pallet can even have the on-chain -//! election provider as fallback, or special _noop_ fallback that simply returns an error, thus -//! replicating [`FallbackStrategy::Nothing`]. +//! [`sp_election_providers::ElectionProvider`]. In this case, this pallet can even have the +//! on-chain election provider as fallback, or special _noop_ fallback that simply returns an error, +//! thus replicating [`FallbackStrategy::Nothing`]. //! //! **Score based on size**: We should always prioritize small solutions over bigger ones, if there //! is a tie. Even more harsh should be to enforce the bound of the `reduce` algorithm. @@ -217,6 +216,7 @@ pub mod unsigned; pub mod weights; use weights::WeightInfo; +use signed::SignedSubmission; /// The compact solution type used by this crate. pub type CompactOf = ::CompactSolution; @@ -372,21 +372,6 @@ impl Default for RawSolution { } } -/// A raw, unchecked signed submission. -/// -/// This is just a wrapper around [`RawSolution`] and some additional info. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] -pub struct SignedSubmission { - /// Who submitted this solution. - who: A, - /// The deposit reserved for storing this solution. - deposit: B, - /// The reward that should be given to this solution, if chosen the as the final one. - reward: B, - /// The raw solution itself. - solution: RawSolution, -} - /// A checked solution, ready to be enacted. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] pub struct ReadySolution { @@ -421,8 +406,8 @@ pub struct SolutionSize { } /// A snapshot of all the data that is needed for en entire round. They are provided by -/// [`ElectionDataProvider`] at the beginning of the signed phase and are kept around until the -/// round is finished. +/// [`ElectionDataProvider`] at the beginning of the signed phase (or the unsigned phase, if signed +/// phase is non-existent) and are kept around until the round is finished. /// /// These are stored together because they are often times accessed together. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] diff --git a/frame/two-phase-election-provider/src/signed.rs b/frame/two-phase-election-provider/src/signed.rs index 145f6adba1758..41caf8762bd62 100644 --- a/frame/two-phase-election-provider/src/signed.rs +++ b/frame/two-phase-election-provider/src/signed.rs @@ -23,6 +23,21 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_npos_elections::{is_score_better, CompactSolution}; use sp_runtime::Perbill; +/// A raw, unchecked signed submission. +/// +/// This is just a wrapper around [`RawSolution`] and some additional info. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default)] +pub struct SignedSubmission { + /// Who submitted this solution. + pub(crate) who: A, + /// The deposit reserved for storing this solution. + pub(crate) deposit: B, + /// The reward that should be given to this solution, if chosen the as the final one. + pub(crate) reward: B, + /// The raw solution itself. + pub(crate) solution: RawSolution, +} + impl Pallet where ExtendedBalance: From>>, diff --git a/frame/two-phase-election-provider/src/unsigned.rs b/frame/two-phase-election-provider/src/unsigned.rs index 9d2bc9ee15730..d2125512bc448 100644 --- a/frame/two-phase-election-provider/src/unsigned.rs +++ b/frame/two-phase-election-provider/src/unsigned.rs @@ -574,7 +574,7 @@ mod tests { #[test] fn validate_unsigned_retracts_wrong_phase() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().desired_targets(0).build_and_execute(|| { let solution = RawSolution:: { score: [5, 0, 0], ..Default::default() @@ -621,7 +621,7 @@ mod tests { #[test] fn validate_unsigned_retracts_low_score() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().desired_targets(0).build_and_execute(|| { roll_to(25); assert!(TwoPhase::current_phase().is_unsigned()); @@ -650,10 +650,32 @@ mod tests { assert!(matches!( ::validate_unsigned(TransactionSource::Local, &call) .unwrap_err(), - TransactionValidityError::Invalid(InvalidTransaction::Custom(1)) + TransactionValidityError::Invalid(InvalidTransaction::Custom(2)) )); assert!(matches!( ::pre_dispatch(&call).unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Custom(2)) + )); + }) + } + + #[test] + fn validate_unsigned_retracts_incorrect_winner_count() { + ExtBuilder::default().desired_targets(1).build_and_execute(|| { + roll_to(25); + assert!(TwoPhase::current_phase().is_unsigned()); + + let solution = RawSolution:: { + score: [5, 0, 0], + ..Default::default() + }; + let call = Call::submit_unsigned(solution.clone(), witness()); + assert_eq!(solution.compact.unique_targets().len(), 0); + + // won't work anymore. + assert!(matches!( + ::validate_unsigned(TransactionSource::Local, &call) + .unwrap_err(), TransactionValidityError::Invalid(InvalidTransaction::Custom(1)) )); }) @@ -661,7 +683,7 @@ mod tests { #[test] fn priority_is_set() { - ExtBuilder::default().unsigned_priority(20).build_and_execute(|| { + ExtBuilder::default().unsigned_priority(20).desired_targets(0).build_and_execute(|| { roll_to(25); assert!(TwoPhase::current_phase().is_unsigned()); @@ -671,7 +693,6 @@ mod tests { }; let call = Call::submit_unsigned(solution.clone(), witness()); - // initial assert_eq!( ::validate_unsigned( TransactionSource::Local, @@ -686,8 +707,7 @@ mod tests { #[test] #[should_panic( - expected = "Invalid unsigned submission must produce invalid block and deprive \ - validator from their authoring reward.: FeasibilityError::WrongWinnerCount" + expected = "Invalid unsigned submission must produce invalid block and deprive validator from their authoring reward.: DispatchError::Module { index: 0, error: 1, message: Some(\"WrongWinnerCount\") }" )] fn unfeasible_solution_panics() { ExtBuilder::default().build_and_execute(|| {