referrerpolicy=no-referrer-when-downgrade

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