mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 21:01:05 +00:00
Bound Election and Staking by MaxActiveValidators (#12436)
* bounding election provider with kian * multi phase implement bounded election provider * election provider blanket implementation * staking compiles * fix test for election provider support * fmt * fixing epmp tests, does not compile yet * fix epmp tests * fix staking tests * fmt * fix runtime tests * fmt * remove outdated wip tags * add enum error * sort and truncate supports * comment * error when unsupported number of election winners * compiling wip after kian's suggestions * fix TODOs * remove,fix tags * ensure validator count does not exceed maxwinners * clean up * some more clean up and todos * handle too many winners * rename parameter for mock * todo * add sort and truncate rule if there are too many winners * fmt * fail, not swallow emergency result bound not met * remove too many winners resolution as it can be guaranteed to be bounded * fix benchmark * give MaxWinners more contextual name * make ready solution generic over T * kian feedback * fix stuff * Kian's way of solvign this * comment fix * fix compile * remove use of BoundedExecution * fmt * comment out failing integrity test * cap validator count increment to max winners * dont panic * add test for bad data provider * Update frame/staking/src/pallet/impls.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * fix namespace conflict and add test for onchain max winners less than desired targets * defensive unwrap * early convert to bounded vec * fix syntax * fmt * fix doc * fix rustdoc * fmt * fix maxwinner count for benchmarking * add instant election for noelection * fmt * fix compile * pr feedbacks * always error at validator count exceeding max winners * add useful error message * pr comments * import fix * add checked_desired_targets * fmt * fmt * fix rust doc Co-authored-by: parity-processbot <> Co-authored-by: kianenigma <kian@parity.io> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
This commit is contained in:
@@ -18,15 +18,15 @@
|
||||
//! Implementations for the Staking FRAME Pallet.
|
||||
|
||||
use frame_election_provider_support::{
|
||||
data_provider, ElectionDataProvider, ElectionProvider, ElectionProviderBase, ScoreProvider,
|
||||
SortedListProvider, Supports, VoteWeight, VoterOf,
|
||||
data_provider, BoundedSupportsOf, ElectionDataProvider, ElectionProvider, ScoreProvider,
|
||||
SortedListProvider, VoteWeight, VoterOf,
|
||||
};
|
||||
use frame_support::{
|
||||
dispatch::WithPostDispatchInfo,
|
||||
pallet_prelude::*,
|
||||
traits::{
|
||||
Currency, CurrencyToVote, Defensive, DefensiveResult, EstimateNextNewSession, Get,
|
||||
Imbalance, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons,
|
||||
Imbalance, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, WithdrawReasons,
|
||||
},
|
||||
weights::Weight,
|
||||
};
|
||||
@@ -44,7 +44,7 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*};
|
||||
|
||||
use crate::{
|
||||
log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, Exposure, ExposureOf,
|
||||
Forcing, IndividualExposure, Nominations, PositiveImbalanceOf, RewardDestination,
|
||||
Forcing, IndividualExposure, MaxWinnersOf, Nominations, PositiveImbalanceOf, RewardDestination,
|
||||
SessionInterface, StakingLedger, ValidatorPrefs,
|
||||
};
|
||||
|
||||
@@ -267,7 +267,10 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
|
||||
/// Plan a new session potentially trigger a new era.
|
||||
fn new_session(session_index: SessionIndex, is_genesis: bool) -> Option<Vec<T::AccountId>> {
|
||||
fn new_session(
|
||||
session_index: SessionIndex,
|
||||
is_genesis: bool,
|
||||
) -> Option<BoundedVec<T::AccountId, MaxWinnersOf<T>>> {
|
||||
if let Some(current_era) = Self::current_era() {
|
||||
// Initial era has been set.
|
||||
let current_era_start_session_index = Self::eras_start_session_index(current_era)
|
||||
@@ -426,8 +429,11 @@ impl<T: Config> Pallet<T> {
|
||||
/// Returns the new validator set.
|
||||
pub fn trigger_new_era(
|
||||
start_session_index: SessionIndex,
|
||||
exposures: Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)>,
|
||||
) -> Vec<T::AccountId> {
|
||||
exposures: BoundedVec<
|
||||
(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>),
|
||||
MaxWinnersOf<T>,
|
||||
>,
|
||||
) -> BoundedVec<T::AccountId, MaxWinnersOf<T>> {
|
||||
// Increment or set current era.
|
||||
let new_planned_era = CurrentEra::<T>::mutate(|s| {
|
||||
*s = Some(s.map(|s| s + 1).unwrap_or(0));
|
||||
@@ -453,19 +459,26 @@ impl<T: Config> Pallet<T> {
|
||||
pub(crate) fn try_trigger_new_era(
|
||||
start_session_index: SessionIndex,
|
||||
is_genesis: bool,
|
||||
) -> Option<Vec<T::AccountId>> {
|
||||
let election_result = if is_genesis {
|
||||
T::GenesisElectionProvider::elect().map_err(|e| {
|
||||
) -> Option<BoundedVec<T::AccountId, MaxWinnersOf<T>>> {
|
||||
let election_result: BoundedVec<_, MaxWinnersOf<T>> = if is_genesis {
|
||||
let result = <T::GenesisElectionProvider>::elect().map_err(|e| {
|
||||
log!(warn, "genesis election provider failed due to {:?}", e);
|
||||
Self::deposit_event(Event::StakingElectionFailed);
|
||||
})
|
||||
});
|
||||
|
||||
result
|
||||
.ok()?
|
||||
.into_inner()
|
||||
.try_into()
|
||||
// both bounds checked in integrity test to be equal
|
||||
.defensive_unwrap_or_default()
|
||||
} else {
|
||||
T::ElectionProvider::elect().map_err(|e| {
|
||||
let result = <T::ElectionProvider>::elect().map_err(|e| {
|
||||
log!(warn, "election provider failed due to {:?}", e);
|
||||
Self::deposit_event(Event::StakingElectionFailed);
|
||||
})
|
||||
}
|
||||
.ok()?;
|
||||
});
|
||||
result.ok()?
|
||||
};
|
||||
|
||||
let exposures = Self::collect_exposures(election_result);
|
||||
if (exposures.len() as u32) < Self::minimum_validator_count().max(1) {
|
||||
@@ -502,10 +515,19 @@ impl<T: Config> Pallet<T> {
|
||||
///
|
||||
/// Store staking information for the new planned era
|
||||
pub fn store_stakers_info(
|
||||
exposures: Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)>,
|
||||
exposures: BoundedVec<
|
||||
(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>),
|
||||
MaxWinnersOf<T>,
|
||||
>,
|
||||
new_planned_era: EraIndex,
|
||||
) -> Vec<T::AccountId> {
|
||||
let elected_stashes = exposures.iter().cloned().map(|(x, _)| x).collect::<Vec<_>>();
|
||||
) -> BoundedVec<T::AccountId, MaxWinnersOf<T>> {
|
||||
let elected_stashes: BoundedVec<_, MaxWinnersOf<T>> = exposures
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|(x, _)| x)
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.expect("since we only map through exposures, size of elected_stashes is always same as exposures; qed");
|
||||
|
||||
// Populate stakers, exposures, and the snapshot of validator prefs.
|
||||
let mut total_stake: BalanceOf<T> = Zero::zero();
|
||||
@@ -543,11 +565,11 @@ impl<T: Config> Pallet<T> {
|
||||
elected_stashes
|
||||
}
|
||||
|
||||
/// Consume a set of [`Supports`] from [`sp_npos_elections`] and collect them into a
|
||||
/// Consume a set of [`BoundedSupports`] from [`sp_npos_elections`] and collect them into a
|
||||
/// [`Exposure`].
|
||||
fn collect_exposures(
|
||||
supports: Supports<T::AccountId>,
|
||||
) -> Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)> {
|
||||
supports: BoundedSupportsOf<T::ElectionProvider>,
|
||||
) -> BoundedVec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>), MaxWinnersOf<T>> {
|
||||
let total_issuance = T::Currency::total_issuance();
|
||||
let to_currency = |e: frame_election_provider_support::ExtendedBalance| {
|
||||
T::CurrencyToVote::to_currency(e, total_issuance)
|
||||
@@ -576,7 +598,8 @@ impl<T: Config> Pallet<T> {
|
||||
let exposure = Exposure { own, others, total };
|
||||
(validator, exposure)
|
||||
})
|
||||
.collect::<Vec<(T::AccountId, Exposure<_, _>)>>()
|
||||
.try_collect()
|
||||
.expect("we only map through support vector which cannot change the size; qed")
|
||||
}
|
||||
|
||||
/// Remove all associated data of a stash account from the staking system.
|
||||
@@ -1085,12 +1108,12 @@ impl<T: Config> pallet_session::SessionManager<T::AccountId> for Pallet<T> {
|
||||
fn new_session(new_index: SessionIndex) -> Option<Vec<T::AccountId>> {
|
||||
log!(trace, "planning new session {}", new_index);
|
||||
CurrentPlannedSession::<T>::put(new_index);
|
||||
Self::new_session(new_index, false)
|
||||
Self::new_session(new_index, false).map(|v| v.into_inner())
|
||||
}
|
||||
fn new_session_genesis(new_index: SessionIndex) -> Option<Vec<T::AccountId>> {
|
||||
log!(trace, "planning new session {} at genesis", new_index);
|
||||
CurrentPlannedSession::<T>::put(new_index);
|
||||
Self::new_session(new_index, true)
|
||||
Self::new_session(new_index, true).map(|v| v.into_inner())
|
||||
}
|
||||
fn start_session(start_index: SessionIndex) {
|
||||
log!(trace, "starting session {}", start_index);
|
||||
@@ -1500,7 +1523,7 @@ impl<T: Config> StakingInterface for Pallet<T> {
|
||||
}
|
||||
|
||||
fn election_ongoing() -> bool {
|
||||
<T::ElectionProvider as ElectionProviderBase>::ongoing()
|
||||
T::ElectionProvider::ongoing()
|
||||
}
|
||||
|
||||
fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult {
|
||||
@@ -1626,6 +1649,12 @@ impl<T: Config> Pallet<T> {
|
||||
Nominators::<T>::count() + Validators::<T>::count(),
|
||||
"wrong external count"
|
||||
);
|
||||
|
||||
ensure!(
|
||||
ValidatorCount::<T>::get() <=
|
||||
<T::ElectionProvider as frame_election_provider_support::ElectionProviderBase>::MaxWinners::get(),
|
||||
"validator count exceeded election max winners"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user