pallet_staking/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! # Staking Pallet
19//!
20//! The Staking pallet is used to manage funds at stake by network maintainers.
21//!
22//! - [`Config`]
23//! - [`Call`]
24//! - [`Pallet`]
25//!
26//! ## Overview
27//!
28//! The Staking pallet is the means by which a set of network maintainers (known as _authorities_ in
29//! some contexts and _validators_ in others) are chosen based upon those who voluntarily place
30//! funds under deposit. Under deposit, those funds are rewarded under normal operation but are held
31//! at pain of _slash_ (expropriation) should the staked maintainer be found not to be discharging
32//! its duties properly.
33//!
34//! ### Terminology
35//! <!-- Original author of paragraph: @gavofyork -->
36//!
37//! - Staking: The process of locking up funds for some time, placing them at risk of slashing
38//!   (loss) in order to become a rewarded maintainer of the network.
39//! - Validating: The process of running a node to actively maintain the network, either by
40//!   producing blocks or guaranteeing finality of the chain.
41//! - Nominating: The process of placing staked funds behind one or more validators in order to
42//!   share in any reward, and punishment, they take.
43//! - Stash account: The account holding an owner's funds used for staking.
44//! - Controller account (being deprecated): The account that controls an owner's funds for staking.
45//! - Era: A (whole) number of sessions, which is the period that the validator set (and each
46//!   validator's active nominator set) is recalculated and where rewards are paid out.
47//! - Slash: The punishment of a staker by reducing its funds.
48//!
49//! ### Goals
50//! <!-- Original author of paragraph: @gavofyork -->
51//!
52//! The staking system in Substrate NPoS is designed to make the following possible:
53//!
54//! - Stake funds that are controlled by a cold wallet.
55//! - Withdraw some, or deposit more, funds without interrupting the role of an entity.
56//! - Switch between roles (nominator, validator, idle) with minimal overhead.
57//!
58//! ### Scenarios
59//!
60//! #### Staking
61//!
62//! Almost any interaction with the Staking pallet requires a process of _**bonding**_ (also known
63//! as being a _staker_). To become *bonded*, a fund-holding register known as the _stash account_,
64//! which holds some or all of the funds that become frozen in place as part of the staking process.
65//! The controller account, which this pallet now assigns the stash account to, issues instructions
66//! on how funds shall be used.
67//!
68//! An account can become a bonded stash account using the [`bond`](Call::bond) call.
69//!
70//! In the event stash accounts registered a unique controller account before the controller account
71//! deprecation, they can update their associated controller back to the stash account using the
72//! [`set_controller`](Call::set_controller) call.
73//!
74//! There are three possible roles that any staked account pair can be in: `Validator`, `Nominator`
75//! and `Idle` (defined in [`StakerStatus`]). There are three corresponding instructions to change
76//! between roles, namely: [`validate`](Call::validate), [`nominate`](Call::nominate), and
77//! [`chill`](Call::chill).
78//!
79//! #### Validating
80//!
81//! A **validator** takes the role of either validating blocks or ensuring their finality,
82//! maintaining the veracity of the network. A validator should avoid both any sort of malicious
83//! misbehavior and going offline. Bonded accounts that state interest in being a validator do NOT
84//! get immediately chosen as a validator. Instead, they are declared as a _candidate_ and they
85//! _might_ get elected at the _next era_ as a validator. The result of the election is determined
86//! by nominators and their votes.
87//!
88//! An account can become a validator candidate via the [`validate`](Call::validate) call.
89//!
90//! #### Nomination
91//!
92//! A **nominator** does not take any _direct_ role in maintaining the network, instead, it votes on
93//! a set of validators to be elected. Once interest in nomination is stated by an account, it takes
94//! effect at the next election round. The funds in the nominator's stash account indicate the
95//! _weight_ of its vote. Both the rewards and any punishment that a validator earns are shared
96//! between the validator and its nominators. This rule incentivizes the nominators to NOT vote for
97//! the misbehaving/offline validators as much as possible, simply because the nominators will also
98//! lose funds if they vote poorly.
99//!
100//! An account can become a nominator via the [`nominate`](Call::nominate) call.
101//!
102//! #### Voting
103//!
104//! Staking is closely related to elections; actual validators are chosen from among all potential
105//! validators via election by the potential validators and nominators. To reduce use of the phrase
106//! "potential validators and nominators", we often use the term **voters**, who are simply the
107//! union of potential validators and nominators.
108//!
109//! #### Rewards and Slash
110//!
111//! The **reward and slashing** procedure is the core of the Staking pallet, attempting to _embrace
112//! valid behavior_ while _punishing any misbehavior or lack of availability_.
113//!
114//! Rewards must be claimed for each era before it gets too old by
115//! [`HistoryDepth`](`Config::HistoryDepth`) using the `payout_stakers` call. Any account can call
116//! `payout_stakers`, which pays the reward to the validator as well as its nominators. Only
117//! [`Config::MaxExposurePageSize`] nominator rewards can be claimed in a single call. When the
118//! number of nominators exceeds [`Config::MaxExposurePageSize`], then the exposed nominators are
119//! stored in multiple pages, with each page containing up to [`Config::MaxExposurePageSize`]
120//! nominators. To pay out all nominators, `payout_stakers` must be called once for each available
121//! page. Paging exists to limit the i/o cost to mutate storage for each nominator's account.
122//!
123//! Slashing can occur at any point in time, once misbehavior is reported. Once slashing is
124//! determined, a value is deducted from the balance of the validator and all the nominators who
125//! voted for this validator (values are deducted from the _stash_ account of the slashed entity).
126//!
127//! Slashing logic is further described in the documentation of the `slashing` pallet.
128//!
129//! Similar to slashing, rewards are also shared among a validator and its associated nominators.
130//! Yet, the reward funds are not always transferred to the stash account and can be configured. See
131//! [Reward Calculation](#reward-calculation) for more details.
132//!
133//! #### Chilling
134//!
135//! Finally, any of the roles above can choose to step back temporarily and just chill for a while.
136//! This means that if they are a nominator, they will not be considered as voters anymore and if
137//! they are validators, they will no longer be a candidate for the next election.
138//!
139//! An account can step back via the [`chill`](Call::chill) call.
140//!
141//! ### Session managing
142//!
143//! The pallet implement the trait `SessionManager`. Which is the only API to query new validator
144//! set and allowing these validator set to be rewarded once their era is ended.
145//!
146//! ## Interface
147//!
148//! ### Dispatchable Functions
149//!
150//! The dispatchable functions of the Staking pallet enable the steps needed for entities to accept
151//! and change their role, alongside some helper functions to get/set the metadata of the pallet.
152//!
153//! ### Public Functions
154//!
155//! The Staking pallet contains many public storage items and (im)mutable functions.
156//!
157//! ## Usage
158//!
159//! ### Example: Rewarding a validator by id.
160//!
161//! ```
162//! use pallet_staking::{self as staking};
163//!
164//! #[frame_support::pallet(dev_mode)]
165//! pub mod pallet {
166//!   use super::*;
167//!   use frame_support::pallet_prelude::*;
168//!   use frame_system::pallet_prelude::*;
169//!
170//!   #[pallet::pallet]
171//!   pub struct Pallet<T>(_);
172//!
173//!   #[pallet::config]
174//!   pub trait Config: frame_system::Config + staking::Config {}
175//!
176//!   #[pallet::call]
177//!   impl<T: Config> Pallet<T> {
178//!         /// Reward a validator.
179//!         #[pallet::weight(0)]
180//!         pub fn reward_myself(origin: OriginFor<T>) -> DispatchResult {
181//!             let reported = ensure_signed(origin)?;
182//!             <staking::Pallet<T>>::reward_by_ids(vec![(reported, 10)]);
183//!             Ok(())
184//!         }
185//!     }
186//! }
187//! # fn main() { }
188//! ```
189//!
190//! ## Implementation Details
191//!
192//! ### Era payout
193//!
194//! The era payout is computed using yearly inflation curve defined at [`Config::EraPayout`] as
195//! such:
196//!
197//! ```nocompile
198//! staker_payout = yearly_inflation(npos_token_staked / total_tokens) * total_tokens / era_per_year
199//! ```
200//! This payout is used to reward stakers as defined in next section
201//!
202//! ```nocompile
203//! remaining_payout = max_yearly_inflation * total_tokens / era_per_year - staker_payout
204//! ```
205//!
206//! Note, however, that it is possible to set a cap on the total `staker_payout` for the era through
207//! the `MaxStakersRewards` storage type. The `era_payout` implementor must ensure that the
208//! `max_payout = remaining_payout + (staker_payout * max_stakers_rewards)`. The excess payout that
209//! is not allocated for stakers is the era remaining reward.
210//!
211//! The remaining reward is send to the configurable end-point [`Config::RewardRemainder`].
212//!
213//! ### Reward Calculation
214//!
215//! Validators and nominators are rewarded at the end of each era. The total reward of an era is
216//! calculated using the era duration and the staking rate (the total amount of tokens staked by
217//! nominators and validators, divided by the total token supply). It aims to incentivize toward a
218//! defined staking rate. The full specification can be found
219//! [here](https://research.web3.foundation/en/latest/polkadot/Token%20Economics.html#inflation-model).
220//!
221//! Total reward is split among validators and their nominators depending on the number of points
222//! they received during the era. Points are added to a validator using
223//! [`reward_by_ids`](Pallet::reward_by_ids).
224//!
225//! [`Pallet`] implements [`pallet_authorship::EventHandler`] to add reward points to block producer
226//! and block producer of referenced uncles.
227//!
228//! The validator and its nominator split their reward as following:
229//!
230//! The validator can declare an amount, named [`commission`](ValidatorPrefs::commission), that does
231//! not get shared with the nominators at each reward payout through its [`ValidatorPrefs`]. This
232//! value gets deducted from the total reward that is paid to the validator and its nominators. The
233//! remaining portion is split pro rata among the validator and the nominators that nominated the
234//! validator, proportional to the value staked behind the validator (_i.e._ dividing the
235//! [`own`](Exposure::own) or [`others`](Exposure::others) by [`total`](Exposure::total) in
236//! [`Exposure`]). Note that payouts are made in pages with each page capped at
237//! [`Config::MaxExposurePageSize`] nominators. The distribution of nominators across pages may be
238//! unsorted. The total commission is paid out proportionally across pages based on the total stake
239//! of the page.
240//!
241//! All entities who receive a reward have the option to choose their reward destination through the
242//! [`Payee`] storage item (see [`set_payee`](Call::set_payee)), to be one of the following:
243//!
244//! - Stash account, not increasing the staked value.
245//! - Stash account, also increasing the staked value.
246//! - Any other account, sent as free balance.
247//!
248//! ### Additional Fund Management Operations
249//!
250//! Any funds already placed into stash can be the target of the following operations:
251//!
252//! The controller account can free a portion (or all) of the funds using the
253//! [`unbond`](Call::unbond) call. Note that the funds are not immediately accessible. Instead, a
254//! duration denoted by [`Config::BondingDuration`] (in number of eras) must pass until the funds
255//! can actually be removed. Once the `BondingDuration` is over, the
256//! [`withdraw_unbonded`](Call::withdraw_unbonded) call can be used to actually withdraw the funds.
257//!
258//! Note that there is a limitation to the number of fund-chunks that can be scheduled to be
259//! unlocked in the future via [`unbond`](Call::unbond). In case this maximum
260//! (`MAX_UNLOCKING_CHUNKS`) is reached, the bonded account _must_ first wait until a successful
261//! call to `withdraw_unbonded` to remove some of the chunks.
262//!
263//! ### Election Algorithm
264//!
265//! The current election algorithm is implemented based on Phragmén. The reference implementation
266//! can be found [here](https://github.com/w3f/consensus/tree/master/NPoS).
267//!
268//! The election algorithm, aside from electing the validators with the most stake value and votes,
269//! tries to divide the nominator votes among candidates in an equal manner. To further assure this,
270//! an optional post-processing can be applied that iteratively normalizes the nominator staked
271//! values until the total difference among votes of a particular nominator are less than a
272//! threshold.
273//!
274//! ## GenesisConfig
275//!
276//! The Staking pallet depends on the [`GenesisConfig`]. The `GenesisConfig` is optional and allow
277//! to set some initial stakers.
278//!
279//! ## Related Modules
280//!
281//! - [Balances](../pallet_balances/index.html): Used to manage values at stake.
282//! - [Session](../pallet_session/index.html): Used to manage sessions. Also, a list of new
283//!   validators is stored in the Session pallet's `Validators` at the end of each era.
284
285#![cfg_attr(not(feature = "std"), no_std)]
286#![recursion_limit = "256"]
287
288#[cfg(feature = "runtime-benchmarks")]
289pub mod benchmarking;
290#[cfg(any(feature = "runtime-benchmarks", test))]
291pub mod testing_utils;
292
293#[cfg(test)]
294pub(crate) mod mock;
295#[cfg(test)]
296mod tests;
297
298pub mod asset;
299pub mod election_size_tracker;
300pub mod inflation;
301pub mod ledger;
302pub mod migrations;
303pub mod slashing;
304pub mod weights;
305
306mod pallet;
307
308extern crate alloc;
309
310use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec};
311use codec::{Decode, Encode, HasCompact, MaxEncodedLen};
312use frame_support::{
313	defensive, defensive_assert,
314	traits::{
315		ConstU32, Contains, Currency, Defensive, DefensiveMax, DefensiveSaturating, Get,
316		LockIdentifier,
317	},
318	weights::Weight,
319	BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound,
320};
321use scale_info::TypeInfo;
322use sp_runtime::{
323	curve::PiecewiseLinear,
324	traits::{AtLeast32BitUnsigned, Convert, StaticLookup, Zero},
325	Perbill, Perquintill, Rounding, RuntimeDebug, Saturating,
326};
327use sp_staking::{
328	offence::{Offence, OffenceError, ReportOffence},
329	EraIndex, ExposurePage, OnStakingUpdate, Page, PagedExposureMetadata, SessionIndex,
330	StakingAccount,
331};
332pub use sp_staking::{Exposure, IndividualExposure, StakerStatus};
333pub use weights::WeightInfo;
334
335pub use pallet::{pallet::*, UseNominatorsAndValidatorsMap, UseValidatorsMap};
336
337pub(crate) const STAKING_ID: LockIdentifier = *b"staking ";
338pub(crate) const LOG_TARGET: &str = "runtime::staking";
339
340// syntactic sugar for logging.
341#[macro_export]
342macro_rules! log {
343	($level:tt, $patter:expr $(, $values:expr)* $(,)?) => {
344		log::$level!(
345			target: crate::LOG_TARGET,
346			concat!("[{:?}] 💸 ", $patter), <frame_system::Pallet<T>>::block_number() $(, $values)*
347		)
348	};
349}
350
351/// Maximum number of winners (aka. active validators), as defined in the election provider of this
352/// pallet.
353pub type MaxWinnersOf<T> = <<T as Config>::ElectionProvider as frame_election_provider_support::ElectionProviderBase>::MaxWinners;
354
355/// Maximum number of nominations per nominator.
356pub type MaxNominationsOf<T> =
357	<<T as Config>::NominationsQuota as NominationsQuota<BalanceOf<T>>>::MaxNominations;
358
359/// Counter for the number of "reward" points earned by a given validator.
360pub type RewardPoint = u32;
361
362/// The balance type of this pallet.
363pub type BalanceOf<T> = <T as Config>::CurrencyBalance;
364
365type PositiveImbalanceOf<T> = <<T as Config>::Currency as Currency<
366	<T as frame_system::Config>::AccountId,
367>>::PositiveImbalance;
368pub type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
369	<T as frame_system::Config>::AccountId,
370>>::NegativeImbalance;
371
372type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
373
374/// Information regarding the active era (era in used in session).
375#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
376pub struct ActiveEraInfo {
377	/// Index of era.
378	pub index: EraIndex,
379	/// Moment of start expressed as millisecond from `$UNIX_EPOCH`.
380	///
381	/// Start can be none if start hasn't been set for the era yet,
382	/// Start is set on the first on_finalize of the era to guarantee usage of `Time`.
383	pub start: Option<u64>,
384}
385
386/// Reward points of an era. Used to split era total payout between validators.
387///
388/// This points will be used to reward validators and their respective nominators.
389#[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
390pub struct EraRewardPoints<AccountId: Ord> {
391	/// Total number of points. Equals the sum of reward points for each validator.
392	pub total: RewardPoint,
393	/// The reward points earned by a given validator.
394	pub individual: BTreeMap<AccountId, RewardPoint>,
395}
396
397impl<AccountId: Ord> Default for EraRewardPoints<AccountId> {
398	fn default() -> Self {
399		EraRewardPoints { total: Default::default(), individual: BTreeMap::new() }
400	}
401}
402
403/// A destination account for payment.
404#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
405pub enum RewardDestination<AccountId> {
406	/// Pay into the stash account, increasing the amount at stake accordingly.
407	Staked,
408	/// Pay into the stash account, not increasing the amount at stake.
409	Stash,
410	#[deprecated(
411		note = "`Controller` will be removed after January 2024. Use `Account(controller)` instead."
412	)]
413	Controller,
414	/// Pay into a specified account.
415	Account(AccountId),
416	/// Receive no reward.
417	None,
418}
419
420/// Preference of what happens regarding validation.
421#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default, MaxEncodedLen)]
422pub struct ValidatorPrefs {
423	/// Reward that validator takes up-front; only the rest is split between themselves and
424	/// nominators.
425	#[codec(compact)]
426	pub commission: Perbill,
427	/// Whether or not this validator is accepting more nominations. If `true`, then no nominator
428	/// who is not already nominating this validator may nominate them. By default, validators
429	/// are accepting nominations.
430	pub blocked: bool,
431}
432
433/// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked.
434#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
435pub struct UnlockChunk<Balance: HasCompact + MaxEncodedLen> {
436	/// Amount of funds to be unlocked.
437	#[codec(compact)]
438	value: Balance,
439	/// Era number at which point it'll be unlocked.
440	#[codec(compact)]
441	era: EraIndex,
442}
443
444/// The ledger of a (bonded) stash.
445///
446/// Note: All the reads and mutations to the [`Ledger`], [`Bonded`] and [`Payee`] storage items
447/// *MUST* be performed through the methods exposed by this struct, to ensure the consistency of
448/// ledger's data and corresponding staking lock
449///
450/// TODO: move struct definition and full implementation into `/src/ledger.rs`. Currently
451/// leaving here to enforce a clean PR diff, given how critical this logic is. Tracking issue
452/// <https://github.com/paritytech/substrate/issues/14749>.
453#[derive(
454	PartialEqNoBound,
455	EqNoBound,
456	CloneNoBound,
457	Encode,
458	Decode,
459	RuntimeDebugNoBound,
460	TypeInfo,
461	MaxEncodedLen,
462)]
463#[scale_info(skip_type_params(T))]
464pub struct StakingLedger<T: Config> {
465	/// The stash account whose balance is actually locked and at stake.
466	pub stash: T::AccountId,
467
468	/// The total amount of the stash's balance that we are currently accounting for.
469	/// It's just `active` plus all the `unlocking` balances.
470	#[codec(compact)]
471	pub total: BalanceOf<T>,
472
473	/// The total amount of the stash's balance that will be at stake in any forthcoming
474	/// rounds.
475	#[codec(compact)]
476	pub active: BalanceOf<T>,
477
478	/// Any balance that is becoming free, which may eventually be transferred out of the stash
479	/// (assuming it doesn't get slashed first). It is assumed that this will be treated as a first
480	/// in, first out queue where the new (higher value) eras get pushed on the back.
481	pub unlocking: BoundedVec<UnlockChunk<BalanceOf<T>>, T::MaxUnlockingChunks>,
482
483	/// List of eras for which the stakers behind a validator have claimed rewards. Only updated
484	/// for validators.
485	///
486	/// This is deprecated as of V14 in favor of `T::ClaimedRewards` and will be removed in future.
487	/// Refer to issue <https://github.com/paritytech/polkadot-sdk/issues/433>
488	pub legacy_claimed_rewards: BoundedVec<EraIndex, T::HistoryDepth>,
489
490	/// The controller associated with this ledger's stash.
491	///
492	/// This is not stored on-chain, and is only bundled when the ledger is read from storage.
493	/// Use [`controller`] function to get the controller associated with the ledger.
494	#[codec(skip)]
495	controller: Option<T::AccountId>,
496}
497
498/// State of a ledger with regards with its data and metadata integrity.
499#[derive(PartialEq, Debug)]
500enum LedgerIntegrityState {
501	/// Ledger, bond and corresponding staking lock is OK.
502	Ok,
503	/// Ledger and/or bond is corrupted. This means that the bond has a ledger with a different
504	/// stash than the bonded stash.
505	Corrupted,
506	/// Ledger was corrupted and it has been killed.
507	CorruptedKilled,
508	/// Ledger and bond are OK, however the ledger's stash lock is out of sync.
509	LockCorrupted,
510}
511
512impl<T: Config> StakingLedger<T> {
513	/// Remove entries from `unlocking` that are sufficiently old and reduce the
514	/// total by the sum of their balances.
515	fn consolidate_unlocked(self, current_era: EraIndex) -> Self {
516		let mut total = self.total;
517		let unlocking: BoundedVec<_, _> = self
518			.unlocking
519			.into_iter()
520			.filter(|chunk| {
521				if chunk.era > current_era {
522					true
523				} else {
524					total = total.saturating_sub(chunk.value);
525					false
526				}
527			})
528			.collect::<Vec<_>>()
529			.try_into()
530			.expect(
531				"filtering items from a bounded vec always leaves length less than bounds. qed",
532			);
533
534		Self {
535			stash: self.stash,
536			total,
537			active: self.active,
538			unlocking,
539			legacy_claimed_rewards: self.legacy_claimed_rewards,
540			controller: self.controller,
541		}
542	}
543
544	/// Sets ledger total to the `new_total`.
545	///
546	/// Removes entries from `unlocking` upto `amount` starting from the oldest first.
547	fn update_total_stake(mut self, new_total: BalanceOf<T>) -> Self {
548		let old_total = self.total;
549		self.total = new_total;
550		debug_assert!(
551			new_total <= old_total,
552			"new_total {:?} must be <= old_total {:?}",
553			new_total,
554			old_total
555		);
556
557		let to_withdraw = old_total.defensive_saturating_sub(new_total);
558		// accumulator to keep track of how much is withdrawn.
559		// First we take out from active.
560		let mut withdrawn = BalanceOf::<T>::zero();
561
562		// first we try to remove stake from active
563		if self.active >= to_withdraw {
564			self.active -= to_withdraw;
565			return self
566		} else {
567			withdrawn += self.active;
568			self.active = BalanceOf::<T>::zero();
569		}
570
571		// start removing from the oldest chunk.
572		while let Some(last) = self.unlocking.last_mut() {
573			if withdrawn.defensive_saturating_add(last.value) <= to_withdraw {
574				withdrawn += last.value;
575				self.unlocking.pop();
576			} else {
577				let diff = to_withdraw.defensive_saturating_sub(withdrawn);
578				withdrawn += diff;
579				last.value -= diff;
580			}
581
582			if withdrawn >= to_withdraw {
583				break
584			}
585		}
586
587		self
588	}
589
590	/// Re-bond funds that were scheduled for unlocking.
591	///
592	/// Returns the updated ledger, and the amount actually rebonded.
593	fn rebond(mut self, value: BalanceOf<T>) -> (Self, BalanceOf<T>) {
594		let mut unlocking_balance = BalanceOf::<T>::zero();
595
596		while let Some(last) = self.unlocking.last_mut() {
597			if unlocking_balance.defensive_saturating_add(last.value) <= value {
598				unlocking_balance += last.value;
599				self.active += last.value;
600				self.unlocking.pop();
601			} else {
602				let diff = value.defensive_saturating_sub(unlocking_balance);
603
604				unlocking_balance += diff;
605				self.active += diff;
606				last.value -= diff;
607			}
608
609			if unlocking_balance >= value {
610				break
611			}
612		}
613
614		(self, unlocking_balance)
615	}
616
617	/// Slash the staker for a given amount of balance.
618	///
619	/// This implements a proportional slashing system, whereby we set our preference to slash as
620	/// such:
621	///
622	/// - If any unlocking chunks exist that are scheduled to be unlocked at `slash_era +
623	///   bonding_duration` and onwards, the slash is divided equally between the active ledger and
624	///   the unlocking chunks.
625	/// - If no such chunks exist, then only the active balance is slashed.
626	///
627	/// Note that the above is only a *preference*. If for any reason the active ledger, with or
628	/// without some portion of the unlocking chunks that are more justified to be slashed are not
629	/// enough, then the slashing will continue and will consume as much of the active and unlocking
630	/// chunks as needed.
631	///
632	/// This will never slash more than the given amount. If any of the chunks become dusted, the
633	/// last chunk is slashed slightly less to compensate. Returns the amount of funds actually
634	/// slashed.
635	///
636	/// `slash_era` is the era in which the slash (which is being enacted now) actually happened.
637	///
638	/// This calls `Config::OnStakingUpdate::on_slash` with information as to how the slash was
639	/// applied.
640	pub fn slash(
641		&mut self,
642		slash_amount: BalanceOf<T>,
643		minimum_balance: BalanceOf<T>,
644		slash_era: EraIndex,
645	) -> BalanceOf<T> {
646		if slash_amount.is_zero() {
647			return Zero::zero()
648		}
649
650		use sp_runtime::PerThing as _;
651		let mut remaining_slash = slash_amount;
652		let pre_slash_total = self.total;
653
654		// for a `slash_era = x`, any chunk that is scheduled to be unlocked at era `x + 28`
655		// (assuming 28 is the bonding duration) onwards should be slashed.
656		let slashable_chunks_start = slash_era.saturating_add(T::BondingDuration::get());
657
658		// `Some(ratio)` if this is proportional, with `ratio`, `None` otherwise. In both cases, we
659		// slash first the active chunk, and then `slash_chunks_priority`.
660		let (maybe_proportional, slash_chunks_priority) = {
661			if let Some(first_slashable_index) =
662				self.unlocking.iter().position(|c| c.era >= slashable_chunks_start)
663			{
664				// If there exists a chunk who's after the first_slashable_start, then this is a
665				// proportional slash, because we want to slash active and these chunks
666				// proportionally.
667
668				// The indices of the first chunk after the slash up through the most recent chunk.
669				// (The most recent chunk is at greatest from this era)
670				let affected_indices = first_slashable_index..self.unlocking.len();
671				let unbonding_affected_balance =
672					affected_indices.clone().fold(BalanceOf::<T>::zero(), |sum, i| {
673						if let Some(chunk) = self.unlocking.get(i).defensive() {
674							sum.saturating_add(chunk.value)
675						} else {
676							sum
677						}
678					});
679				let affected_balance = self.active.saturating_add(unbonding_affected_balance);
680				let ratio = Perquintill::from_rational_with_rounding(
681					slash_amount,
682					affected_balance,
683					Rounding::Up,
684				)
685				.unwrap_or_else(|_| Perquintill::one());
686				(
687					Some(ratio),
688					affected_indices.chain((0..first_slashable_index).rev()).collect::<Vec<_>>(),
689				)
690			} else {
691				// We just slash from the last chunk to the most recent one, if need be.
692				(None, (0..self.unlocking.len()).rev().collect::<Vec<_>>())
693			}
694		};
695
696		// Helper to update `target` and the ledgers total after accounting for slashing `target`.
697		log!(
698			debug,
699			"slashing {:?} for era {:?} out of {:?}, priority: {:?}, proportional = {:?}",
700			slash_amount,
701			slash_era,
702			self,
703			slash_chunks_priority,
704			maybe_proportional,
705		);
706
707		let mut slash_out_of = |target: &mut BalanceOf<T>, slash_remaining: &mut BalanceOf<T>| {
708			let mut slash_from_target = if let Some(ratio) = maybe_proportional {
709				ratio.mul_ceil(*target)
710			} else {
711				*slash_remaining
712			}
713			// this is the total that that the slash target has. We can't slash more than
714			// this anyhow!
715			.min(*target)
716			// this is the total amount that we would have wanted to slash
717			// non-proportionally, a proportional slash should never exceed this either!
718			.min(*slash_remaining);
719
720			// slash out from *target exactly `slash_from_target`.
721			*target = *target - slash_from_target;
722			if *target < minimum_balance {
723				// Slash the rest of the target if it's dust. This might cause the last chunk to be
724				// slightly under-slashed, by at most `MaxUnlockingChunks * ED`, which is not a big
725				// deal.
726				slash_from_target =
727					core::mem::replace(target, Zero::zero()).saturating_add(slash_from_target)
728			}
729
730			self.total = self.total.saturating_sub(slash_from_target);
731			*slash_remaining = slash_remaining.saturating_sub(slash_from_target);
732		};
733
734		// If this is *not* a proportional slash, the active will always wiped to 0.
735		slash_out_of(&mut self.active, &mut remaining_slash);
736
737		let mut slashed_unlocking = BTreeMap::<_, _>::new();
738		for i in slash_chunks_priority {
739			if remaining_slash.is_zero() {
740				break
741			}
742
743			if let Some(chunk) = self.unlocking.get_mut(i).defensive() {
744				slash_out_of(&mut chunk.value, &mut remaining_slash);
745				// write the new slashed value of this chunk to the map.
746				slashed_unlocking.insert(chunk.era, chunk.value);
747			} else {
748				break
749			}
750		}
751
752		// clean unlocking chunks that are set to zero.
753		self.unlocking.retain(|c| !c.value.is_zero());
754
755		let final_slashed_amount = pre_slash_total.saturating_sub(self.total);
756		T::EventListeners::on_slash(
757			&self.stash,
758			self.active,
759			&slashed_unlocking,
760			final_slashed_amount,
761		);
762		final_slashed_amount
763	}
764}
765
766/// A record of the nominations made by a specific account.
767#[derive(
768	PartialEqNoBound, EqNoBound, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo, MaxEncodedLen,
769)]
770#[codec(mel_bound())]
771#[scale_info(skip_type_params(T))]
772pub struct Nominations<T: Config> {
773	/// The targets of nomination.
774	pub targets: BoundedVec<T::AccountId, MaxNominationsOf<T>>,
775	/// The era the nominations were submitted.
776	///
777	/// Except for initial nominations which are considered submitted at era 0.
778	pub submitted_in: EraIndex,
779	/// Whether the nominations have been suppressed. This can happen due to slashing of the
780	/// validators, or other events that might invalidate the nomination.
781	///
782	/// NOTE: this for future proofing and is thus far not used.
783	pub suppressed: bool,
784}
785
786/// Facade struct to encapsulate `PagedExposureMetadata` and a single page of `ExposurePage`.
787///
788/// This is useful where we need to take into account the validator's own stake and total exposure
789/// in consideration, in addition to the individual nominators backing them.
790#[derive(Encode, Decode, RuntimeDebug, TypeInfo, PartialEq, Eq)]
791pub struct PagedExposure<AccountId, Balance: HasCompact + codec::MaxEncodedLen> {
792	exposure_metadata: PagedExposureMetadata<Balance>,
793	exposure_page: ExposurePage<AccountId, Balance>,
794}
795
796impl<AccountId, Balance: HasCompact + Copy + AtLeast32BitUnsigned + codec::MaxEncodedLen>
797	PagedExposure<AccountId, Balance>
798{
799	/// Create a new instance of `PagedExposure` from legacy clipped exposures.
800	pub fn from_clipped(exposure: Exposure<AccountId, Balance>) -> Self {
801		Self {
802			exposure_metadata: PagedExposureMetadata {
803				total: exposure.total,
804				own: exposure.own,
805				nominator_count: exposure.others.len() as u32,
806				page_count: 1,
807			},
808			exposure_page: ExposurePage { page_total: exposure.total, others: exposure.others },
809		}
810	}
811
812	/// Returns total exposure of this validator across pages
813	pub fn total(&self) -> Balance {
814		self.exposure_metadata.total
815	}
816
817	/// Returns total exposure of this validator for the current page
818	pub fn page_total(&self) -> Balance {
819		self.exposure_page.page_total + self.exposure_metadata.own
820	}
821
822	/// Returns validator's own stake that is exposed
823	pub fn own(&self) -> Balance {
824		self.exposure_metadata.own
825	}
826
827	/// Returns the portions of nominators stashes that are exposed in this page.
828	pub fn others(&self) -> &Vec<IndividualExposure<AccountId, Balance>> {
829		&self.exposure_page.others
830	}
831}
832
833/// A pending slash record. The value of the slash has been computed but not applied yet,
834/// rather deferred for several eras.
835#[derive(Encode, Decode, RuntimeDebug, TypeInfo)]
836pub struct UnappliedSlash<AccountId, Balance: HasCompact> {
837	/// The stash ID of the offending validator.
838	validator: AccountId,
839	/// The validator's own slash.
840	own: Balance,
841	/// All other slashed stakers and amounts.
842	others: Vec<(AccountId, Balance)>,
843	/// Reporters of the offence; bounty payout recipients.
844	reporters: Vec<AccountId>,
845	/// The amount of payout.
846	payout: Balance,
847}
848
849impl<AccountId, Balance: HasCompact + Zero> UnappliedSlash<AccountId, Balance> {
850	/// Initializes the default object using the given `validator`.
851	pub fn default_from(validator: AccountId) -> Self {
852		Self {
853			validator,
854			own: Zero::zero(),
855			others: vec![],
856			reporters: vec![],
857			payout: Zero::zero(),
858		}
859	}
860}
861
862/// Something that defines the maximum number of nominations per nominator based on a curve.
863///
864/// The method `curve` implements the nomination quota curve and should not be used directly.
865/// However, `get_quota` returns the bounded maximum number of nominations based on `fn curve` and
866/// the nominator's balance.
867pub trait NominationsQuota<Balance> {
868	/// Strict maximum number of nominations that caps the nominations curve. This value can be
869	/// used as the upper bound of the number of votes per nominator.
870	type MaxNominations: Get<u32>;
871
872	/// Returns the voter's nomination quota within reasonable bounds [`min`, `max`], where `min`
873	/// is 1 and `max` is `Self::MaxNominations`.
874	fn get_quota(balance: Balance) -> u32 {
875		Self::curve(balance).clamp(1, Self::MaxNominations::get())
876	}
877
878	/// Returns the voter's nomination quota based on its balance and a curve.
879	fn curve(balance: Balance) -> u32;
880}
881
882/// A nomination quota that allows up to MAX nominations for all validators.
883pub struct FixedNominationsQuota<const MAX: u32>;
884impl<Balance, const MAX: u32> NominationsQuota<Balance> for FixedNominationsQuota<MAX> {
885	type MaxNominations = ConstU32<MAX>;
886
887	fn curve(_: Balance) -> u32 {
888		MAX
889	}
890}
891
892/// Means for interacting with a specialized version of the `session` trait.
893///
894/// This is needed because `Staking` sets the `ValidatorIdOf` of the `pallet_session::Config`
895pub trait SessionInterface<AccountId> {
896	/// Disable the validator at the given index, returns `false` if the validator was already
897	/// disabled or the index is out of bounds.
898	fn disable_validator(validator_index: u32) -> bool;
899	/// Get the validators from session.
900	fn validators() -> Vec<AccountId>;
901	/// Prune historical session tries up to but not including the given index.
902	fn prune_historical_up_to(up_to: SessionIndex);
903}
904
905impl<T: Config> SessionInterface<<T as frame_system::Config>::AccountId> for T
906where
907	T: pallet_session::Config<ValidatorId = <T as frame_system::Config>::AccountId>,
908	T: pallet_session::historical::Config<
909		FullIdentification = Exposure<<T as frame_system::Config>::AccountId, BalanceOf<T>>,
910		FullIdentificationOf = ExposureOf<T>,
911	>,
912	T::SessionHandler: pallet_session::SessionHandler<<T as frame_system::Config>::AccountId>,
913	T::SessionManager: pallet_session::SessionManager<<T as frame_system::Config>::AccountId>,
914	T::ValidatorIdOf: Convert<
915		<T as frame_system::Config>::AccountId,
916		Option<<T as frame_system::Config>::AccountId>,
917	>,
918{
919	fn disable_validator(validator_index: u32) -> bool {
920		<pallet_session::Pallet<T>>::disable_index(validator_index)
921	}
922
923	fn validators() -> Vec<<T as frame_system::Config>::AccountId> {
924		<pallet_session::Pallet<T>>::validators()
925	}
926
927	fn prune_historical_up_to(up_to: SessionIndex) {
928		<pallet_session::historical::Pallet<T>>::prune_up_to(up_to);
929	}
930}
931
932impl<AccountId> SessionInterface<AccountId> for () {
933	fn disable_validator(_: u32) -> bool {
934		true
935	}
936	fn validators() -> Vec<AccountId> {
937		Vec::new()
938	}
939	fn prune_historical_up_to(_: SessionIndex) {
940		()
941	}
942}
943
944/// Handler for determining how much of a balance should be paid out on the current era.
945pub trait EraPayout<Balance> {
946	/// Determine the payout for this era.
947	///
948	/// Returns the amount to be paid to stakers in this era, as well as whatever else should be
949	/// paid out ("the rest").
950	fn era_payout(
951		total_staked: Balance,
952		total_issuance: Balance,
953		era_duration_millis: u64,
954	) -> (Balance, Balance);
955}
956
957impl<Balance: Default> EraPayout<Balance> for () {
958	fn era_payout(
959		_total_staked: Balance,
960		_total_issuance: Balance,
961		_era_duration_millis: u64,
962	) -> (Balance, Balance) {
963		(Default::default(), Default::default())
964	}
965}
966
967/// Adaptor to turn a `PiecewiseLinear` curve definition into an `EraPayout` impl, used for
968/// backwards compatibility.
969pub struct ConvertCurve<T>(core::marker::PhantomData<T>);
970impl<Balance, T> EraPayout<Balance> for ConvertCurve<T>
971where
972	Balance: AtLeast32BitUnsigned + Clone + Copy,
973	T: Get<&'static PiecewiseLinear<'static>>,
974{
975	fn era_payout(
976		total_staked: Balance,
977		total_issuance: Balance,
978		era_duration_millis: u64,
979	) -> (Balance, Balance) {
980		let (validator_payout, max_payout) = inflation::compute_total_payout(
981			T::get(),
982			total_staked,
983			total_issuance,
984			// Duration of era; more than u64::MAX is rewarded as u64::MAX.
985			era_duration_millis,
986		);
987		let rest = max_payout.saturating_sub(validator_payout);
988		(validator_payout, rest)
989	}
990}
991
992/// Mode of era-forcing.
993#[derive(
994	Copy,
995	Clone,
996	PartialEq,
997	Eq,
998	Encode,
999	Decode,
1000	RuntimeDebug,
1001	TypeInfo,
1002	MaxEncodedLen,
1003	serde::Serialize,
1004	serde::Deserialize,
1005)]
1006pub enum Forcing {
1007	/// Not forcing anything - just let whatever happen.
1008	NotForcing,
1009	/// Force a new era, then reset to `NotForcing` as soon as it is done.
1010	/// Note that this will force to trigger an election until a new era is triggered, if the
1011	/// election failed, the next session end will trigger a new election again, until success.
1012	ForceNew,
1013	/// Avoid a new era indefinitely.
1014	ForceNone,
1015	/// Force a new era at the end of all sessions indefinitely.
1016	ForceAlways,
1017}
1018
1019impl Default for Forcing {
1020	fn default() -> Self {
1021		Forcing::NotForcing
1022	}
1023}
1024
1025/// A `Convert` implementation that finds the stash of the given controller account,
1026/// if any.
1027pub struct StashOf<T>(core::marker::PhantomData<T>);
1028
1029impl<T: Config> Convert<T::AccountId, Option<T::AccountId>> for StashOf<T> {
1030	fn convert(controller: T::AccountId) -> Option<T::AccountId> {
1031		StakingLedger::<T>::paired_account(StakingAccount::Controller(controller))
1032	}
1033}
1034
1035/// A typed conversion from stash account ID to the active exposure of nominators
1036/// on that account.
1037///
1038/// Active exposure is the exposure of the validator set currently validating, i.e. in
1039/// `active_era`. It can differ from the latest planned exposure in `current_era`.
1040pub struct ExposureOf<T>(core::marker::PhantomData<T>);
1041
1042impl<T: Config> Convert<T::AccountId, Option<Exposure<T::AccountId, BalanceOf<T>>>>
1043	for ExposureOf<T>
1044{
1045	fn convert(validator: T::AccountId) -> Option<Exposure<T::AccountId, BalanceOf<T>>> {
1046		<Pallet<T>>::active_era()
1047			.map(|active_era| <Pallet<T>>::eras_stakers(active_era.index, &validator))
1048	}
1049}
1050
1051/// Filter historical offences out and only allow those from the bonding period.
1052pub struct FilterHistoricalOffences<T, R> {
1053	_inner: core::marker::PhantomData<(T, R)>,
1054}
1055
1056impl<T, Reporter, Offender, R, O> ReportOffence<Reporter, Offender, O>
1057	for FilterHistoricalOffences<Pallet<T>, R>
1058where
1059	T: Config,
1060	R: ReportOffence<Reporter, Offender, O>,
1061	O: Offence<Offender>,
1062{
1063	fn report_offence(reporters: Vec<Reporter>, offence: O) -> Result<(), OffenceError> {
1064		// Disallow any slashing from before the current bonding period.
1065		let offence_session = offence.session_index();
1066		let bonded_eras = BondedEras::<T>::get();
1067
1068		if bonded_eras.first().filter(|(_, start)| offence_session >= *start).is_some() {
1069			R::report_offence(reporters, offence)
1070		} else {
1071			<Pallet<T>>::deposit_event(Event::<T>::OldSlashingReportDiscarded {
1072				session_index: offence_session,
1073			});
1074			Ok(())
1075		}
1076	}
1077
1078	fn is_known_offence(offenders: &[Offender], time_slot: &O::TimeSlot) -> bool {
1079		R::is_known_offence(offenders, time_slot)
1080	}
1081}
1082
1083/// Wrapper struct for Era related information. It is not a pure encapsulation as these storage
1084/// items can be accessed directly but nevertheless, its recommended to use `EraInfo` where we
1085/// can and add more functions to it as needed.
1086pub struct EraInfo<T>(core::marker::PhantomData<T>);
1087impl<T: Config> EraInfo<T> {
1088	/// Returns true if validator has one or more page of era rewards not claimed yet.
1089	// Also looks at legacy storage that can be cleaned up after #433.
1090	pub fn pending_rewards(era: EraIndex, validator: &T::AccountId) -> bool {
1091		let page_count = if let Some(overview) = <ErasStakersOverview<T>>::get(&era, validator) {
1092			overview.page_count
1093		} else {
1094			if <ErasStakers<T>>::contains_key(era, validator) {
1095				// this means non paged exposure, and we treat them as single paged.
1096				1
1097			} else {
1098				// if no exposure, then no rewards to claim.
1099				return false
1100			}
1101		};
1102
1103		// check if era is marked claimed in legacy storage.
1104		if <Ledger<T>>::get(validator)
1105			.map(|l| l.legacy_claimed_rewards.contains(&era))
1106			.unwrap_or_default()
1107		{
1108			return false
1109		}
1110
1111		ClaimedRewards::<T>::get(era, validator).len() < page_count as usize
1112	}
1113
1114	/// Temporary function which looks at both (1) passed param `T::StakingLedger` for legacy
1115	/// non-paged rewards, and (2) `T::ClaimedRewards` for paged rewards. This function can be
1116	/// removed once `T::HistoryDepth` eras have passed and none of the older non-paged rewards
1117	/// are relevant/claimable.
1118	// Refer tracker issue for cleanup: https://github.com/paritytech/polkadot-sdk/issues/433
1119	pub(crate) fn is_rewards_claimed_with_legacy_fallback(
1120		era: EraIndex,
1121		ledger: &StakingLedger<T>,
1122		validator: &T::AccountId,
1123		page: Page,
1124	) -> bool {
1125		ledger.legacy_claimed_rewards.binary_search(&era).is_ok() ||
1126			Self::is_rewards_claimed(era, validator, page)
1127	}
1128
1129	/// Check if the rewards for the given era and page index have been claimed.
1130	///
1131	/// This is only used for paged rewards. Once older non-paged rewards are no longer
1132	/// relevant, `is_rewards_claimed_with_legacy_fallback` can be removed and this function can
1133	/// be made public.
1134	fn is_rewards_claimed(era: EraIndex, validator: &T::AccountId, page: Page) -> bool {
1135		ClaimedRewards::<T>::get(era, validator).contains(&page)
1136	}
1137
1138	/// Get exposure for a validator at a given era and page.
1139	///
1140	/// This builds a paged exposure from `PagedExposureMetadata` and `ExposurePage` of the
1141	/// validator. For older non-paged exposure, it returns the clipped exposure directly.
1142	pub fn get_paged_exposure(
1143		era: EraIndex,
1144		validator: &T::AccountId,
1145		page: Page,
1146	) -> Option<PagedExposure<T::AccountId, BalanceOf<T>>> {
1147		let overview = <ErasStakersOverview<T>>::get(&era, validator);
1148
1149		// return clipped exposure if page zero and paged exposure does not exist
1150		// exists for backward compatibility and can be removed as part of #13034
1151		if overview.is_none() && page == 0 {
1152			return Some(PagedExposure::from_clipped(<ErasStakersClipped<T>>::get(era, validator)))
1153		}
1154
1155		// no exposure for this validator
1156		if overview.is_none() {
1157			return None
1158		}
1159
1160		let overview = overview.expect("checked above; qed");
1161
1162		// validator stake is added only in page zero
1163		let validator_stake = if page == 0 { overview.own } else { Zero::zero() };
1164
1165		// since overview is present, paged exposure will always be present except when a
1166		// validator has only own stake and no nominator stake.
1167		let exposure_page = <ErasStakersPaged<T>>::get((era, validator, page)).unwrap_or_default();
1168
1169		// build the exposure
1170		Some(PagedExposure {
1171			exposure_metadata: PagedExposureMetadata { own: validator_stake, ..overview },
1172			exposure_page,
1173		})
1174	}
1175
1176	/// Get full exposure of the validator at a given era.
1177	pub fn get_full_exposure(
1178		era: EraIndex,
1179		validator: &T::AccountId,
1180	) -> Exposure<T::AccountId, BalanceOf<T>> {
1181		let overview = <ErasStakersOverview<T>>::get(&era, validator);
1182
1183		if overview.is_none() {
1184			return ErasStakers::<T>::get(era, validator)
1185		}
1186
1187		let overview = overview.expect("checked above; qed");
1188
1189		let mut others = Vec::with_capacity(overview.nominator_count as usize);
1190		for page in 0..overview.page_count {
1191			let nominators = <ErasStakersPaged<T>>::get((era, validator, page));
1192			others.append(&mut nominators.map(|n| n.others).defensive_unwrap_or_default());
1193		}
1194
1195		Exposure { total: overview.total, own: overview.own, others }
1196	}
1197
1198	/// Returns the number of pages of exposure a validator has for the given era.
1199	///
1200	/// For eras where paged exposure does not exist, this returns 1 to keep backward compatibility.
1201	pub(crate) fn get_page_count(era: EraIndex, validator: &T::AccountId) -> Page {
1202		<ErasStakersOverview<T>>::get(&era, validator)
1203			.map(|overview| {
1204				if overview.page_count == 0 && overview.own > Zero::zero() {
1205					// Even though there are no nominator pages, there is still validator's own
1206					// stake exposed which needs to be paid out in a page.
1207					1
1208				} else {
1209					overview.page_count
1210				}
1211			})
1212			// Always returns 1 page for older non-paged exposure.
1213			// FIXME: Can be cleaned up with issue #13034.
1214			.unwrap_or(1)
1215	}
1216
1217	/// Returns the next page that can be claimed or `None` if nothing to claim.
1218	pub(crate) fn get_next_claimable_page(
1219		era: EraIndex,
1220		validator: &T::AccountId,
1221		ledger: &StakingLedger<T>,
1222	) -> Option<Page> {
1223		if Self::is_non_paged_exposure(era, validator) {
1224			return match ledger.legacy_claimed_rewards.binary_search(&era) {
1225				// already claimed
1226				Ok(_) => None,
1227				// Non-paged exposure is considered as a single page
1228				Err(_) => Some(0),
1229			}
1230		}
1231
1232		// Find next claimable page of paged exposure.
1233		let page_count = Self::get_page_count(era, validator);
1234		let all_claimable_pages: Vec<Page> = (0..page_count).collect();
1235		let claimed_pages = ClaimedRewards::<T>::get(era, validator);
1236
1237		all_claimable_pages.into_iter().find(|p| !claimed_pages.contains(p))
1238	}
1239
1240	/// Checks if exposure is paged or not.
1241	fn is_non_paged_exposure(era: EraIndex, validator: &T::AccountId) -> bool {
1242		<ErasStakersClipped<T>>::contains_key(&era, validator)
1243	}
1244
1245	/// Returns validator commission for this era and page.
1246	pub(crate) fn get_validator_commission(
1247		era: EraIndex,
1248		validator_stash: &T::AccountId,
1249	) -> Perbill {
1250		<ErasValidatorPrefs<T>>::get(&era, validator_stash).commission
1251	}
1252
1253	/// Creates an entry to track validator reward has been claimed for a given era and page.
1254	/// Noop if already claimed.
1255	pub(crate) fn set_rewards_as_claimed(era: EraIndex, validator: &T::AccountId, page: Page) {
1256		let mut claimed_pages = ClaimedRewards::<T>::get(era, validator);
1257
1258		// this should never be called if the reward has already been claimed
1259		if claimed_pages.contains(&page) {
1260			defensive!("Trying to set an already claimed reward");
1261			// nevertheless don't do anything since the page already exist in claimed rewards.
1262			return
1263		}
1264
1265		// add page to claimed entries
1266		claimed_pages.push(page);
1267		ClaimedRewards::<T>::insert(era, validator, claimed_pages);
1268	}
1269
1270	/// Store exposure for elected validators at start of an era.
1271	pub fn set_exposure(
1272		era: EraIndex,
1273		validator: &T::AccountId,
1274		exposure: Exposure<T::AccountId, BalanceOf<T>>,
1275	) {
1276		let page_size = T::MaxExposurePageSize::get().defensive_max(1);
1277
1278		let nominator_count = exposure.others.len();
1279		// expected page count is the number of nominators divided by the page size, rounded up.
1280		let expected_page_count = nominator_count
1281			.defensive_saturating_add((page_size as usize).defensive_saturating_sub(1))
1282			.saturating_div(page_size as usize);
1283
1284		let (exposure_metadata, exposure_pages) = exposure.into_pages(page_size);
1285		defensive_assert!(exposure_pages.len() == expected_page_count, "unexpected page count");
1286
1287		<ErasStakersOverview<T>>::insert(era, &validator, &exposure_metadata);
1288		exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| {
1289			<ErasStakersPaged<T>>::insert((era, &validator, page as Page), &paged_exposure);
1290		});
1291	}
1292
1293	/// Store total exposure for all the elected validators in the era.
1294	pub(crate) fn set_total_stake(era: EraIndex, total_stake: BalanceOf<T>) {
1295		<ErasTotalStake<T>>::insert(era, total_stake);
1296	}
1297}
1298
1299/// A utility struct that provides a way to check if a given account is a staker.
1300///
1301/// This struct implements the `Contains` trait, allowing it to determine whether
1302/// a particular account is currently staking by checking if the account exists in
1303/// the staking ledger.
1304pub struct AllStakers<T: Config>(core::marker::PhantomData<T>);
1305
1306impl<T: Config> Contains<T::AccountId> for AllStakers<T> {
1307	/// Checks if the given account ID corresponds to a staker.
1308	///
1309	/// # Returns
1310	/// - `true` if the account has an entry in the staking ledger (indicating it is staking).
1311	/// - `false` otherwise.
1312	fn contains(account: &T::AccountId) -> bool {
1313		Ledger::<T>::contains_key(account)
1314	}
1315}
1316
1317/// Configurations of the benchmarking of the pallet.
1318pub trait BenchmarkingConfig {
1319	/// The maximum number of validators to use.
1320	type MaxValidators: Get<u32>;
1321	/// The maximum number of nominators to use.
1322	type MaxNominators: Get<u32>;
1323}
1324
1325/// A mock benchmarking config for pallet-staking.
1326///
1327/// Should only be used for testing.
1328#[cfg(feature = "std")]
1329pub struct TestBenchmarkingConfig;
1330
1331#[cfg(feature = "std")]
1332impl BenchmarkingConfig for TestBenchmarkingConfig {
1333	type MaxValidators = frame_support::traits::ConstU32<100>;
1334	type MaxNominators = frame_support::traits::ConstU32<100>;
1335}
1336
1337/// Controls validator disabling
1338pub trait DisablingStrategy<T: Config> {
1339	/// Make a disabling decision. Returns the index of the validator to disable or `None` if no new
1340	/// validator should be disabled.
1341	fn decision(
1342		offender_stash: &T::AccountId,
1343		slash_era: EraIndex,
1344		currently_disabled: &Vec<u32>,
1345	) -> Option<u32>;
1346}
1347
1348/// Implementation of [`DisablingStrategy`] which disables validators from the active set up to a
1349/// threshold. `DISABLING_LIMIT_FACTOR` is the factor of the maximum disabled validators in the
1350/// active set. E.g. setting this value to `3` means no more than 1/3 of the validators in the
1351/// active set can be disabled in an era.
1352/// By default a factor of 3 is used which is the byzantine threshold.
1353pub struct UpToLimitDisablingStrategy<const DISABLING_LIMIT_FACTOR: usize = 3>;
1354
1355impl<const DISABLING_LIMIT_FACTOR: usize> UpToLimitDisablingStrategy<DISABLING_LIMIT_FACTOR> {
1356	/// Disabling limit calculated from the total number of validators in the active set. When
1357	/// reached no more validators will be disabled.
1358	pub fn disable_limit(validators_len: usize) -> usize {
1359		validators_len
1360			.saturating_sub(1)
1361			.checked_div(DISABLING_LIMIT_FACTOR)
1362			.unwrap_or_else(|| {
1363				defensive!("DISABLING_LIMIT_FACTOR should not be 0");
1364				0
1365			})
1366	}
1367}
1368
1369impl<T: Config, const DISABLING_LIMIT_FACTOR: usize> DisablingStrategy<T>
1370	for UpToLimitDisablingStrategy<DISABLING_LIMIT_FACTOR>
1371{
1372	fn decision(
1373		offender_stash: &T::AccountId,
1374		slash_era: EraIndex,
1375		currently_disabled: &Vec<u32>,
1376	) -> Option<u32> {
1377		let active_set = T::SessionInterface::validators();
1378
1379		// We don't disable more than the limit
1380		if currently_disabled.len() >= Self::disable_limit(active_set.len()) {
1381			log!(
1382				debug,
1383				"Won't disable: reached disabling limit {:?}",
1384				Self::disable_limit(active_set.len())
1385			);
1386			return None
1387		}
1388
1389		// We don't disable for offences in previous eras
1390		if ActiveEra::<T>::get().map(|e| e.index).unwrap_or_default() > slash_era {
1391			log!(
1392				debug,
1393				"Won't disable: current_era {:?} > slash_era {:?}",
1394				Pallet::<T>::current_era().unwrap_or_default(),
1395				slash_era
1396			);
1397			return None
1398		}
1399
1400		let offender_idx = if let Some(idx) = active_set.iter().position(|i| i == offender_stash) {
1401			idx as u32
1402		} else {
1403			log!(debug, "Won't disable: offender not in active set",);
1404			return None
1405		};
1406
1407		log!(debug, "Will disable {:?}", offender_idx);
1408
1409		Some(offender_idx)
1410	}
1411}