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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,8 @@ frame_election_provider_support::generate_solution_type!(
parameter_types! {
pub MaxNominations: u32 = <NposSolution16 as frame_election_provider_support::NposSolution>::LIMIT as u32;
pub MaxElectingVoters: u32 = 10_000;
// Conservative value, unbounded to keep backward compatibility.
pub MaxWinnersPerPage: u32 = u32::max_value();
}

/// The numbers configured here could always be more than the the maximum limits of staking pallet
Expand Down Expand Up @@ -652,6 +654,9 @@ impl onchain::Config for OnChainSeqPhragmen {
>;
type DataProvider = <Runtime as pallet_election_provider_multi_phase::Config>::DataProvider;
type WeightInfo = frame_election_provider_support::weights::SubstrateWeight<Runtime>;
// This is being defensive by defending the maximum bound possible.
type MaxBackersPerWinner = MaxElectingVoters;
type MaxWinnersPerPage = MaxWinnersPerPage;
}

impl onchain::BoundedConfig for OnChainSeqPhragmen {
Expand Down Expand Up @@ -686,6 +691,9 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
type ForceOrigin = EnsureRootOrHalfCouncil;
type MaxElectableTargets = ConstU16<{ u16::MAX }>;
type MaxElectingVoters = MaxElectingVoters;
// This is being defensive by defending the maximum bound possible.
type MaxBackersPerWinner = MaxElectingVoters;
type MaxWinnersPerPage = MaxWinnersPerPage;
type BenchmarkingConfig = ElectionProviderBenchmarkConfig;
type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight<Self>;
}
Expand Down
2 changes: 2 additions & 0 deletions frame/babe/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ impl onchain::Config for OnChainSeqPhragmen {
type Solver = SequentialPhragmen<DummyValidatorId, Perbill>;
type DataProvider = Staking;
type WeightInfo = ();
type MaxBackersPerWinner = ConstU32<{ u32::MAX }>;
type MaxWinnersPerPage = ConstU32<{ u32::MAX }>;
}

impl pallet_staking::Config for Test {
Expand Down
2 changes: 1 addition & 1 deletion frame/election-provider-multi-phase/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ frame_benchmarking::benchmarks! {
let initial_balance = T::Currency::minimum_balance() * 10u32.into();
T::Currency::make_free_balance_be(&receiver, initial_balance);
let ready = ReadySolution {
supports: vec![],
supports: Default::default(),
score: Default::default(),
compute: Default::default()
};
Expand Down
77 changes: 56 additions & 21 deletions frame/election-provider-multi-phase/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,17 @@

#![cfg_attr(not(feature = "std"), no_std)]

use codec::{Decode, Encode};
use codec::{Decode, Encode, MaxEncodedLen};
use frame_election_provider_support::{
ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolution,
BoundedSupportsOf, ElectionDataProvider, ElectionProvider, InstantElectionProvider,
NposSolution, TryIntoBoundedSupports,
};
use frame_support::{
dispatch::DispatchResultWithPostInfo,
ensure,
traits::{Currency, Get, OnUnbalanced, ReservableCurrency},
weights::{DispatchClass, Weight},
DefaultNoBound, PartialEqNoBound, RuntimeDebugNoBound,
};
use frame_system::{ensure_none, offchain::SendTransactionTypes};
use scale_info::TypeInfo;
Expand All @@ -246,7 +248,7 @@ use sp_arithmetic::{
UpperOf,
};
use sp_npos_elections::{
assignment_ratio_to_staked_normalized, ElectionScore, EvaluateSupport, Supports, VoteWeight,
assignment_ratio_to_staked_normalized, ElectionScore, EvaluateSupport, VoteWeight,
};
use sp_runtime::{
transaction_validity::{
Expand Down Expand Up @@ -315,21 +317,23 @@ impl<T: Config> ElectionProvider for NoFallback<T> {
type BlockNumber = T::BlockNumber;
type DataProvider = T::DataProvider;
type Error = &'static str;
type MaxBackersPerWinner = T::MaxBackersPerWinner;
type MaxWinnersPerPage = T::MaxWinnersPerPage;

fn elect() -> Result<Supports<T::AccountId>, Self::Error> {
fn elect() -> Result<BoundedSupportsOf<Self>, Self::Error> {
// Do nothing, this will enable the emergency phase.
Err("NoFallback.")
}
}

impl<T: Config> InstantElectionProvider for NoFallback<T> {
fn elect_with_bounds(_: usize, _: usize) -> Result<Supports<T::AccountId>, Self::Error> {
fn elect_with_bounds(_: usize, _: usize) -> Result<BoundedSupportsOf<Self>, Self::Error> {
Err("NoFallback.")
}
}

/// Current phase of the pallet.
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo)]
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
pub enum Phase<Bn> {
/// Nothing, the election is not happening.
Off,
Expand Down Expand Up @@ -391,7 +395,7 @@ impl<Bn: PartialEq + Eq> Phase<Bn> {
}

/// The type of `Computation` that provided this election data.
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo)]
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
pub enum ElectionCompute {
/// Election was computed on-chain.
OnChain,
Expand All @@ -417,7 +421,9 @@ impl Default for ElectionCompute {
///
/// Such a solution should never become effective in anyway before being checked by the
/// `Pallet::feasibility_check`.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, PartialOrd, Ord, TypeInfo)]
#[derive(
PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, PartialOrd, Ord, TypeInfo, MaxEncodedLen,
)]
pub struct RawSolution<S> {
/// the solution itself.
pub solution: S,
Expand All @@ -435,13 +441,24 @@ impl<C: Default> Default for RawSolution<C> {
}

/// A checked solution, ready to be enacted.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, Default, TypeInfo)]
pub struct ReadySolution<A> {
#[derive(
PartialEqNoBound,
Eq,
Clone,
Encode,
Decode,
RuntimeDebugNoBound,
DefaultNoBound,
TypeInfo,
MaxEncodedLen,
)]
#[scale_info(skip_type_params(T))]
pub struct ReadySolution<T: Config> {
/// The final supports of the solution.
///
/// This is target-major vector, storing each winners, total backing, and each individual
/// backer.
pub supports: Supports<A>,
pub supports: BoundedSupportsOf<Pallet<T>>,
/// The score of the solution.
///
/// This is needed to potentially challenge the solution.
Expand Down Expand Up @@ -469,7 +486,7 @@ pub struct RoundSnapshot<T: Config> {
/// This is stored automatically on-chain, and it contains the **size of the entire snapshot**.
/// This is also used in dispatchables as weight witness data and should **only contain the size of
/// the presented solution**, not the entire snapshot.
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, Debug, Default, TypeInfo)]
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, Debug, Default, TypeInfo, MaxEncodedLen)]
pub struct SolutionOrSnapshotSize {
/// The length of voters.
#[codec(compact)]
Expand Down Expand Up @@ -649,6 +666,14 @@ pub mod pallet {
#[pallet::constant]
type MaxElectableTargets: Get<SolutionTargetIndexOf<Self>>;

/// Check [`ElectionProvider::MaxBackersPerWinner`] for more information.
#[pallet::constant]
type MaxBackersPerWinner: Get<u32>;

/// Maximum number of winner that can be returned, per page (i.e. per call to `elect`).
#[pallet::constant]
type MaxWinnersPerPage: Get<u32>;

/// Handler for the slashed deposits.
type SlashHandler: OnUnbalanced<NegativeImbalanceOf<Self>>;

Expand Down Expand Up @@ -677,13 +702,16 @@ pub mod pallet {
+ sp_std::fmt::Debug
+ Ord
+ NposSolution
+ TypeInfo;
+ TypeInfo
+ MaxEncodedLen;

/// Configuration for the fallback.
type Fallback: InstantElectionProvider<
AccountId = Self::AccountId,
BlockNumber = Self::BlockNumber,
DataProvider = Self::DataProvider,
MaxBackersPerWinner = Self::MaxBackersPerWinner,
MaxWinnersPerPage = Self::MaxWinnersPerPage,
>;

/// Configuration of the governance-only fallback.
Expand All @@ -694,6 +722,8 @@ pub mod pallet {
AccountId = Self::AccountId,
BlockNumber = Self::BlockNumber,
DataProvider = Self::DataProvider,
MaxBackersPerWinner = Self::MaxBackersPerWinner,
MaxWinnersPerPage = Self::MaxWinnersPerPage,
>;

/// OCW election solution miner algorithm implementation.
Expand Down Expand Up @@ -932,7 +962,7 @@ pub mod pallet {
#[pallet::weight(T::DbWeight::get().reads_writes(1, 1))]
pub fn set_emergency_election_result(
origin: OriginFor<T>,
supports: Supports<T::AccountId>,
supports: BoundedSupportsOf<Pallet<T>>,
) -> DispatchResult {
T::ForceOrigin::ensure_origin(origin)?;
ensure!(Self::current_phase().is_emergency(), <Error<T>>::CallNotAllowed);
Expand Down Expand Up @@ -1180,7 +1210,7 @@ pub mod pallet {
/// Current best solution, signed or unsigned, queued to be returned upon `elect`.
#[pallet::storage]
#[pallet::getter(fn queued_solution)]
pub type QueuedSolution<T: Config> = StorageValue<_, ReadySolution<T::AccountId>>;
pub type QueuedSolution<T: Config> = StorageValue<_, ReadySolution<T>>;

/// Snapshot data of the round.
///
Expand Down Expand Up @@ -1414,7 +1444,7 @@ impl<T: Config> Pallet<T> {
pub fn feasibility_check(
raw_solution: RawSolution<SolutionOf<T>>,
compute: ElectionCompute,
) -> Result<ReadySolution<T::AccountId>, FeasibilityError> {
) -> Result<ReadySolution<T>, FeasibilityError> {
let RawSolution { solution, score, round } = raw_solution;

// First, check round.
Expand Down Expand Up @@ -1490,6 +1520,9 @@ impl<T: Config> Pallet<T> {
let known_score = supports.evaluate();
ensure!(known_score == score, FeasibilityError::InvalidScore);

let supports = supports
.try_into_bounded_supports()
.map_err(|_| FeasibilityError::WrongWinnerCount)?;
Ok(ReadySolution { supports, compute, score })
}

Expand All @@ -1509,7 +1542,7 @@ impl<T: Config> Pallet<T> {
Self::kill_snapshot();
}

fn do_elect() -> Result<Supports<T::AccountId>, ElectionError<T>> {
fn do_elect() -> Result<BoundedSupportsOf<Self>, ElectionError<T>> {
// We have to unconditionally try finalizing the signed phase here. There are only two
// possibilities:
//
Expand Down Expand Up @@ -1544,7 +1577,7 @@ impl<T: Config> Pallet<T> {
}

/// record the weight of the given `supports`.
fn weigh_supports(supports: &Supports<T::AccountId>) {
fn weigh_supports(supports: &BoundedSupportsOf<Self>) {
let active_voters = supports
.iter()
.map(|(_, x)| x)
Expand All @@ -1559,8 +1592,10 @@ impl<T: Config> ElectionProvider for Pallet<T> {
type BlockNumber = T::BlockNumber;
type Error = ElectionError<T>;
type DataProvider = T::DataProvider;
type MaxBackersPerWinner = T::MaxBackersPerWinner;
type MaxWinnersPerPage = T::MaxWinnersPerPage;

fn elect() -> Result<Supports<T::AccountId>, Self::Error> {
fn elect() -> Result<BoundedSupportsOf<Self>, Self::Error> {
match Self::do_elect() {
Ok(supports) => {
// All went okay, record the weight, put sign to be Off, clean snapshot, etc.
Expand Down Expand Up @@ -1794,7 +1829,7 @@ mod tests {
},
Phase,
};
use frame_election_provider_support::ElectionProvider;
use frame_election_provider_support::{bounded_supports_to_supports, ElectionProvider};
use frame_support::{assert_noop, assert_ok};
use sp_npos_elections::Support;

Expand Down Expand Up @@ -2016,7 +2051,7 @@ mod tests {
let supports = MultiPhase::elect().unwrap();

assert_eq!(
supports,
bounded_supports_to_supports(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)] })
Expand Down
10 changes: 8 additions & 2 deletions frame/election-provider-multi-phase/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ impl onchain::Config for OnChainSeqPhragmen {
type Solver = SequentialPhragmen<AccountId, SolutionAccuracyOf<Runtime>, Balancing>;
type DataProvider = StakingMock;
type WeightInfo = ();
type MaxBackersPerWinner = MaxElectingVoters;
type MaxWinnersPerPage = MaxElectableTargets;
}

pub struct MockFallback;
Expand All @@ -289,8 +291,10 @@ impl ElectionProvider for MockFallback {
type BlockNumber = u64;
type Error = &'static str;
type DataProvider = StakingMock;
type MaxBackersPerWinner = MaxElectingVoters;
type MaxWinnersPerPage = MaxElectableTargets;

fn elect() -> Result<Supports<AccountId>, Self::Error> {
fn elect() -> Result<BoundedSupportsOf<Self>, Self::Error> {
Self::elect_with_bounds(Bounded::max_value(), Bounded::max_value())
}
}
Expand All @@ -299,7 +303,7 @@ impl InstantElectionProvider for MockFallback {
fn elect_with_bounds(
max_voters: usize,
max_targets: usize,
) -> Result<Supports<Self::AccountId>, Self::Error> {
) -> Result<BoundedSupportsOf<Self>, Self::Error> {
if OnChainFallback::get() {
onchain::UnboundedExecution::<OnChainSeqPhragmen>::elect_with_bounds(
max_voters,
Expand Down Expand Up @@ -425,6 +429,8 @@ impl crate::Config for Runtime {
type SignedDepositWeight = ();
type SignedMaxWeight = SignedMaxWeight;
type SignedMaxSubmissions = SignedMaxSubmissions;
type MaxBackersPerWinner = MaxElectingVoters;
type MaxWinnersPerPage = MaxElectableTargets;
type SlashHandler = ();
type RewardHandler = ();
type DataProvider = StakingMock;
Expand Down
8 changes: 5 additions & 3 deletions frame/election-provider-multi-phase/src/signed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{
SignedSubmissionIndices, SignedSubmissionNextIndex, SignedSubmissionsMap, SolutionOf,
SolutionOrSnapshotSize, Weight, WeightInfo,
};
use codec::{Decode, Encode, HasCompact};
use codec::{Decode, Encode, HasCompact, MaxEncodedLen};
use frame_election_provider_support::NposSolution;
use frame_support::{
storage::bounded_btree_map::BoundedBTreeMap,
Expand All @@ -43,7 +43,9 @@ use sp_std::{
/// A raw, unchecked signed submission.
///
/// This is just a wrapper around [`RawSolution`] and some additional info.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)]
#[derive(
PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, scale_info::TypeInfo, MaxEncodedLen,
)]
pub struct SignedSubmission<AccountId, Balance: HasCompact, Solution> {
/// Who submitted this solution.
pub who: AccountId,
Expand Down Expand Up @@ -421,7 +423,7 @@ impl<T: Config> Pallet<T> {
///
/// Infallible
pub fn finalize_signed_phase_accept_solution(
ready_solution: ReadySolution<T::AccountId>,
ready_solution: ReadySolution<T>,
who: &T::AccountId,
deposit: BalanceOf<T>,
reward: BalanceOf<T>,
Expand Down
Loading