pallet_staking_async/pallet/mod.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//! `pallet-staking-async`'s main `pallet` module.
19
20use crate::{
21 asset, slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout,
22 EraRewardPoints, ExposurePage, Forcing, LedgerIntegrityState, MaxNominationsOf,
23 NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination,
24 StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs,
25};
26use alloc::{format, vec::Vec};
27use codec::Codec;
28use frame_election_provider_support::{ElectionProvider, SortedListProvider, VoteWeight};
29use frame_support::{
30 assert_ok,
31 pallet_prelude::*,
32 traits::{
33 fungible::{
34 hold::{Balanced as FunHoldBalanced, Mutate as FunHoldMutate},
35 Mutate, Mutate as FunMutate,
36 },
37 Contains, Defensive, DefensiveSaturating, EnsureOrigin, Get, InspectLockableCurrency,
38 Nothing, OnUnbalanced,
39 },
40 weights::Weight,
41 BoundedBTreeSet, BoundedVec,
42};
43use frame_system::{ensure_root, ensure_signed, pallet_prelude::*};
44pub use impls::*;
45use rand::seq::SliceRandom;
46use rand_chacha::{
47 rand_core::{RngCore, SeedableRng},
48 ChaChaRng,
49};
50use sp_core::{sr25519::Pair as SrPair, Pair};
51use sp_runtime::{
52 traits::{StaticLookup, Zero},
53 ArithmeticError, Perbill, Percent,
54};
55use sp_staking::{
56 EraIndex, Page, SessionIndex,
57 StakingAccount::{self, Controller, Stash},
58 StakingInterface,
59};
60
61mod impls;
62
63#[frame_support::pallet]
64pub mod pallet {
65 use core::ops::Deref;
66
67 use super::*;
68 use crate::{session_rotation, PagedExposureMetadata, SnapshotStatus};
69 use codec::HasCompact;
70 use frame_election_provider_support::{ElectionDataProvider, PageIndex};
71 use frame_support::{traits::ConstBool, DefaultNoBound};
72
73 /// Represents the current step in the era pruning process
74 #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
75 pub enum PruningStep {
76 /// Pruning ErasStakersPaged storage
77 ErasStakersPaged,
78 /// Pruning ErasStakersOverview storage
79 ErasStakersOverview,
80 /// Pruning ErasValidatorPrefs storage
81 ErasValidatorPrefs,
82 /// Pruning ClaimedRewards storage
83 ClaimedRewards,
84 /// Pruning ErasValidatorReward storage
85 ErasValidatorReward,
86 /// Pruning ErasRewardPoints storage
87 ErasRewardPoints,
88 /// Pruning single-entry storages: ErasTotalStake and ErasNominatorsSlashable
89 SingleEntryCleanups,
90 /// Pruning ValidatorSlashInEra storage
91 ValidatorSlashInEra,
92 }
93
94 /// The in-code storage version.
95 const STORAGE_VERSION: StorageVersion = StorageVersion::new(17);
96
97 #[pallet::pallet]
98 #[pallet::storage_version(STORAGE_VERSION)]
99 pub struct Pallet<T>(_);
100
101 /// Possible operations on the configuration values of this pallet.
102 #[derive(TypeInfo, Debug, Clone, Encode, Decode, DecodeWithMemTracking, PartialEq)]
103 pub enum ConfigOp<T: Default + Codec> {
104 /// Don't change.
105 Noop,
106 /// Set the given value.
107 Set(T),
108 /// Remove from storage.
109 Remove,
110 }
111
112 #[pallet::config(with_default)]
113 pub trait Config: frame_system::Config {
114 /// The old trait for staking balance. Deprecated and only used for migrating old ledgers.
115 #[pallet::no_default]
116 type OldCurrency: InspectLockableCurrency<
117 Self::AccountId,
118 Moment = BlockNumberFor<Self>,
119 Balance = Self::CurrencyBalance,
120 >;
121
122 /// The staking balance.
123 #[pallet::no_default]
124 type Currency: FunHoldMutate<
125 Self::AccountId,
126 Reason = Self::RuntimeHoldReason,
127 Balance = Self::CurrencyBalance,
128 > + FunMutate<Self::AccountId, Balance = Self::CurrencyBalance>
129 + FunHoldBalanced<Self::AccountId, Balance = Self::CurrencyBalance>;
130
131 /// Overarching hold reason.
132 #[pallet::no_default_bounds]
133 type RuntimeHoldReason: From<HoldReason>;
134
135 /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to
136 /// `From<u64>`.
137 type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned
138 + codec::FullCodec
139 + DecodeWithMemTracking
140 + HasCompact<Type: DecodeWithMemTracking>
141 + Copy
142 + MaybeSerializeDeserialize
143 + core::fmt::Debug
144 + Default
145 + From<u64>
146 + TypeInfo
147 + Send
148 + Sync
149 + MaxEncodedLen;
150
151 /// Convert a balance into a number used for election calculation. This must fit into a
152 /// `u64` but is allowed to be sensibly lossy. The `u64` is used to communicate with the
153 /// [`frame_election_provider_support`] crate which accepts u64 numbers and does operations
154 /// in 128.
155 /// Consequently, the backward convert is used convert the u128s from sp-elections back to a
156 /// [`BalanceOf`].
157 #[pallet::no_default_bounds]
158 type CurrencyToVote: sp_staking::currency_to_vote::CurrencyToVote<BalanceOf<Self>>;
159
160 /// Something that provides the election functionality.
161 #[pallet::no_default]
162 type ElectionProvider: ElectionProvider<
163 AccountId = Self::AccountId,
164 BlockNumber = BlockNumberFor<Self>,
165 // we only accept an election provider that has staking as data provider.
166 DataProvider = Pallet<Self>,
167 >;
168
169 /// Something that defines the maximum number of nominations per nominator.
170 #[pallet::no_default_bounds]
171 type NominationsQuota: NominationsQuota<BalanceOf<Self>>;
172
173 /// Number of eras to keep in history.
174 ///
175 /// Following information is kept for eras in `[current_era -
176 /// HistoryDepth, current_era]`: `ErasValidatorPrefs`, `ErasValidatorReward`,
177 /// `ErasRewardPoints`, `ErasTotalStake`, `ClaimedRewards`,
178 /// `ErasStakersPaged`, `ErasStakersOverview`.
179 ///
180 /// Must be more than the number of eras delayed by session.
181 /// I.e. active era must always be in history. I.e. `active_era >
182 /// current_era - history_depth` must be guaranteed.
183 ///
184 /// If migrating an existing pallet from storage value to config value,
185 /// this should be set to same value or greater as in storage.
186 #[pallet::constant]
187 type HistoryDepth: Get<u32>;
188
189 /// Tokens have been minted and are unused for validator-reward.
190 /// See [Era payout](./index.html#era-payout).
191 #[pallet::no_default_bounds]
192 type RewardRemainder: OnUnbalanced<NegativeImbalanceOf<Self>>;
193
194 /// Handler for the unbalanced reduction when slashing a staker.
195 #[pallet::no_default_bounds]
196 type Slash: OnUnbalanced<NegativeImbalanceOf<Self>>;
197
198 /// Handler for the unbalanced increment when rewarding a staker.
199 /// NOTE: in most cases, the implementation of `OnUnbalanced` should modify the total
200 /// issuance.
201 #[pallet::no_default_bounds]
202 type Reward: OnUnbalanced<PositiveImbalanceOf<Self>>;
203
204 /// Number of sessions per era, as per the preferences of the **relay chain**.
205 #[pallet::constant]
206 type SessionsPerEra: Get<SessionIndex>;
207
208 /// Number of sessions before the end of an era when the election for the next era will
209 /// start.
210 ///
211 /// - This determines how many sessions **before** the last session of the era the staking
212 /// election process should begin.
213 /// - The value is bounded between **1** (election starts at the beginning of the last
214 /// session) and `SessionsPerEra` (election starts at the beginning of the first session
215 /// of the era).
216 ///
217 /// ### Example:
218 /// - If `SessionsPerEra = 6` and `PlanningEraOffset = 1`, the election starts at the
219 /// beginning of session `6 - 1 = 5`.
220 /// - If `PlanningEraOffset = 6`, the election starts at the beginning of session `6 - 6 =
221 /// 0`, meaning it starts at the very beginning of the era.
222 #[pallet::constant]
223 type PlanningEraOffset: Get<SessionIndex>;
224
225 /// Number of eras that staked funds must remain bonded for.
226 ///
227 /// This is the bonding duration for validators. Nominators may have a shorter bonding
228 /// duration when [`AreNominatorsSlashable`] is set to `false` (see
229 /// [`StakingInterface::nominator_bonding_duration`]).
230 #[pallet::constant]
231 type BondingDuration: Get<EraIndex>;
232
233 /// Number of eras nominators must wait to unbond when they are not slashable.
234 ///
235 /// This duration is used for nominators when [`AreNominatorsSlashable`] is `false`.
236 /// When nominators are slashable, they use the full [`Config::BondingDuration`] to ensure
237 /// slashes can be applied during the unbonding period.
238 ///
239 /// Setting this to a lower value (e.g., 1 era) allows for faster withdrawals when
240 /// nominators are not subject to slashing risk.
241 #[pallet::constant]
242 type NominatorFastUnbondDuration: Get<EraIndex>;
243
244 /// Number of eras that slashes are deferred by, after computation.
245 ///
246 /// This should be less than the bonding duration. Set to 0 if slashes
247 /// should be applied immediately, without opportunity for intervention.
248 #[pallet::constant]
249 type SlashDeferDuration: Get<EraIndex>;
250
251 /// The origin which can manage less critical staking parameters that does not require root.
252 ///
253 /// Supported actions: (1) cancel deferred slash, (2) set minimum commission.
254 #[pallet::no_default]
255 type AdminOrigin: EnsureOrigin<Self::RuntimeOrigin>;
256
257 /// The payout for validators and the system for the current era.
258 /// See [Era payout](./index.html#era-payout).
259 #[pallet::no_default]
260 type EraPayout: EraPayout<BalanceOf<Self>>;
261
262 /// The maximum size of each `T::ExposurePage`.
263 ///
264 /// An `ExposurePage` is weakly bounded to a maximum of `MaxExposurePageSize`
265 /// nominators.
266 ///
267 /// For older non-paged exposure, a reward payout was restricted to the top
268 /// `MaxExposurePageSize` nominators. This is to limit the i/o cost for the
269 /// nominator payout.
270 ///
271 /// Note: `MaxExposurePageSize` is used to bound `ClaimedRewards` and is unsafe to
272 /// reduce without handling it in a migration.
273 #[pallet::constant]
274 type MaxExposurePageSize: Get<u32>;
275
276 /// The absolute maximum of winner validators this pallet should return.
277 ///
278 /// As this pallet supports multi-block election, the set of winner validators *per
279 /// election* is bounded by this type.
280 #[pallet::constant]
281 type MaxValidatorSet: Get<u32>;
282
283 /// Something that provides a best-effort sorted list of voters aka electing nominators,
284 /// used for NPoS election.
285 ///
286 /// The changes to nominators are reported to this. Moreover, each validator's self-vote is
287 /// also reported as one independent vote.
288 ///
289 /// To keep the load off the chain as much as possible, changes made to the staked amount
290 /// via rewards and slashes are not reported and thus need to be manually fixed by the
291 /// staker. In case of `bags-list`, this always means using `rebag` and `putInFrontOf`.
292 ///
293 /// Invariant: what comes out of this list will always be a nominator.
294 #[pallet::no_default]
295 type VoterList: SortedListProvider<Self::AccountId, Score = VoteWeight>;
296
297 /// WIP: This is a noop as of now, the actual business logic that's described below is going
298 /// to be introduced in a follow-up PR.
299 ///
300 /// Something that provides a best-effort sorted list of targets aka electable validators,
301 /// used for NPoS election.
302 ///
303 /// The changes to the approval stake of each validator are reported to this. This means any
304 /// change to:
305 /// 1. The stake of any validator or nominator.
306 /// 2. The targets of any nominator
307 /// 3. The role of any staker (e.g. validator -> chilled, nominator -> validator, etc)
308 ///
309 /// Unlike `VoterList`, the values in this list are always kept up to date with reward and
310 /// slash as well, and thus represent the accurate approval stake of all account being
311 /// nominated by nominators.
312 ///
313 /// Note that while at the time of nomination, all targets are checked to be real
314 /// validators, they can chill at any point, and their approval stakes will still be
315 /// recorded. This implies that what comes out of iterating this list MIGHT NOT BE AN ACTIVE
316 /// VALIDATOR.
317 #[pallet::no_default]
318 type TargetList: SortedListProvider<Self::AccountId, Score = BalanceOf<Self>>;
319
320 /// The maximum number of `unlocking` chunks a [`StakingLedger`] can
321 /// have. Effectively determines how many unique eras a staker may be
322 /// unbonding in.
323 ///
324 /// Note: `MaxUnlockingChunks` is used as the upper bound for the
325 /// `BoundedVec` item `StakingLedger.unlocking`. Setting this value
326 /// lower than the existing value can lead to inconsistencies in the
327 /// `StakingLedger` and will need to be handled properly in a runtime
328 /// migration. The test `reducing_max_unlocking_chunks_abrupt` shows
329 /// this effect.
330 #[pallet::constant]
331 type MaxUnlockingChunks: Get<u32>;
332
333 /// The maximum amount of controller accounts that can be deprecated in one call.
334 type MaxControllersInDeprecationBatch: Get<u32>;
335
336 /// Something that listens to staking updates and performs actions based on the data it
337 /// receives.
338 ///
339 /// WARNING: this only reports slashing and withdraw events for the time being.
340 #[pallet::no_default_bounds]
341 type EventListeners: sp_staking::OnStakingUpdate<Self::AccountId, BalanceOf<Self>>;
342
343 /// Maximum number of invulnerable validators.
344 #[pallet::constant]
345 type MaxInvulnerables: Get<u32>;
346
347 /// Maximum allowed era duration in milliseconds.
348 ///
349 /// This provides a defensive upper bound to cap the effective era duration, preventing
350 /// excessively long eras from causing runaway inflation (e.g., due to bugs). If the actual
351 /// era duration exceeds this value, it will be clamped to this maximum.
352 ///
353 /// Example: For an ideal era duration of 24 hours (86,400,000 ms),
354 /// this can be set to 604,800,000 ms (7 days).
355 #[pallet::constant]
356 type MaxEraDuration: Get<u64>;
357
358 /// Maximum number of storage items that can be pruned in a single call.
359 ///
360 /// This controls how many storage items can be deleted in each call to `prune_era_step`.
361 /// This should be set to a conservative value (e.g., 100-500 items) to ensure pruning
362 /// doesn't consume too much block space. The actual weight is determined by benchmarks.
363 #[pallet::constant]
364 type MaxPruningItems: Get<u32>;
365
366 /// Interface to talk to the RC-Client pallet, possibly sending election results to the
367 /// relay chain.
368 #[pallet::no_default]
369 type RcClientInterface: pallet_staking_async_rc_client::RcClientInterface<
370 AccountId = Self::AccountId,
371 >;
372
373 #[pallet::no_default_bounds]
374 /// Filter some accounts from participating in staking.
375 ///
376 /// This is useful for example to blacklist an account that is participating in staking in
377 /// another way (such as pools).
378 type Filter: Contains<Self::AccountId>;
379
380 /// Weight information for extrinsics in this pallet.
381 type WeightInfo: WeightInfo;
382 }
383
384 /// A reason for placing a hold on funds.
385 #[pallet::composite_enum]
386 pub enum HoldReason {
387 /// Funds on stake by a nominator or a validator.
388 #[codec(index = 0)]
389 Staking,
390 }
391
392 /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`].
393 pub mod config_preludes {
394 use super::*;
395 use frame_support::{derive_impl, parameter_types, traits::ConstU32};
396 pub struct TestDefaultConfig;
397
398 #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
399 impl frame_system::DefaultConfig for TestDefaultConfig {}
400
401 parameter_types! {
402 pub const SessionsPerEra: SessionIndex = 3;
403 pub const BondingDuration: EraIndex = 3;
404 pub const NominatorFastUnbondDuration: EraIndex = 2;
405 pub const MaxPruningItems: u32 = 100;
406 }
407
408 #[frame_support::register_default_impl(TestDefaultConfig)]
409 impl DefaultConfig for TestDefaultConfig {
410 #[inject_runtime_type]
411 type RuntimeHoldReason = ();
412 type CurrencyBalance = u128;
413 type CurrencyToVote = ();
414 type NominationsQuota = crate::FixedNominationsQuota<16>;
415 type HistoryDepth = ConstU32<84>;
416 type RewardRemainder = ();
417 type Slash = ();
418 type Reward = ();
419 type SessionsPerEra = SessionsPerEra;
420 type BondingDuration = BondingDuration;
421 type NominatorFastUnbondDuration = NominatorFastUnbondDuration;
422 type PlanningEraOffset = ConstU32<1>;
423 type SlashDeferDuration = ();
424 type MaxExposurePageSize = ConstU32<64>;
425 type MaxUnlockingChunks = ConstU32<32>;
426 type MaxValidatorSet = ConstU32<100>;
427 type MaxControllersInDeprecationBatch = ConstU32<100>;
428 type MaxInvulnerables = ConstU32<20>;
429 type MaxEraDuration = ();
430 type MaxPruningItems = MaxPruningItems;
431 type EventListeners = ();
432 type Filter = Nothing;
433 type WeightInfo = ();
434 }
435 }
436
437 /// The ideal number of active validators.
438 #[pallet::storage]
439 pub type ValidatorCount<T> = StorageValue<_, u32, ValueQuery>;
440
441 /// Any validators that may never be slashed or forcibly kicked. It's a Vec since they're
442 /// easy to initialize and the performance hit is minimal (we expect no more than four
443 /// invulnerables) and restricted to testnets.
444 #[pallet::storage]
445 pub type Invulnerables<T: Config> =
446 StorageValue<_, BoundedVec<T::AccountId, T::MaxInvulnerables>, ValueQuery>;
447
448 /// Map from all locked "stash" accounts to the controller account.
449 ///
450 /// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
451 #[pallet::storage]
452 pub type Bonded<T: Config> = StorageMap<_, Twox64Concat, T::AccountId, T::AccountId>;
453
454 /// The minimum active bond to become and maintain the role of a nominator.
455 #[pallet::storage]
456 pub type MinNominatorBond<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
457
458 /// The minimum active bond to become and maintain the role of a validator.
459 #[pallet::storage]
460 pub type MinValidatorBond<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
461
462 /// The minimum active nominator stake of the last successful election.
463 #[pallet::storage]
464 pub type MinimumActiveStake<T> = StorageValue<_, BalanceOf<T>, ValueQuery>;
465
466 /// The minimum amount of commission that validators can set.
467 ///
468 /// If set to `0`, no limit exists.
469 #[pallet::storage]
470 pub type MinCommission<T: Config> = StorageValue<_, Perbill, ValueQuery>;
471
472 /// Whether nominators are slashable or not.
473 ///
474 /// - When set to `true` (default), nominators are slashed along with validators and must wait
475 /// the full [`Config::BondingDuration`] before withdrawing unbonded funds.
476 /// - When set to `false`, nominators are not slashed, and can unbond in
477 /// [`Config::NominatorFastUnbondDuration`] eras instead of the full
478 /// [`Config::BondingDuration`] (see [`StakingInterface::nominator_bonding_duration`]).
479 #[pallet::storage]
480 pub type AreNominatorsSlashable<T: Config> = StorageValue<_, bool, ValueQuery, ConstBool<true>>;
481
482 /// Per-era snapshot of whether nominators are slashable.
483 ///
484 /// This is copied from [`AreNominatorsSlashable`] at the start of each era. When processing
485 /// offences, we use the value from this storage for the offence era to ensure that the
486 /// slashing rules at the time of the offence are applied, not the current rules.
487 ///
488 /// If an entry does not exist for an era, nominators are assumed to be slashable (default).
489 #[pallet::storage]
490 pub type ErasNominatorsSlashable<T: Config> =
491 StorageMap<_, Twox64Concat, EraIndex, bool, OptionQuery>;
492
493 /// Map from all (unlocked) "controller" accounts to the info regarding the staking.
494 ///
495 /// Note: All the reads and mutations to this storage *MUST* be done through the methods exposed
496 /// by [`StakingLedger`] to ensure data and lock consistency.
497 #[pallet::storage]
498 pub type Ledger<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger<T>>;
499
500 /// Where the reward payment should be made. Keyed by stash.
501 ///
502 /// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
503 #[pallet::storage]
504 pub type Payee<T: Config> =
505 StorageMap<_, Twox64Concat, T::AccountId, RewardDestination<T::AccountId>, OptionQuery>;
506
507 /// The map from (wannabe) validator stash key to the preferences of that validator.
508 ///
509 /// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
510 #[pallet::storage]
511 pub type Validators<T: Config> =
512 CountedStorageMap<_, Twox64Concat, T::AccountId, ValidatorPrefs, ValueQuery>;
513
514 /// The maximum validator count before we stop allowing new validators to join.
515 ///
516 /// When this value is not set, no limits are enforced.
517 #[pallet::storage]
518 pub type MaxValidatorsCount<T> = StorageValue<_, u32, OptionQuery>;
519
520 /// Tracks the last era in which an account was active as a validator (included in the era's
521 /// exposure/snapshot).
522 ///
523 /// This is used to enforce that accounts who were recently validators must wait the full
524 /// [`Config::BondingDuration`] before their funds can be withdrawn, even if they switch to
525 /// nominator role. This prevents validators from:
526 /// 1. Committing a slashable offence in era N
527 /// 2. Switching to nominator role
528 /// 3. Using the shorter nominator unbonding duration to withdraw funds before being slashed
529 ///
530 /// Updated when era snapshots are created (in `ErasStakersPaged`/`ErasStakersOverview`).
531 /// Cleaned up when the stash is killed (fully withdrawn/reaped).
532 #[pallet::storage]
533 pub type LastValidatorEra<T: Config> = StorageMap<_, Twox64Concat, T::AccountId, EraIndex>;
534
535 /// The map from nominator stash key to their nomination preferences, namely the validators that
536 /// they wish to support.
537 ///
538 /// Note that the keys of this storage map might become non-decodable in case the
539 /// account's [`NominationsQuota::MaxNominations`] configuration is decreased.
540 /// In this rare case, these nominators
541 /// are still existent in storage, their key is correct and retrievable (i.e. `contains_key`
542 /// indicates that they exist), but their value cannot be decoded. Therefore, the non-decodable
543 /// nominators will effectively not-exist, until they re-submit their preferences such that it
544 /// is within the bounds of the newly set `Config::MaxNominations`.
545 ///
546 /// This implies that `::iter_keys().count()` and `::iter().count()` might return different
547 /// values for this map. Moreover, the main `::count()` is aligned with the former, namely the
548 /// number of keys that exist.
549 ///
550 /// Lastly, if any of the nominators become non-decodable, they can be chilled immediately via
551 /// [`Call::chill_other`] dispatchable by anyone.
552 ///
553 /// TWOX-NOTE: SAFE since `AccountId` is a secure hash.
554 #[pallet::storage]
555 pub type Nominators<T: Config> =
556 CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations<T>>;
557
558 /// Stakers whose funds are managed by other pallets.
559 ///
560 /// This pallet does not apply any locks on them, therefore they are only virtually bonded. They
561 /// are expected to be keyless accounts and hence should not be allowed to mutate their ledger
562 /// directly via this pallet. Instead, these accounts are managed by other pallets and accessed
563 /// via low level apis. We keep track of them to do minimal integrity checks.
564 #[pallet::storage]
565 pub type VirtualStakers<T: Config> = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>;
566
567 /// The maximum nominator count before we stop allowing new validators to join.
568 ///
569 /// When this value is not set, no limits are enforced.
570 #[pallet::storage]
571 pub type MaxNominatorsCount<T> = StorageValue<_, u32, OptionQuery>;
572
573 // --- AUDIT NOTE: the following storage items should only be controlled by `Rotator`
574
575 /// The current planned era index.
576 ///
577 /// This is the latest planned era, depending on how the Session pallet queues the validator
578 /// set, it might be active or not.
579 #[pallet::storage]
580 pub type CurrentEra<T> = StorageValue<_, EraIndex>;
581
582 /// The active era information, it holds index and start.
583 ///
584 /// The active era is the era being currently rewarded. Validator set of this era must be
585 /// equal to what is RC's session pallet.
586 #[pallet::storage]
587 pub type ActiveEra<T> = StorageValue<_, ActiveEraInfo>;
588
589 /// Custom bound for [`BondedEras`] which is equal to [`Config::BondingDuration`] + 1.
590 pub struct BondedErasBound<T>(core::marker::PhantomData<T>);
591 impl<T: Config> Get<u32> for BondedErasBound<T> {
592 fn get() -> u32 {
593 T::BondingDuration::get().saturating_add(1)
594 }
595 }
596
597 /// A mapping from still-bonded eras to the first session index of that era.
598 ///
599 /// Must contains information for eras for the range:
600 /// `[active_era - bounding_duration; active_era]`
601 #[pallet::storage]
602 pub type BondedEras<T: Config> =
603 StorageValue<_, BoundedVec<(EraIndex, SessionIndex), BondedErasBound<T>>, ValueQuery>;
604
605 // --- AUDIT Note: end of storage items controlled by `Rotator`.
606
607 /// Summary of validator exposure at a given era.
608 ///
609 /// This contains the total stake in support of the validator and their own stake. In addition,
610 /// it can also be used to get the number of nominators backing this validator and the number of
611 /// exposure pages they are divided into. The page count is useful to determine the number of
612 /// pages of rewards that needs to be claimed.
613 ///
614 /// This is keyed first by the era index to allow bulk deletion and then the stash account.
615 /// Should only be accessed through `Eras`.
616 ///
617 /// Is it removed after [`Config::HistoryDepth`] eras.
618 /// If stakers hasn't been set or has been removed then empty overview is returned.
619 #[pallet::storage]
620 pub type ErasStakersOverview<T: Config> = StorageDoubleMap<
621 _,
622 Twox64Concat,
623 EraIndex,
624 Twox64Concat,
625 T::AccountId,
626 PagedExposureMetadata<BalanceOf<T>>,
627 OptionQuery,
628 >;
629
630 /// A bounded wrapper for [`sp_staking::ExposurePage`].
631 ///
632 /// It has `Deref` and `DerefMut` impls that map it back [`sp_staking::ExposurePage`] for all
633 /// purposes. This is done in such a way because we prefer to keep the types in [`sp_staking`]
634 /// pure, and not polluted by pallet-specific bounding logic.
635 ///
636 /// It encoded and decodes exactly the same as [`sp_staking::ExposurePage`], and provides a
637 /// manual `MaxEncodedLen` implementation, to be used in benchmarking
638 #[derive(PartialEqNoBound, Encode, Decode, DebugNoBound, TypeInfo, DefaultNoBound)]
639 #[scale_info(skip_type_params(T))]
640 pub struct BoundedExposurePage<T: Config>(pub ExposurePage<T::AccountId, BalanceOf<T>>);
641 impl<T: Config> Deref for BoundedExposurePage<T> {
642 type Target = ExposurePage<T::AccountId, BalanceOf<T>>;
643
644 fn deref(&self) -> &Self::Target {
645 &self.0
646 }
647 }
648
649 impl<T: Config> core::ops::DerefMut for BoundedExposurePage<T> {
650 fn deref_mut(&mut self) -> &mut Self::Target {
651 &mut self.0
652 }
653 }
654
655 impl<T: Config> codec::MaxEncodedLen for BoundedExposurePage<T> {
656 fn max_encoded_len() -> usize {
657 let max_exposure_page_size = T::MaxExposurePageSize::get() as usize;
658 let individual_size =
659 T::AccountId::max_encoded_len() + BalanceOf::<T>::max_encoded_len();
660
661 // 1 balance for `total`
662 BalanceOf::<T>::max_encoded_len() +
663 // individual_size multiplied by page size
664 max_exposure_page_size.saturating_mul(individual_size)
665 }
666 }
667
668 impl<T: Config> From<ExposurePage<T::AccountId, BalanceOf<T>>> for BoundedExposurePage<T> {
669 fn from(value: ExposurePage<T::AccountId, BalanceOf<T>>) -> Self {
670 Self(value)
671 }
672 }
673
674 impl<T: Config> From<BoundedExposurePage<T>> for ExposurePage<T::AccountId, BalanceOf<T>> {
675 fn from(value: BoundedExposurePage<T>) -> Self {
676 value.0
677 }
678 }
679
680 impl<T: Config> codec::EncodeLike<BoundedExposurePage<T>>
681 for ExposurePage<T::AccountId, BalanceOf<T>>
682 {
683 }
684
685 /// Paginated exposure of a validator at given era.
686 ///
687 /// This is keyed first by the era index to allow bulk deletion, then stash account and finally
688 /// the page. Should only be accessed through `Eras`.
689 ///
690 /// This is cleared after [`Config::HistoryDepth`] eras.
691 #[pallet::storage]
692 pub type ErasStakersPaged<T: Config> = StorageNMap<
693 _,
694 (
695 NMapKey<Twox64Concat, EraIndex>,
696 NMapKey<Twox64Concat, T::AccountId>,
697 NMapKey<Twox64Concat, Page>,
698 ),
699 BoundedExposurePage<T>,
700 OptionQuery,
701 >;
702
703 pub struct ClaimedRewardsBound<T>(core::marker::PhantomData<T>);
704 impl<T: Config> Get<u32> for ClaimedRewardsBound<T> {
705 fn get() -> u32 {
706 let max_total_nominators_per_validator =
707 <T::ElectionProvider as ElectionProvider>::MaxBackersPerWinnerFinal::get();
708 let exposure_page_size = T::MaxExposurePageSize::get();
709 max_total_nominators_per_validator
710 .saturating_div(exposure_page_size)
711 .saturating_add(1)
712 }
713 }
714
715 /// History of claimed paged rewards by era and validator.
716 ///
717 /// This is keyed by era and validator stash which maps to the set of page indexes which have
718 /// been claimed.
719 ///
720 /// It is removed after [`Config::HistoryDepth`] eras.
721 #[pallet::storage]
722 pub type ClaimedRewards<T: Config> = StorageDoubleMap<
723 _,
724 Twox64Concat,
725 EraIndex,
726 Twox64Concat,
727 T::AccountId,
728 WeakBoundedVec<Page, ClaimedRewardsBound<T>>,
729 ValueQuery,
730 >;
731
732 /// Exposure of validator at era with the preferences of validators.
733 ///
734 /// This is keyed first by the era index to allow bulk deletion and then the stash account.
735 ///
736 /// Is it removed after [`Config::HistoryDepth`] eras.
737 // If prefs hasn't been set or has been removed then 0 commission is returned.
738 #[pallet::storage]
739 pub type ErasValidatorPrefs<T: Config> = StorageDoubleMap<
740 _,
741 Twox64Concat,
742 EraIndex,
743 Twox64Concat,
744 T::AccountId,
745 ValidatorPrefs,
746 ValueQuery,
747 >;
748
749 /// The total validator era payout for the last [`Config::HistoryDepth`] eras.
750 ///
751 /// Eras that haven't finished yet or has been removed doesn't have reward.
752 #[pallet::storage]
753 pub type ErasValidatorReward<T: Config> = StorageMap<_, Twox64Concat, EraIndex, BalanceOf<T>>;
754
755 /// Rewards for the last [`Config::HistoryDepth`] eras.
756 /// If reward hasn't been set or has been removed then 0 reward is returned.
757 #[pallet::storage]
758 pub type ErasRewardPoints<T: Config> =
759 StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints<T>, ValueQuery>;
760
761 /// The total amount staked for the last [`Config::HistoryDepth`] eras.
762 /// If total hasn't been set or has been removed then 0 stake is returned.
763 #[pallet::storage]
764 pub type ErasTotalStake<T: Config> =
765 StorageMap<_, Twox64Concat, EraIndex, BalanceOf<T>, ValueQuery>;
766
767 /// Mode of era forcing.
768 #[pallet::storage]
769 pub type ForceEra<T> = StorageValue<_, Forcing, ValueQuery>;
770
771 /// Maximum staked rewards, i.e. the percentage of the era inflation that
772 /// is used for stake rewards.
773 /// See [Era payout](./index.html#era-payout).
774 #[pallet::storage]
775 pub type MaxStakedRewards<T> = StorageValue<_, Percent, OptionQuery>;
776
777 /// The percentage of the slash that is distributed to reporters.
778 ///
779 /// The rest of the slashed value is handled by the `Slash`.
780 #[pallet::storage]
781 pub type SlashRewardFraction<T> = StorageValue<_, Perbill, ValueQuery>;
782
783 /// The amount of currency given to reporters of a slash event which was
784 /// canceled by extraordinary circumstances (e.g. governance).
785 #[pallet::storage]
786 pub type CanceledSlashPayout<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;
787
788 /// Stores reported offences in a queue until they are processed in subsequent blocks.
789 ///
790 /// Each offence is recorded under the corresponding era index and the offending validator's
791 /// account. If an offence spans multiple pages, only one page is processed at a time. Offences
792 /// are handled sequentially, with their associated slashes computed and stored in
793 /// `UnappliedSlashes`. These slashes are then applied in a future era as determined by
794 /// `SlashDeferDuration`.
795 ///
796 /// Any offences tied to an era older than `BondingDuration` are automatically dropped.
797 /// Processing always prioritizes the oldest era first.
798 #[pallet::storage]
799 pub type OffenceQueue<T: Config> = StorageDoubleMap<
800 _,
801 Twox64Concat,
802 EraIndex,
803 Twox64Concat,
804 T::AccountId,
805 slashing::OffenceRecord<T::AccountId>,
806 >;
807
808 /// Tracks the eras that contain offences in `OffenceQueue`, sorted from **earliest to latest**.
809 ///
810 /// - This ensures efficient retrieval of the oldest offence without iterating through
811 /// `OffenceQueue`.
812 /// - When a new offence is added to `OffenceQueue`, its era is **inserted in sorted order**
813 /// if not already present.
814 /// - When all offences for an era are processed, it is **removed** from this list.
815 /// - The maximum length of this vector is bounded by `BondingDuration`.
816 ///
817 /// This eliminates the need for expensive iteration and sorting when fetching the next offence
818 /// to process.
819 #[pallet::storage]
820 pub type OffenceQueueEras<T: Config> = StorageValue<_, WeakBoundedVec<u32, T::BondingDuration>>;
821
822 /// Tracks the currently processed offence record from the `OffenceQueue`.
823 ///
824 /// - When processing offences, an offence record is **popped** from the oldest era in
825 /// `OffenceQueue` and stored here.
826 /// - The function `process_offence` reads from this storage, processing one page of exposure at
827 /// a time.
828 /// - After processing a page, the `exposure_page` count is **decremented** until it reaches
829 /// zero.
830 /// - Once fully processed, the offence record is removed from this storage.
831 ///
832 /// This ensures that offences are processed incrementally, preventing excessive computation
833 /// in a single block while maintaining correct slashing behavior.
834 #[pallet::storage]
835 pub type ProcessingOffence<T: Config> =
836 StorageValue<_, (EraIndex, T::AccountId, slashing::OffenceRecord<T::AccountId>)>;
837
838 /// All unapplied slashes that are queued for later.
839 #[pallet::storage]
840 pub type UnappliedSlashes<T: Config> = StorageDoubleMap<
841 _,
842 Twox64Concat,
843 EraIndex,
844 Twox64Concat,
845 // Unique key for unapplied slashes: (validator, slash fraction, page index).
846 (T::AccountId, Perbill, u32),
847 UnappliedSlash<T>,
848 OptionQuery,
849 >;
850
851 /// Cancelled slashes by era and validator with maximum slash fraction to be cancelled.
852 ///
853 /// When slashes are cancelled by governance, this stores the era and the validators
854 /// whose slashes should be cancelled, along with the maximum slash fraction that should
855 /// be cancelled for each validator.
856 #[pallet::storage]
857 pub type CancelledSlashes<T: Config> = StorageMap<
858 _,
859 Twox64Concat,
860 EraIndex,
861 BoundedVec<(T::AccountId, Perbill), T::MaxValidatorSet>,
862 ValueQuery,
863 >;
864
865 /// All slashing events on validators, mapped by era to the highest slash proportion
866 /// and slash value of the era.
867 #[pallet::storage]
868 pub type ValidatorSlashInEra<T: Config> = StorageDoubleMap<
869 _,
870 Twox64Concat,
871 EraIndex,
872 Twox64Concat,
873 T::AccountId,
874 (Perbill, BalanceOf<T>),
875 >;
876
877 /// The threshold for when users can start calling `chill_other` for other validators /
878 /// nominators. The threshold is compared to the actual number of validators / nominators
879 /// (`CountFor*`) in the system compared to the configured max (`Max*Count`).
880 #[pallet::storage]
881 pub type ChillThreshold<T: Config> = StorageValue<_, Percent, OptionQuery>;
882
883 /// Voter snapshot progress status.
884 ///
885 /// If the status is `Ongoing`, it keeps a cursor of the last voter retrieved to proceed when
886 /// creating the next snapshot page.
887 #[pallet::storage]
888 pub type VoterSnapshotStatus<T: Config> =
889 StorageValue<_, SnapshotStatus<T::AccountId>, ValueQuery>;
890
891 /// Keeps track of an ongoing multi-page election solution request.
892 ///
893 /// If `Some(_)``, it is the next page that we intend to elect. If `None`, we are not in the
894 /// election process.
895 ///
896 /// This is only set in multi-block elections. Should always be `None` otherwise.
897 #[pallet::storage]
898 pub type NextElectionPage<T: Config> = StorageValue<_, PageIndex, OptionQuery>;
899
900 /// A bounded list of the "electable" stashes that resulted from a successful election.
901 #[pallet::storage]
902 pub type ElectableStashes<T: Config> =
903 StorageValue<_, BoundedBTreeSet<T::AccountId, T::MaxValidatorSet>, ValueQuery>;
904
905 /// Tracks the current step of era pruning process for each era being lazily pruned.
906 #[pallet::storage]
907 pub type EraPruningState<T: Config> = StorageMap<_, Twox64Concat, EraIndex, PruningStep>;
908
909 #[pallet::genesis_config]
910 #[derive(frame_support::DefaultNoBound, frame_support::DebugNoBound)]
911 pub struct GenesisConfig<T: Config> {
912 pub validator_count: u32,
913 pub invulnerables: BoundedVec<T::AccountId, T::MaxInvulnerables>,
914 pub force_era: Forcing,
915 pub slash_reward_fraction: Perbill,
916 pub canceled_payout: BalanceOf<T>,
917 pub stakers: Vec<(T::AccountId, BalanceOf<T>, crate::StakerStatus<T::AccountId>)>,
918 pub min_nominator_bond: BalanceOf<T>,
919 pub min_validator_bond: BalanceOf<T>,
920 pub max_validator_count: Option<u32>,
921 pub max_nominator_count: Option<u32>,
922 /// Create the given number of validators and nominators.
923 ///
924 /// These account need not be in the endowment list of balances, and are auto-topped up
925 /// here.
926 ///
927 /// Useful for testing genesis config.
928 pub dev_stakers: Option<(u32, u32)>,
929 /// initial active era, corresponding session index and start timestamp.
930 pub active_era: (u32, u32, u64),
931 }
932
933 impl<T: Config> GenesisConfig<T> {
934 fn generate_endowed_bonded_account(derivation: &str, rng: &mut ChaChaRng) -> T::AccountId {
935 let pair: SrPair = Pair::from_string(&derivation, None)
936 .expect(&format!("Failed to parse derivation string: {derivation}"));
937 let who = T::AccountId::decode(&mut &pair.public().encode()[..])
938 .expect(&format!("Failed to decode public key from pair: {:?}", pair.public()));
939
940 let (min, max) = T::VoterList::range();
941 let stake = BalanceOf::<T>::from(rng.next_u64().min(max).max(min));
942 let two: BalanceOf<T> = 2u32.into();
943
944 assert_ok!(T::Currency::mint_into(&who, stake * two));
945 assert_ok!(<Pallet<T>>::bond(
946 T::RuntimeOrigin::from(Some(who.clone()).into()),
947 stake,
948 RewardDestination::Staked,
949 ));
950 who
951 }
952 }
953
954 #[pallet::genesis_build]
955 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
956 fn build(&self) {
957 crate::log!(trace, "initializing with {:?}", self);
958 assert!(
959 self.validator_count <=
960 <T::ElectionProvider as ElectionProvider>::MaxWinnersPerPage::get() *
961 <T::ElectionProvider as ElectionProvider>::Pages::get(),
962 "validator count is too high, `ElectionProvider` can never fulfill this"
963 );
964 ValidatorCount::<T>::put(self.validator_count);
965
966 assert!(
967 self.invulnerables.len() as u32 <= T::MaxInvulnerables::get(),
968 "Too many invulnerable validators at genesis."
969 );
970 <Invulnerables<T>>::put(&self.invulnerables);
971
972 ForceEra::<T>::put(self.force_era);
973 CanceledSlashPayout::<T>::put(self.canceled_payout);
974 SlashRewardFraction::<T>::put(self.slash_reward_fraction);
975 MinNominatorBond::<T>::put(self.min_nominator_bond);
976 MinValidatorBond::<T>::put(self.min_validator_bond);
977 if let Some(x) = self.max_validator_count {
978 MaxValidatorsCount::<T>::put(x);
979 }
980 if let Some(x) = self.max_nominator_count {
981 MaxNominatorsCount::<T>::put(x);
982 }
983
984 // First pass: set up all validators and idle stakers
985 for &(ref stash, balance, ref status) in &self.stakers {
986 match status {
987 crate::StakerStatus::Validator => {
988 crate::log!(
989 trace,
990 "inserting genesis validator: {:?} => {:?} => {:?}",
991 stash,
992 balance,
993 status
994 );
995 assert!(
996 asset::free_to_stake::<T>(stash) >= balance,
997 "Stash does not have enough balance to bond."
998 );
999 assert_ok!(<Pallet<T>>::bond(
1000 T::RuntimeOrigin::from(Some(stash.clone()).into()),
1001 balance,
1002 RewardDestination::Staked,
1003 ));
1004 assert_ok!(<Pallet<T>>::validate(
1005 T::RuntimeOrigin::from(Some(stash.clone()).into()),
1006 Default::default(),
1007 ));
1008 },
1009 crate::StakerStatus::Idle => {
1010 crate::log!(
1011 trace,
1012 "inserting genesis idle staker: {:?} => {:?} => {:?}",
1013 stash,
1014 balance,
1015 status
1016 );
1017 assert!(
1018 asset::free_to_stake::<T>(stash) >= balance,
1019 "Stash does not have enough balance to bond."
1020 );
1021 assert_ok!(<Pallet<T>>::bond(
1022 T::RuntimeOrigin::from(Some(stash.clone()).into()),
1023 balance,
1024 RewardDestination::Staked,
1025 ));
1026 },
1027 _ => {},
1028 }
1029 }
1030
1031 // Second pass: set up all nominators (now that validators exist)
1032 for &(ref stash, balance, ref status) in &self.stakers {
1033 match status {
1034 crate::StakerStatus::Nominator(votes) => {
1035 crate::log!(
1036 trace,
1037 "inserting genesis nominator: {:?} => {:?} => {:?}",
1038 stash,
1039 balance,
1040 status
1041 );
1042 assert!(
1043 asset::free_to_stake::<T>(stash) >= balance,
1044 "Stash does not have enough balance to bond."
1045 );
1046 assert_ok!(<Pallet<T>>::bond(
1047 T::RuntimeOrigin::from(Some(stash.clone()).into()),
1048 balance,
1049 RewardDestination::Staked,
1050 ));
1051 assert_ok!(<Pallet<T>>::nominate(
1052 T::RuntimeOrigin::from(Some(stash.clone()).into()),
1053 votes.iter().map(|l| T::Lookup::unlookup(l.clone())).collect(),
1054 ));
1055 },
1056 _ => {},
1057 }
1058 }
1059
1060 // all voters are reported to the `VoterList`.
1061 assert_eq!(
1062 T::VoterList::count(),
1063 Nominators::<T>::count() + Validators::<T>::count(),
1064 "not all genesis stakers were inserted into sorted list provider, something is wrong."
1065 );
1066
1067 // now generate the dev stakers, after all else is setup
1068 if let Some((validators, nominators)) = self.dev_stakers {
1069 crate::log!(
1070 debug,
1071 "generating dev stakers: validators: {}, nominators: {}",
1072 validators,
1073 nominators
1074 );
1075 let base_derivation = "//staker//{}";
1076
1077 // it is okay for the randomness to be the same on every call. If we want different,
1078 // we can make `base_derivation` configurable.
1079 let mut rng =
1080 ChaChaRng::from_seed(base_derivation.using_encoded(sp_core::blake2_256));
1081
1082 (0..validators).for_each(|index| {
1083 let derivation = base_derivation.replace("{}", &format!("validator{}", index));
1084 let who = Self::generate_endowed_bonded_account(&derivation, &mut rng);
1085 assert_ok!(<Pallet<T>>::validate(
1086 T::RuntimeOrigin::from(Some(who.clone()).into()),
1087 Default::default(),
1088 ));
1089 });
1090
1091 // This allows us to work with configs like `dev_stakers: (0, 10)`. Don't create new
1092 // validators, just add a bunch of nominators. Useful for slashing tests.
1093 let all_validators = Validators::<T>::iter_keys().collect::<Vec<_>>();
1094
1095 (0..nominators).for_each(|index| {
1096 let derivation = base_derivation.replace("{}", &format!("nominator{}", index));
1097 let who = Self::generate_endowed_bonded_account(&derivation, &mut rng);
1098
1099 let random_nominations = all_validators
1100 .choose_multiple(&mut rng, MaxNominationsOf::<T>::get() as usize)
1101 .map(|v| v.clone())
1102 .collect::<Vec<_>>();
1103
1104 assert_ok!(<Pallet<T>>::nominate(
1105 T::RuntimeOrigin::from(Some(who.clone()).into()),
1106 random_nominations.iter().map(|l| T::Lookup::unlookup(l.clone())).collect(),
1107 ));
1108 })
1109 }
1110
1111 let (active_era, session_index, timestamp) = self.active_era;
1112 ActiveEra::<T>::put(ActiveEraInfo { index: active_era, start: Some(timestamp) });
1113 // at genesis, we do not have any new planned era.
1114 CurrentEra::<T>::put(active_era);
1115 // set the bonded genesis era
1116 BondedEras::<T>::put(
1117 BoundedVec::<_, BondedErasBound<T>>::try_from(
1118 alloc::vec![(active_era, session_index)]
1119 )
1120 .expect("bound for BondedEras is BondingDuration + 1; can contain at least one element; qed")
1121 );
1122 }
1123 }
1124
1125 #[pallet::event]
1126 #[pallet::generate_deposit(pub fn deposit_event)]
1127 pub enum Event<T: Config> {
1128 /// The era payout has been set; the first balance is the validator-payout; the second is
1129 /// the remainder from the maximum amount of reward.
1130 EraPaid {
1131 era_index: EraIndex,
1132 validator_payout: BalanceOf<T>,
1133 remainder: BalanceOf<T>,
1134 },
1135 /// The nominator has been rewarded by this amount to this destination.
1136 Rewarded {
1137 stash: T::AccountId,
1138 dest: RewardDestination<T::AccountId>,
1139 amount: BalanceOf<T>,
1140 },
1141 /// A staker (validator or nominator) has been slashed by the given amount.
1142 Slashed {
1143 staker: T::AccountId,
1144 amount: BalanceOf<T>,
1145 },
1146 /// An old slashing report from a prior era was discarded because it could
1147 /// not be processed.
1148 OldSlashingReportDiscarded {
1149 session_index: SessionIndex,
1150 },
1151 /// An account has bonded this amount. \[stash, amount\]
1152 ///
1153 /// NOTE: This event is only emitted when funds are bonded via a dispatchable. Notably,
1154 /// it will not be emitted for staking rewards when they are added to stake.
1155 Bonded {
1156 stash: T::AccountId,
1157 amount: BalanceOf<T>,
1158 },
1159 /// An account has unbonded this amount.
1160 Unbonded {
1161 stash: T::AccountId,
1162 amount: BalanceOf<T>,
1163 },
1164 /// An account has called `withdraw_unbonded` and removed unbonding chunks worth `Balance`
1165 /// from the unlocking queue.
1166 Withdrawn {
1167 stash: T::AccountId,
1168 amount: BalanceOf<T>,
1169 },
1170 /// A subsequent event of `Withdrawn`, indicating that `stash` was fully removed from the
1171 /// system.
1172 StakerRemoved {
1173 stash: T::AccountId,
1174 },
1175 /// A nominator has been kicked from a validator.
1176 Kicked {
1177 nominator: T::AccountId,
1178 stash: T::AccountId,
1179 },
1180 /// An account has stopped participating as either a validator or nominator.
1181 Chilled {
1182 stash: T::AccountId,
1183 },
1184 /// A Page of stakers rewards are getting paid. `next` is `None` if all pages are claimed.
1185 PayoutStarted {
1186 era_index: EraIndex,
1187 validator_stash: T::AccountId,
1188 page: Page,
1189 next: Option<Page>,
1190 },
1191 /// A validator has set their preferences.
1192 ValidatorPrefsSet {
1193 stash: T::AccountId,
1194 prefs: ValidatorPrefs,
1195 },
1196 /// Voters size limit reached.
1197 SnapshotVotersSizeExceeded {
1198 size: u32,
1199 },
1200 /// Targets size limit reached.
1201 SnapshotTargetsSizeExceeded {
1202 size: u32,
1203 },
1204 ForceEra {
1205 mode: Forcing,
1206 },
1207 /// Report of a controller batch deprecation.
1208 ControllerBatchDeprecated {
1209 failures: u32,
1210 },
1211 /// Staking balance migrated from locks to holds, with any balance that could not be held
1212 /// is force withdrawn.
1213 CurrencyMigrated {
1214 stash: T::AccountId,
1215 force_withdraw: BalanceOf<T>,
1216 },
1217 /// A page from a multi-page election was fetched. A number of these are followed by
1218 /// `StakersElected`.
1219 ///
1220 /// `Ok(count)` indicates the give number of stashes were added.
1221 /// `Err(index)` indicates that the stashes after index were dropped.
1222 /// `Err(0)` indicates that an error happened but no stashes were dropped nor added.
1223 ///
1224 /// The error indicates that a number of validators were dropped due to excess size, but
1225 /// the overall election will continue.
1226 PagedElectionProceeded {
1227 page: PageIndex,
1228 result: Result<u32, u32>,
1229 },
1230 /// An offence for the given validator, for the given percentage of their stake, at the
1231 /// given era as been reported.
1232 OffenceReported {
1233 offence_era: EraIndex,
1234 validator: T::AccountId,
1235 fraction: Perbill,
1236 },
1237 /// An offence has been processed and the corresponding slash has been computed.
1238 SlashComputed {
1239 offence_era: EraIndex,
1240 slash_era: EraIndex,
1241 offender: T::AccountId,
1242 page: u32,
1243 },
1244 /// An unapplied slash has been cancelled.
1245 SlashCancelled {
1246 slash_era: EraIndex,
1247 validator: T::AccountId,
1248 },
1249 /// Session change has been triggered.
1250 ///
1251 /// If planned_era is one era ahead of active_era, it implies new era is being planned and
1252 /// election is ongoing.
1253 SessionRotated {
1254 starting_session: SessionIndex,
1255 active_era: EraIndex,
1256 planned_era: EraIndex,
1257 },
1258 /// Something occurred that should never happen under normal operation.
1259 /// Logged as an event for fail-safe observability.
1260 Unexpected(UnexpectedKind),
1261 /// An offence was reported that was too old to be processed, and thus was dropped.
1262 OffenceTooOld {
1263 offence_era: EraIndex,
1264 validator: T::AccountId,
1265 fraction: Perbill,
1266 },
1267 /// An old era with the given index was pruned.
1268 EraPruned {
1269 index: EraIndex,
1270 },
1271 }
1272
1273 /// Represents unexpected or invariant-breaking conditions encountered during execution.
1274 ///
1275 /// These variants are emitted as [`Event::Unexpected`] and indicate a defensive check has
1276 /// failed. While these should never occur under normal operation, they are useful for
1277 /// diagnosing issues in production or test environments.
1278 #[derive(Clone, Encode, Decode, DecodeWithMemTracking, PartialEq, TypeInfo, RuntimeDebug)]
1279 pub enum UnexpectedKind {
1280 /// Emitted when calculated era duration exceeds the configured maximum.
1281 EraDurationBoundExceeded,
1282 /// Received a validator activation event that is not recognized.
1283 UnknownValidatorActivation,
1284 }
1285
1286 #[pallet::error]
1287 #[derive(PartialEq)]
1288 pub enum Error<T> {
1289 /// Not a controller account.
1290 NotController,
1291 /// Not a stash account.
1292 NotStash,
1293 /// Stash is already bonded.
1294 AlreadyBonded,
1295 /// Controller is already paired.
1296 AlreadyPaired,
1297 /// Targets cannot be empty.
1298 EmptyTargets,
1299 /// Duplicate index.
1300 DuplicateIndex,
1301 /// Slash record not found.
1302 InvalidSlashRecord,
1303 /// Cannot bond, nominate or validate with value less than the minimum defined by
1304 /// governance (see `MinValidatorBond` and `MinNominatorBond`). If unbonding is the
1305 /// intention, `chill` first to remove one's role as validator/nominator.
1306 InsufficientBond,
1307 /// Can not schedule more unlock chunks.
1308 NoMoreChunks,
1309 /// Can not rebond without unlocking chunks.
1310 NoUnlockChunk,
1311 /// Attempting to target a stash that still has funds.
1312 FundedTarget,
1313 /// Invalid era to reward.
1314 InvalidEraToReward,
1315 /// Invalid number of nominations.
1316 InvalidNumberOfNominations,
1317 /// Rewards for this era have already been claimed for this validator.
1318 AlreadyClaimed,
1319 /// No nominators exist on this page.
1320 InvalidPage,
1321 /// Incorrect previous history depth input provided.
1322 IncorrectHistoryDepth,
1323 /// Internal state has become somehow corrupted and the operation cannot continue.
1324 BadState,
1325 /// Too many nomination targets supplied.
1326 TooManyTargets,
1327 /// A nomination target was supplied that was blocked or otherwise not a validator.
1328 BadTarget,
1329 /// The user has enough bond and thus cannot be chilled forcefully by an external person.
1330 CannotChillOther,
1331 /// There are too many nominators in the system. Governance needs to adjust the staking
1332 /// settings to keep things safe for the runtime.
1333 TooManyNominators,
1334 /// There are too many validator candidates in the system. Governance needs to adjust the
1335 /// staking settings to keep things safe for the runtime.
1336 TooManyValidators,
1337 /// Commission is too low. Must be at least `MinCommission`.
1338 CommissionTooLow,
1339 /// Some bound is not met.
1340 BoundNotMet,
1341 /// Used when attempting to use deprecated controller account logic.
1342 ControllerDeprecated,
1343 /// Cannot reset a ledger.
1344 CannotRestoreLedger,
1345 /// Provided reward destination is not allowed.
1346 RewardDestinationRestricted,
1347 /// Not enough funds available to withdraw.
1348 NotEnoughFunds,
1349 /// Operation not allowed for virtual stakers.
1350 VirtualStakerNotAllowed,
1351 /// Stash could not be reaped as other pallet might depend on it.
1352 CannotReapStash,
1353 /// The stake of this account is already migrated to `Fungible` holds.
1354 AlreadyMigrated,
1355 /// Era not yet started.
1356 EraNotStarted,
1357 /// Account is restricted from participation in staking. This may happen if the account is
1358 /// staking in another way already, such as via pool.
1359 Restricted,
1360 /// Unapplied slashes in the recently concluded era is blocking this operation.
1361 /// See `Call::apply_slash` to apply them.
1362 UnappliedSlashesInPreviousEra,
1363 /// The era is not eligible for pruning.
1364 EraNotPrunable,
1365 /// The slash has been cancelled and cannot be applied.
1366 CancelledSlash,
1367 }
1368
1369 impl<T: Config> Pallet<T> {
1370 /// Apply previously-unapplied slashes on the beginning of a new era, after a delay.
1371 pub fn apply_unapplied_slashes(active_era: EraIndex) -> Weight {
1372 let mut slashes = UnappliedSlashes::<T>::iter_prefix(&active_era).take(1);
1373 if let Some((key, slash)) = slashes.next() {
1374 crate::log!(
1375 debug,
1376 "🦹 found slash {:?} scheduled to be executed in era {:?}",
1377 slash,
1378 active_era,
1379 );
1380
1381 let nominators_slashed = slash.others.len() as u32;
1382
1383 // Check if this slash has been cancelled
1384 if Self::check_slash_cancelled(active_era, &key.0, key.1) {
1385 crate::log!(
1386 debug,
1387 "🦹 slash for {:?} in era {:?} was cancelled, skipping",
1388 key.0,
1389 active_era,
1390 );
1391 } else {
1392 let offence_era = active_era.saturating_sub(T::SlashDeferDuration::get());
1393 slashing::apply_slash::<T>(slash, offence_era);
1394 }
1395
1396 // Always remove the slash from UnappliedSlashes
1397 UnappliedSlashes::<T>::remove(&active_era, &key);
1398
1399 // Check if there are more slashes for this era
1400 if UnappliedSlashes::<T>::iter_prefix(&active_era).next().is_none() {
1401 // No more slashes for this era, clear CancelledSlashes
1402 CancelledSlashes::<T>::remove(&active_era);
1403 }
1404
1405 T::WeightInfo::apply_slash(nominators_slashed)
1406 } else {
1407 // No slashes found for this era
1408 T::DbWeight::get().reads(1)
1409 }
1410 }
1411
1412 /// Execute one step of era pruning and get actual weight used
1413 fn do_prune_era_step(era: EraIndex) -> Result<Weight, DispatchError> {
1414 // Get current pruning state. If EraPruningState doesn't exist, it means:
1415 // - Era was never marked for pruning, OR
1416 // - Era was already fully pruned (pruning state was removed on final step)
1417 // In either case, this is an error - user should not call prune on non-prunable eras
1418 let current_step = EraPruningState::<T>::get(era).ok_or(Error::<T>::EraNotPrunable)?;
1419
1420 // Limit items to prevent deleting more than we can safely account for in weight
1421 // calculations
1422 let items_limit = T::MaxPruningItems::get().min(T::MaxValidatorSet::get());
1423
1424 let actual_weight = match current_step {
1425 PruningStep::ErasStakersPaged => {
1426 let result = ErasStakersPaged::<T>::clear_prefix((era,), items_limit, None);
1427 let items_deleted = result.backend as u32;
1428 result.maybe_cursor.is_none().then(|| {
1429 EraPruningState::<T>::insert(era, PruningStep::ErasStakersOverview)
1430 });
1431 T::WeightInfo::prune_era_stakers_paged(items_deleted)
1432 },
1433 PruningStep::ErasStakersOverview => {
1434 let result = ErasStakersOverview::<T>::clear_prefix(era, items_limit, None);
1435 let items_deleted = result.backend as u32;
1436 result.maybe_cursor.is_none().then(|| {
1437 EraPruningState::<T>::insert(era, PruningStep::ErasValidatorPrefs)
1438 });
1439 T::WeightInfo::prune_era_stakers_overview(items_deleted)
1440 },
1441 PruningStep::ErasValidatorPrefs => {
1442 let result = ErasValidatorPrefs::<T>::clear_prefix(era, items_limit, None);
1443 let items_deleted = result.backend as u32;
1444 result
1445 .maybe_cursor
1446 .is_none()
1447 .then(|| EraPruningState::<T>::insert(era, PruningStep::ClaimedRewards));
1448 T::WeightInfo::prune_era_validator_prefs(items_deleted)
1449 },
1450 PruningStep::ClaimedRewards => {
1451 let result = ClaimedRewards::<T>::clear_prefix(era, items_limit, None);
1452 let items_deleted = result.backend as u32;
1453 result.maybe_cursor.is_none().then(|| {
1454 EraPruningState::<T>::insert(era, PruningStep::ErasValidatorReward)
1455 });
1456 T::WeightInfo::prune_era_claimed_rewards(items_deleted)
1457 },
1458 PruningStep::ErasValidatorReward => {
1459 ErasValidatorReward::<T>::remove(era);
1460 EraPruningState::<T>::insert(era, PruningStep::ErasRewardPoints);
1461 T::WeightInfo::prune_era_validator_reward()
1462 },
1463 PruningStep::ErasRewardPoints => {
1464 ErasRewardPoints::<T>::remove(era);
1465 EraPruningState::<T>::insert(era, PruningStep::SingleEntryCleanups);
1466 T::WeightInfo::prune_era_reward_points()
1467 },
1468 PruningStep::SingleEntryCleanups => {
1469 ErasTotalStake::<T>::remove(era);
1470 // Also clean up ErasNominatorsSlashable
1471 ErasNominatorsSlashable::<T>::remove(era);
1472 EraPruningState::<T>::insert(era, PruningStep::ValidatorSlashInEra);
1473 T::WeightInfo::prune_era_single_entry_cleanups()
1474 },
1475 PruningStep::ValidatorSlashInEra => {
1476 // Clear ValidatorSlashInEra entries for this era
1477 let result = ValidatorSlashInEra::<T>::clear_prefix(era, items_limit, None);
1478 let items_deleted = result.backend as u32;
1479
1480 // This is the final step - remove the pruning state when done
1481 if result.maybe_cursor.is_none() {
1482 EraPruningState::<T>::remove(era);
1483 }
1484
1485 T::WeightInfo::prune_era_validator_slash_in_era(items_deleted)
1486 },
1487 };
1488
1489 // Check if era is fully pruned (pruning state removed) and emit event
1490 if EraPruningState::<T>::get(era).is_none() {
1491 Self::deposit_event(Event::<T>::EraPruned { index: era });
1492 }
1493
1494 Ok(actual_weight)
1495 }
1496 }
1497
1498 #[pallet::hooks]
1499 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
1500 fn on_initialize(_now: BlockNumberFor<T>) -> Weight {
1501 // Process our queue, using the era-specific nominators slashable setting.
1502 let mut consumed_weight = slashing::process_offence_for_era::<T>();
1503
1504 // apply any pending slashes after `SlashDeferDuration`.
1505 consumed_weight.saturating_accrue(T::DbWeight::get().reads(1));
1506 if let Some(active_era) = ActiveEra::<T>::get() {
1507 let slash_weight = Self::apply_unapplied_slashes(active_era.index);
1508 consumed_weight.saturating_accrue(slash_weight);
1509 }
1510
1511 // maybe plan eras and stuff. Note that this is benchmark as a part of the
1512 // election-provider's benchmarks.
1513 session_rotation::EraElectionPlanner::<T>::maybe_fetch_election_results();
1514 consumed_weight
1515 }
1516
1517 fn integrity_test() {
1518 // ensure that we funnel the correct value to the `DataProvider::MaxVotesPerVoter`;
1519 assert_eq!(
1520 MaxNominationsOf::<T>::get(),
1521 <Self as ElectionDataProvider>::MaxVotesPerVoter::get()
1522 );
1523
1524 // and that MaxNominations is always greater than 1, since we count on this.
1525 assert!(!MaxNominationsOf::<T>::get().is_zero());
1526
1527 assert!(
1528 T::SlashDeferDuration::get() < T::BondingDuration::get() || T::BondingDuration::get() == 0,
1529 "As per documentation, slash defer duration ({}) should be less than bonding duration ({}).",
1530 T::SlashDeferDuration::get(),
1531 T::BondingDuration::get(),
1532 );
1533
1534 // Ensure NominatorFastUnbondDuration is not greater than BondingDuration
1535 assert!(
1536 T::NominatorFastUnbondDuration::get() <= T::BondingDuration::get(),
1537 "NominatorFastUnbondDuration ({}) must not exceed BondingDuration ({}).",
1538 T::NominatorFastUnbondDuration::get(),
1539 T::BondingDuration::get(),
1540 );
1541 // Ensure MaxPruningItems is reasonable (minimum 100 for efficiency)
1542 assert!(
1543 T::MaxPruningItems::get() >= 100,
1544 "MaxPruningItems must be at least 100 for efficient pruning, got: {}",
1545 T::MaxPruningItems::get()
1546 );
1547 }
1548
1549 #[cfg(feature = "try-runtime")]
1550 fn try_state(n: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
1551 Self::do_try_state(n)
1552 }
1553 }
1554
1555 #[pallet::call]
1556 impl<T: Config> Pallet<T> {
1557 /// Take the origin account as a stash and lock up `value` of its balance. `controller` will
1558 /// be the account that controls it.
1559 ///
1560 /// `value` must be more than the `minimum_balance` specified by `T::Currency`.
1561 ///
1562 /// The dispatch origin for this call must be _Signed_ by the stash account.
1563 ///
1564 /// Emits `Bonded`.
1565 ///
1566 /// NOTE: Two of the storage writes (`Self::bonded`, `Self::payee`) are _never_ cleaned
1567 /// unless the `origin` falls below _existential deposit_ (or equal to 0) and gets removed
1568 /// as dust.
1569 #[pallet::call_index(0)]
1570 #[pallet::weight(T::WeightInfo::bond())]
1571 pub fn bond(
1572 origin: OriginFor<T>,
1573 #[pallet::compact] value: BalanceOf<T>,
1574 payee: RewardDestination<T::AccountId>,
1575 ) -> DispatchResult {
1576 let stash = ensure_signed(origin)?;
1577
1578 ensure!(!T::Filter::contains(&stash), Error::<T>::Restricted);
1579
1580 if StakingLedger::<T>::is_bonded(StakingAccount::Stash(stash.clone())) {
1581 return Err(Error::<T>::AlreadyBonded.into());
1582 }
1583
1584 // An existing controller cannot become a stash.
1585 if StakingLedger::<T>::is_bonded(StakingAccount::Controller(stash.clone())) {
1586 return Err(Error::<T>::AlreadyPaired.into());
1587 }
1588
1589 // Reject a bond which is lower than the minimum bond.
1590 if value < Self::min_chilled_bond() {
1591 return Err(Error::<T>::InsufficientBond.into());
1592 }
1593
1594 let stash_balance = asset::free_to_stake::<T>(&stash);
1595 let value = value.min(stash_balance);
1596 Self::deposit_event(Event::<T>::Bonded { stash: stash.clone(), amount: value });
1597 let ledger = StakingLedger::<T>::new(stash.clone(), value);
1598
1599 // You're auto-bonded forever, here. We might improve this by only bonding when
1600 // you actually validate/nominate and remove once you unbond __everything__.
1601 ledger.bond(payee)?;
1602
1603 Ok(())
1604 }
1605
1606 /// Add some extra amount that have appeared in the stash `free_balance` into the balance up
1607 /// for staking.
1608 ///
1609 /// The dispatch origin for this call must be _Signed_ by the stash, not the controller.
1610 ///
1611 /// Use this if there are additional funds in your stash account that you wish to bond.
1612 /// Unlike [`bond`](Self::bond) or [`unbond`](Self::unbond) this function does not impose
1613 /// any limitation on the amount that can be added.
1614 ///
1615 /// Emits `Bonded`.
1616 #[pallet::call_index(1)]
1617 #[pallet::weight(T::WeightInfo::bond_extra())]
1618 pub fn bond_extra(
1619 origin: OriginFor<T>,
1620 #[pallet::compact] max_additional: BalanceOf<T>,
1621 ) -> DispatchResult {
1622 let stash = ensure_signed(origin)?;
1623 ensure!(!T::Filter::contains(&stash), Error::<T>::Restricted);
1624 Self::do_bond_extra(&stash, max_additional)
1625 }
1626
1627 /// Schedule a portion of the stash to be unlocked ready for transfer out after the bond
1628 /// period ends. If this leaves an amount actively bonded less than
1629 /// [`asset::existential_deposit`], then it is increased to the full amount.
1630 ///
1631 /// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1632 ///
1633 /// Once the unlock period is done, you can call `withdraw_unbonded` to actually move
1634 /// the funds out of management ready for transfer.
1635 ///
1636 /// No more than a limited number of unlocking chunks (see `MaxUnlockingChunks`)
1637 /// can co-exists at the same time. If there are no unlocking chunks slots available
1638 /// [`Call::withdraw_unbonded`] is called to remove some of the chunks (if possible).
1639 ///
1640 /// If a user encounters the `InsufficientBond` error when calling this extrinsic,
1641 /// they should call `chill` first in order to free up their bonded funds.
1642 ///
1643 /// Emits `Unbonded`.
1644 ///
1645 /// See also [`Call::withdraw_unbonded`].
1646 #[pallet::call_index(2)]
1647 #[pallet::weight(
1648 T::WeightInfo::withdraw_unbonded_kill().saturating_add(T::WeightInfo::unbond()))
1649 ]
1650 pub fn unbond(
1651 origin: OriginFor<T>,
1652 #[pallet::compact] value: BalanceOf<T>,
1653 ) -> DispatchResultWithPostInfo {
1654 let controller = ensure_signed(origin)?;
1655 let unlocking =
1656 Self::ledger(Controller(controller.clone())).map(|l| l.unlocking.len())?;
1657
1658 // if there are no unlocking chunks available, try to remove any chunks by withdrawing
1659 // funds that have fully unbonded.
1660 let maybe_withdraw_weight = {
1661 if unlocking == T::MaxUnlockingChunks::get() as usize {
1662 Some(Self::do_withdraw_unbonded(&controller)?)
1663 } else {
1664 None
1665 }
1666 };
1667
1668 // we need to fetch the ledger again because it may have been mutated in the call
1669 // to `Self::do_withdraw_unbonded` above.
1670 let mut ledger = Self::ledger(Controller(controller))?;
1671 let mut value = value.min(ledger.active);
1672 let stash = ledger.stash.clone();
1673
1674 // If unbonding all active stake, chill the stash first to avoid `InsufficientBond`
1675 // errors. This matches the behavior of pallet-staking.
1676 let chill_weight = if value >= ledger.active {
1677 Self::chill_stash(&stash);
1678 T::WeightInfo::chill()
1679 } else {
1680 Weight::zero()
1681 };
1682
1683 ensure!(
1684 ledger.unlocking.len() < T::MaxUnlockingChunks::get() as usize,
1685 Error::<T>::NoMoreChunks,
1686 );
1687
1688 if !value.is_zero() {
1689 ledger.active -= value;
1690
1691 // Avoid there being a dust balance left in the staking system.
1692 if ledger.active < asset::existential_deposit::<T>() {
1693 value += ledger.active;
1694 ledger.active = Zero::zero();
1695 }
1696
1697 let is_nominator = Nominators::<T>::contains_key(&stash);
1698
1699 let min_active_bond = if is_nominator {
1700 Self::min_nominator_bond()
1701 } else if Validators::<T>::contains_key(&stash) {
1702 Self::min_validator_bond()
1703 } else {
1704 // staker is chilled, no min bond.
1705 Zero::zero()
1706 };
1707
1708 // Make sure that the user maintains enough active bond for their role.
1709 // If a user runs into this error, they should chill first.
1710 ensure!(ledger.active >= min_active_bond, Error::<T>::InsufficientBond);
1711
1712 // Determine unbonding duration based on validator history.
1713 // If the account was a validator in recent eras (within BondingDuration), they must
1714 // wait the full BondingDuration even if they've switched to nominator role.
1715 // This prevents validators from avoiding slashing by switching roles and using the
1716 // shorter nominator unbonding period.
1717 let active_era = session_rotation::Rotator::<T>::active_era();
1718 let was_recent_validator = LastValidatorEra::<T>::get(&stash)
1719 .map(|last_era| active_era.saturating_sub(last_era) < T::BondingDuration::get())
1720 .unwrap_or(false);
1721
1722 let unbond_duration = if was_recent_validator {
1723 // Use full bonding duration for recent validators
1724 T::BondingDuration::get()
1725 } else {
1726 // Use nominator bonding duration for pure nominators
1727 <Self as sp_staking::StakingInterface>::nominator_bonding_duration()
1728 };
1729
1730 let era =
1731 session_rotation::Rotator::<T>::active_era().saturating_add(unbond_duration);
1732 if let Some(chunk) = ledger.unlocking.last_mut().filter(|chunk| chunk.era == era) {
1733 // To keep the chunk count down, we only keep one chunk per era. Since
1734 // `unlocking` is a FiFo queue, if a chunk exists for `era` we know that it will
1735 // be the last one.
1736 chunk.value = chunk.value.defensive_saturating_add(value)
1737 } else {
1738 ledger
1739 .unlocking
1740 .try_push(UnlockChunk { value, era })
1741 .map_err(|_| Error::<T>::NoMoreChunks)?;
1742 };
1743 // NOTE: ledger must be updated prior to calling `Self::weight_of`.
1744 ledger.update()?;
1745
1746 // update this staker in the sorted list, if they exist in it.
1747 if T::VoterList::contains(&stash) {
1748 let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash));
1749 }
1750
1751 Self::deposit_event(Event::<T>::Unbonded { stash, amount: value });
1752 }
1753
1754 let actual_weight = if let Some(withdraw_weight) = maybe_withdraw_weight {
1755 Some(
1756 T::WeightInfo::unbond()
1757 .saturating_add(withdraw_weight)
1758 .saturating_add(chill_weight),
1759 )
1760 } else {
1761 Some(T::WeightInfo::unbond().saturating_add(chill_weight))
1762 };
1763
1764 Ok(actual_weight.into())
1765 }
1766
1767 /// Remove any stake that has been fully unbonded and is ready for withdrawal.
1768 ///
1769 /// Stake is considered fully unbonded once [`Config::BondingDuration`] has elapsed since
1770 /// the unbonding was initiated. In rare cases—such as when offences for the unbonded era
1771 /// have been reported but not yet processed—withdrawal is restricted to eras for which
1772 /// all offences have been processed.
1773 ///
1774 /// The unlocked stake will be returned as free balance in the stash account.
1775 ///
1776 /// The dispatch origin for this call must be _Signed_ by the controller.
1777 ///
1778 /// Emits `Withdrawn`.
1779 ///
1780 /// See also [`Call::unbond`].
1781 ///
1782 /// ## Parameters
1783 ///
1784 /// - `num_slashing_spans`: **Deprecated**. Retained only for backward compatibility; this
1785 /// parameter has no effect.
1786 #[pallet::call_index(3)]
1787 #[pallet::weight(T::WeightInfo::withdraw_unbonded_kill())]
1788 pub fn withdraw_unbonded(
1789 origin: OriginFor<T>,
1790 _num_slashing_spans: u32,
1791 ) -> DispatchResultWithPostInfo {
1792 let controller = ensure_signed(origin)?;
1793
1794 let actual_weight = Self::do_withdraw_unbonded(&controller)?;
1795 Ok(Some(actual_weight).into())
1796 }
1797
1798 /// Declare the desire to validate for the origin controller.
1799 ///
1800 /// Effects will be felt at the beginning of the next era.
1801 ///
1802 /// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1803 #[pallet::call_index(4)]
1804 #[pallet::weight(T::WeightInfo::validate())]
1805 pub fn validate(origin: OriginFor<T>, prefs: ValidatorPrefs) -> DispatchResult {
1806 let controller = ensure_signed(origin)?;
1807
1808 let ledger = Self::ledger(Controller(controller))?;
1809
1810 ensure!(ledger.active >= Self::min_validator_bond(), Error::<T>::InsufficientBond);
1811 let stash = &ledger.stash;
1812
1813 // ensure their commission is correct.
1814 ensure!(prefs.commission >= MinCommission::<T>::get(), Error::<T>::CommissionTooLow);
1815
1816 // Only check limits if they are not already a validator.
1817 if !Validators::<T>::contains_key(stash) {
1818 // If this error is reached, we need to adjust the `MinValidatorBond` and start
1819 // calling `chill_other`. Until then, we explicitly block new validators to protect
1820 // the runtime.
1821 if let Some(max_validators) = MaxValidatorsCount::<T>::get() {
1822 ensure!(
1823 Validators::<T>::count() < max_validators,
1824 Error::<T>::TooManyValidators
1825 );
1826 }
1827 }
1828
1829 Self::do_remove_nominator(stash);
1830 Self::do_add_validator(stash, prefs.clone());
1831 Self::deposit_event(Event::<T>::ValidatorPrefsSet { stash: ledger.stash, prefs });
1832
1833 Ok(())
1834 }
1835
1836 /// Declare the desire to nominate `targets` for the origin controller.
1837 ///
1838 /// Effects will be felt at the beginning of the next era.
1839 ///
1840 /// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1841 #[pallet::call_index(5)]
1842 #[pallet::weight(T::WeightInfo::nominate(targets.len() as u32))]
1843 pub fn nominate(
1844 origin: OriginFor<T>,
1845 targets: Vec<AccountIdLookupOf<T>>,
1846 ) -> DispatchResult {
1847 let controller = ensure_signed(origin)?;
1848
1849 let ledger = Self::ledger(StakingAccount::Controller(controller.clone()))?;
1850
1851 ensure!(ledger.active >= Self::min_nominator_bond(), Error::<T>::InsufficientBond);
1852 let stash = &ledger.stash;
1853
1854 // Only check limits if they are not already a nominator.
1855 if !Nominators::<T>::contains_key(stash) {
1856 // If this error is reached, we need to adjust the `MinNominatorBond` and start
1857 // calling `chill_other`. Until then, we explicitly block new nominators to protect
1858 // the runtime.
1859 if let Some(max_nominators) = MaxNominatorsCount::<T>::get() {
1860 ensure!(
1861 Nominators::<T>::count() < max_nominators,
1862 Error::<T>::TooManyNominators
1863 );
1864 }
1865 }
1866
1867 // dedup targets
1868 let mut targets = targets
1869 .into_iter()
1870 .map(|t| T::Lookup::lookup(t).map_err(DispatchError::from))
1871 .collect::<Result<Vec<_>, _>>()?;
1872 targets.sort();
1873 targets.dedup();
1874
1875 ensure!(!targets.is_empty(), Error::<T>::EmptyTargets);
1876 ensure!(
1877 targets.len() <= T::NominationsQuota::get_quota(ledger.active) as usize,
1878 Error::<T>::TooManyTargets
1879 );
1880
1881 let old = Nominators::<T>::get(stash).map_or_else(Vec::new, |x| x.targets.into_inner());
1882
1883 let targets: BoundedVec<_, _> = targets
1884 .into_iter()
1885 .map(|n| {
1886 if old.contains(&n) ||
1887 (Validators::<T>::contains_key(&n) && !Validators::<T>::get(&n).blocked)
1888 {
1889 Ok(n)
1890 } else {
1891 Err(Error::<T>::BadTarget.into())
1892 }
1893 })
1894 .collect::<Result<Vec<_>, DispatchError>>()?
1895 .try_into()
1896 .map_err(|_| Error::<T>::TooManyNominators)?;
1897
1898 let nominations = Nominations {
1899 targets,
1900 // Initial nominations are considered submitted at era 0. See `Nominations` doc.
1901 submitted_in: CurrentEra::<T>::get().unwrap_or(0),
1902 suppressed: false,
1903 };
1904
1905 Self::do_remove_validator(stash);
1906 Self::do_add_nominator(stash, nominations);
1907 Ok(())
1908 }
1909
1910 /// Declare no desire to either validate or nominate.
1911 ///
1912 /// Effects will be felt at the beginning of the next era.
1913 ///
1914 /// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1915 ///
1916 /// ## Complexity
1917 /// - Independent of the arguments. Insignificant complexity.
1918 /// - Contains one read.
1919 /// - Writes are limited to the `origin` account key.
1920 #[pallet::call_index(6)]
1921 #[pallet::weight(T::WeightInfo::chill())]
1922 pub fn chill(origin: OriginFor<T>) -> DispatchResult {
1923 let controller = ensure_signed(origin)?;
1924
1925 let ledger = Self::ledger(StakingAccount::Controller(controller))?;
1926
1927 Self::chill_stash(&ledger.stash);
1928 Ok(())
1929 }
1930
1931 /// (Re-)set the payment target for a controller.
1932 ///
1933 /// Effects will be felt instantly (as soon as this function is completed successfully).
1934 ///
1935 /// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
1936 #[pallet::call_index(7)]
1937 #[pallet::weight(T::WeightInfo::set_payee())]
1938 pub fn set_payee(
1939 origin: OriginFor<T>,
1940 payee: RewardDestination<T::AccountId>,
1941 ) -> DispatchResult {
1942 let controller = ensure_signed(origin)?;
1943 let ledger = Self::ledger(Controller(controller.clone()))?;
1944
1945 ensure!(
1946 (payee != {
1947 #[allow(deprecated)]
1948 RewardDestination::Controller
1949 }),
1950 Error::<T>::ControllerDeprecated
1951 );
1952
1953 let _ = ledger
1954 .set_payee(payee)
1955 .defensive_proof("ledger was retrieved from storage, thus it's bonded; qed.")?;
1956
1957 Ok(())
1958 }
1959
1960 /// (Re-)sets the controller of a stash to the stash itself. This function previously
1961 /// accepted a `controller` argument to set the controller to an account other than the
1962 /// stash itself. This functionality has now been removed, now only setting the controller
1963 /// to the stash, if it is not already.
1964 ///
1965 /// Effects will be felt instantly (as soon as this function is completed successfully).
1966 ///
1967 /// The dispatch origin for this call must be _Signed_ by the stash, not the controller.
1968 #[pallet::call_index(8)]
1969 #[pallet::weight(T::WeightInfo::set_controller())]
1970 pub fn set_controller(origin: OriginFor<T>) -> DispatchResult {
1971 let stash = ensure_signed(origin)?;
1972
1973 Self::ledger(StakingAccount::Stash(stash.clone())).map(|ledger| {
1974 let controller = ledger.controller()
1975 .defensive_proof("Ledger's controller field didn't exist. The controller should have been fetched using StakingLedger.")
1976 .ok_or(Error::<T>::NotController)?;
1977
1978 if controller == stash {
1979 // Stash is already its own controller.
1980 return Err(Error::<T>::AlreadyPaired.into())
1981 }
1982
1983 let _ = ledger.set_controller_to_stash()?;
1984 Ok(())
1985 })?
1986 }
1987
1988 /// Sets the ideal number of validators.
1989 ///
1990 /// The dispatch origin must be Root.
1991 #[pallet::call_index(9)]
1992 #[pallet::weight(T::WeightInfo::set_validator_count())]
1993 pub fn set_validator_count(
1994 origin: OriginFor<T>,
1995 #[pallet::compact] new: u32,
1996 ) -> DispatchResult {
1997 ensure_root(origin)?;
1998
1999 ensure!(new <= T::MaxValidatorSet::get(), Error::<T>::TooManyValidators);
2000
2001 ValidatorCount::<T>::put(new);
2002 Ok(())
2003 }
2004
2005 /// Increments the ideal number of validators up to maximum of
2006 /// `T::MaxValidatorSet`.
2007 ///
2008 /// The dispatch origin must be Root.
2009 #[pallet::call_index(10)]
2010 #[pallet::weight(T::WeightInfo::set_validator_count())]
2011 pub fn increase_validator_count(
2012 origin: OriginFor<T>,
2013 #[pallet::compact] additional: u32,
2014 ) -> DispatchResult {
2015 ensure_root(origin)?;
2016 let old = ValidatorCount::<T>::get();
2017 let new = old.checked_add(additional).ok_or(ArithmeticError::Overflow)?;
2018
2019 ensure!(new <= T::MaxValidatorSet::get(), Error::<T>::TooManyValidators);
2020
2021 ValidatorCount::<T>::put(new);
2022 Ok(())
2023 }
2024
2025 /// Scale up the ideal number of validators by a factor up to maximum of
2026 /// `T::MaxValidatorSet`.
2027 ///
2028 /// The dispatch origin must be Root.
2029 #[pallet::call_index(11)]
2030 #[pallet::weight(T::WeightInfo::set_validator_count())]
2031 pub fn scale_validator_count(origin: OriginFor<T>, factor: Percent) -> DispatchResult {
2032 ensure_root(origin)?;
2033 let old = ValidatorCount::<T>::get();
2034 let new = old.checked_add(factor.mul_floor(old)).ok_or(ArithmeticError::Overflow)?;
2035
2036 ensure!(new <= T::MaxValidatorSet::get(), Error::<T>::TooManyValidators);
2037
2038 ValidatorCount::<T>::put(new);
2039 Ok(())
2040 }
2041
2042 /// Force there to be no new eras indefinitely.
2043 ///
2044 /// The dispatch origin must be Root.
2045 ///
2046 /// # Warning
2047 ///
2048 /// The election process starts multiple blocks before the end of the era.
2049 /// Thus the election process may be ongoing when this is called. In this case the
2050 /// election will continue until the next era is triggered.
2051 #[pallet::call_index(12)]
2052 #[pallet::weight(T::WeightInfo::force_no_eras())]
2053 pub fn force_no_eras(origin: OriginFor<T>) -> DispatchResult {
2054 ensure_root(origin)?;
2055 Self::set_force_era(Forcing::ForceNone);
2056 Ok(())
2057 }
2058
2059 /// Force there to be a new era at the end of the next session. After this, it will be
2060 /// reset to normal (non-forced) behaviour.
2061 ///
2062 /// The dispatch origin must be Root.
2063 ///
2064 /// # Warning
2065 ///
2066 /// The election process starts multiple blocks before the end of the era.
2067 /// If this is called just before a new era is triggered, the election process may not
2068 /// have enough blocks to get a result.
2069 #[pallet::call_index(13)]
2070 #[pallet::weight(T::WeightInfo::force_new_era())]
2071 pub fn force_new_era(origin: OriginFor<T>) -> DispatchResult {
2072 ensure_root(origin)?;
2073 Self::set_force_era(Forcing::ForceNew);
2074 Ok(())
2075 }
2076
2077 /// Set the validators who cannot be slashed (if any).
2078 ///
2079 /// The dispatch origin must be Root.
2080 #[pallet::call_index(14)]
2081 #[pallet::weight(T::WeightInfo::set_invulnerables(invulnerables.len() as u32))]
2082 pub fn set_invulnerables(
2083 origin: OriginFor<T>,
2084 invulnerables: Vec<T::AccountId>,
2085 ) -> DispatchResult {
2086 ensure_root(origin)?;
2087 let invulnerables =
2088 BoundedVec::try_from(invulnerables).map_err(|_| Error::<T>::BoundNotMet)?;
2089 <Invulnerables<T>>::put(invulnerables);
2090 Ok(())
2091 }
2092
2093 /// Force a current staker to become completely unstaked, immediately.
2094 ///
2095 /// The dispatch origin must be Root.
2096 /// ## Parameters
2097 ///
2098 /// - `stash`: The stash account to be unstaked.
2099 /// - `num_slashing_spans`: **Deprecated**. This parameter is retained for backward
2100 /// compatibility. It no longer has any effect.
2101 #[pallet::call_index(15)]
2102 #[pallet::weight(T::WeightInfo::force_unstake())]
2103 pub fn force_unstake(
2104 origin: OriginFor<T>,
2105 stash: T::AccountId,
2106 _num_slashing_spans: u32,
2107 ) -> DispatchResult {
2108 ensure_root(origin)?;
2109
2110 // Remove all staking-related information and lock.
2111 Self::kill_stash(&stash)?;
2112
2113 Ok(())
2114 }
2115
2116 /// Force there to be a new era at the end of sessions indefinitely.
2117 ///
2118 /// The dispatch origin must be Root.
2119 ///
2120 /// # Warning
2121 ///
2122 /// The election process starts multiple blocks before the end of the era.
2123 /// If this is called just before a new era is triggered, the election process may not
2124 /// have enough blocks to get a result.
2125 #[pallet::call_index(16)]
2126 #[pallet::weight(T::WeightInfo::force_new_era_always())]
2127 pub fn force_new_era_always(origin: OriginFor<T>) -> DispatchResult {
2128 ensure_root(origin)?;
2129 Self::set_force_era(Forcing::ForceAlways);
2130 Ok(())
2131 }
2132
2133 /// Cancels scheduled slashes for a given era before they are applied.
2134 ///
2135 /// This function allows `T::AdminOrigin` to cancel pending slashes for specified validators
2136 /// in a given era. The cancelled slashes are stored and will be checked when applying
2137 /// slashes.
2138 ///
2139 /// ## Parameters
2140 /// - `era`: The staking era for which slashes should be cancelled. This is the era where
2141 /// the slash would be applied, not the era in which the offence was committed.
2142 /// - `validator_slashes`: A list of validator stash accounts and their slash fractions to
2143 /// be cancelled.
2144 #[pallet::call_index(17)]
2145 #[pallet::weight(T::WeightInfo::cancel_deferred_slash(validator_slashes.len() as u32))]
2146 pub fn cancel_deferred_slash(
2147 origin: OriginFor<T>,
2148 era: EraIndex,
2149 validator_slashes: Vec<(T::AccountId, Perbill)>,
2150 ) -> DispatchResult {
2151 T::AdminOrigin::ensure_origin(origin)?;
2152 ensure!(!validator_slashes.is_empty(), Error::<T>::EmptyTargets);
2153
2154 // Get current cancelled slashes for this era
2155 let mut cancelled_slashes = CancelledSlashes::<T>::get(&era);
2156
2157 // Process each validator slash
2158 for (validator, slash_fraction) in validator_slashes {
2159 // Since this is gated by admin origin, we don't need to check if they are really
2160 // validators and trust governance to correctly set the parameters.
2161
2162 // Remove any existing entry for this validator
2163 cancelled_slashes.retain(|(v, _)| v != &validator);
2164
2165 // Add the validator with the specified slash fraction
2166 cancelled_slashes
2167 .try_push((validator.clone(), slash_fraction))
2168 .map_err(|_| Error::<T>::BoundNotMet)
2169 .defensive_proof("cancelled_slashes should have capacity for all validators")?;
2170
2171 Self::deposit_event(Event::<T>::SlashCancelled { slash_era: era, validator });
2172 }
2173
2174 // Update storage
2175 CancelledSlashes::<T>::insert(&era, cancelled_slashes);
2176
2177 Ok(())
2178 }
2179
2180 /// Pay out next page of the stakers behind a validator for the given era.
2181 ///
2182 /// - `validator_stash` is the stash account of the validator.
2183 /// - `era` may be any era between `[current_era - history_depth; current_era]`.
2184 ///
2185 /// The origin of this call must be _Signed_. Any account can call this function, even if
2186 /// it is not one of the stakers.
2187 ///
2188 /// The reward payout could be paged in case there are too many nominators backing the
2189 /// `validator_stash`. This call will payout unpaid pages in an ascending order. To claim a
2190 /// specific page, use `payout_stakers_by_page`.`
2191 ///
2192 /// If all pages are claimed, it returns an error `InvalidPage`.
2193 #[pallet::call_index(18)]
2194 #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked(T::MaxExposurePageSize::get()))]
2195 pub fn payout_stakers(
2196 origin: OriginFor<T>,
2197 validator_stash: T::AccountId,
2198 era: EraIndex,
2199 ) -> DispatchResultWithPostInfo {
2200 ensure_signed(origin)?;
2201
2202 Self::do_payout_stakers(validator_stash, era)
2203 }
2204
2205 /// Rebond a portion of the stash scheduled to be unlocked.
2206 ///
2207 /// The dispatch origin must be signed by the controller.
2208 #[pallet::call_index(19)]
2209 #[pallet::weight(T::WeightInfo::rebond(T::MaxUnlockingChunks::get() as u32))]
2210 pub fn rebond(
2211 origin: OriginFor<T>,
2212 #[pallet::compact] value: BalanceOf<T>,
2213 ) -> DispatchResultWithPostInfo {
2214 let controller = ensure_signed(origin)?;
2215 let ledger = Self::ledger(Controller(controller))?;
2216
2217 ensure!(!T::Filter::contains(&ledger.stash), Error::<T>::Restricted);
2218 ensure!(!ledger.unlocking.is_empty(), Error::<T>::NoUnlockChunk);
2219
2220 let initial_unlocking = ledger.unlocking.len() as u32;
2221 let (ledger, rebonded_value) = ledger.rebond(value);
2222 // Last check: the new active amount of ledger must be more than min bond.
2223 ensure!(ledger.active >= Self::min_chilled_bond(), Error::<T>::InsufficientBond);
2224
2225 Self::deposit_event(Event::<T>::Bonded {
2226 stash: ledger.stash.clone(),
2227 amount: rebonded_value,
2228 });
2229
2230 let stash = ledger.stash.clone();
2231 let final_unlocking = ledger.unlocking.len();
2232
2233 // NOTE: ledger must be updated prior to calling `Self::weight_of`.
2234 ledger.update()?;
2235 if T::VoterList::contains(&stash) {
2236 let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash));
2237 }
2238
2239 let removed_chunks = 1u32 // for the case where the last iterated chunk is not removed
2240 .saturating_add(initial_unlocking)
2241 .saturating_sub(final_unlocking as u32);
2242 Ok(Some(T::WeightInfo::rebond(removed_chunks)).into())
2243 }
2244
2245 /// Remove all data structures concerning a staker/stash once it is at a state where it can
2246 /// be considered `dust` in the staking system. The requirements are:
2247 ///
2248 /// 1. the `total_balance` of the stash is below `min_chilled_bond` or is zero.
2249 /// 2. or, the `ledger.total` of the stash is below `min_chilled_bond` or is zero.
2250 ///
2251 /// The former can happen in cases like a slash; the latter when a fully unbonded account
2252 /// is still receiving staking rewards in `RewardDestination::Staked`.
2253 ///
2254 /// It can be called by anyone, as long as `stash` meets the above requirements.
2255 ///
2256 /// Refunds the transaction fees upon successful execution.
2257 ///
2258 /// ## Parameters
2259 ///
2260 /// - `stash`: The stash account to be reaped.
2261 /// - `num_slashing_spans`: **Deprecated**. This parameter is retained for backward
2262 /// compatibility. It no longer has any effect.
2263 #[pallet::call_index(20)]
2264 #[pallet::weight(T::WeightInfo::reap_stash())]
2265 pub fn reap_stash(
2266 origin: OriginFor<T>,
2267 stash: T::AccountId,
2268 _num_slashing_spans: u32,
2269 ) -> DispatchResultWithPostInfo {
2270 let _ = ensure_signed(origin)?;
2271
2272 // virtual stakers should not be allowed to be reaped.
2273 ensure!(!Self::is_virtual_staker(&stash), Error::<T>::VirtualStakerNotAllowed);
2274
2275 let min_chilled_bond = Self::min_chilled_bond();
2276 let origin_balance = asset::total_balance::<T>(&stash);
2277 let ledger_total =
2278 Self::ledger(Stash(stash.clone())).map(|l| l.total).unwrap_or_default();
2279 let reapable = origin_balance < min_chilled_bond ||
2280 origin_balance.is_zero() ||
2281 ledger_total < min_chilled_bond ||
2282 ledger_total.is_zero();
2283 ensure!(reapable, Error::<T>::FundedTarget);
2284
2285 // Remove all staking-related information and lock.
2286 Self::kill_stash(&stash)?;
2287
2288 Ok(Pays::No.into())
2289 }
2290
2291 /// Remove the given nominations from the calling validator.
2292 ///
2293 /// Effects will be felt at the beginning of the next era.
2294 ///
2295 /// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
2296 ///
2297 /// - `who`: A list of nominator stash accounts who are nominating this validator which
2298 /// should no longer be nominating this validator.
2299 ///
2300 /// Note: Making this call only makes sense if you first set the validator preferences to
2301 /// block any further nominations.
2302 #[pallet::call_index(21)]
2303 #[pallet::weight(T::WeightInfo::kick(who.len() as u32))]
2304 pub fn kick(origin: OriginFor<T>, who: Vec<AccountIdLookupOf<T>>) -> DispatchResult {
2305 let controller = ensure_signed(origin)?;
2306 let ledger = Self::ledger(Controller(controller))?;
2307 let stash = &ledger.stash;
2308
2309 for nom_stash in who
2310 .into_iter()
2311 .map(T::Lookup::lookup)
2312 .collect::<Result<Vec<T::AccountId>, _>>()?
2313 .into_iter()
2314 {
2315 Nominators::<T>::mutate(&nom_stash, |maybe_nom| {
2316 if let Some(ref mut nom) = maybe_nom {
2317 if let Some(pos) = nom.targets.iter().position(|v| v == stash) {
2318 nom.targets.swap_remove(pos);
2319 Self::deposit_event(Event::<T>::Kicked {
2320 nominator: nom_stash.clone(),
2321 stash: stash.clone(),
2322 });
2323 }
2324 }
2325 });
2326 }
2327
2328 Ok(())
2329 }
2330
2331 /// Update the various staking configurations .
2332 ///
2333 /// * `min_nominator_bond`: The minimum active bond needed to be a nominator.
2334 /// * `min_validator_bond`: The minimum active bond needed to be a validator.
2335 /// * `max_nominator_count`: The max number of users who can be a nominator at once. When
2336 /// set to `None`, no limit is enforced.
2337 /// * `max_validator_count`: The max number of users who can be a validator at once. When
2338 /// set to `None`, no limit is enforced.
2339 /// * `chill_threshold`: The ratio of `max_nominator_count` or `max_validator_count` which
2340 /// should be filled in order for the `chill_other` transaction to work.
2341 /// * `min_commission`: The minimum amount of commission that each validators must maintain.
2342 /// This is checked only upon calling `validate`. Existing validators are not affected.
2343 ///
2344 /// RuntimeOrigin must be Root to call this function.
2345 ///
2346 /// NOTE: Existing nominators and validators will not be affected by this update.
2347 /// to kick people under the new limits, `chill_other` should be called.
2348 // We assume the worst case for this call is either: all items are set or all items are
2349 // removed.
2350 #[pallet::call_index(22)]
2351 #[pallet::weight(
2352 T::WeightInfo::set_staking_configs_all_set()
2353 .max(T::WeightInfo::set_staking_configs_all_remove())
2354 )]
2355 pub fn set_staking_configs(
2356 origin: OriginFor<T>,
2357 min_nominator_bond: ConfigOp<BalanceOf<T>>,
2358 min_validator_bond: ConfigOp<BalanceOf<T>>,
2359 max_nominator_count: ConfigOp<u32>,
2360 max_validator_count: ConfigOp<u32>,
2361 chill_threshold: ConfigOp<Percent>,
2362 min_commission: ConfigOp<Perbill>,
2363 max_staked_rewards: ConfigOp<Percent>,
2364 are_nominators_slashable: ConfigOp<bool>,
2365 ) -> DispatchResult {
2366 ensure_root(origin)?;
2367
2368 macro_rules! config_op_exp {
2369 ($storage:ty, $op:ident) => {
2370 match $op {
2371 ConfigOp::Noop => (),
2372 ConfigOp::Set(v) => <$storage>::put(v),
2373 ConfigOp::Remove => <$storage>::kill(),
2374 }
2375 };
2376 }
2377
2378 config_op_exp!(MinNominatorBond<T>, min_nominator_bond);
2379 config_op_exp!(MinValidatorBond<T>, min_validator_bond);
2380 config_op_exp!(MaxNominatorsCount<T>, max_nominator_count);
2381 config_op_exp!(MaxValidatorsCount<T>, max_validator_count);
2382 config_op_exp!(ChillThreshold<T>, chill_threshold);
2383 config_op_exp!(MinCommission<T>, min_commission);
2384 config_op_exp!(MaxStakedRewards<T>, max_staked_rewards);
2385 config_op_exp!(AreNominatorsSlashable<T>, are_nominators_slashable);
2386 Ok(())
2387 }
2388 /// Declare a `controller` to stop participating as either a validator or nominator.
2389 ///
2390 /// Effects will be felt at the beginning of the next era.
2391 ///
2392 /// The dispatch origin for this call must be _Signed_, but can be called by anyone.
2393 ///
2394 /// If the caller is the same as the controller being targeted, then no further checks are
2395 /// enforced, and this function behaves just like `chill`.
2396 ///
2397 /// If the caller is different than the controller being targeted, the following conditions
2398 /// must be met:
2399 ///
2400 /// * `controller` must belong to a nominator who has become non-decodable,
2401 ///
2402 /// Or:
2403 ///
2404 /// * A `ChillThreshold` must be set and checked which defines how close to the max
2405 /// nominators or validators we must reach before users can start chilling one-another.
2406 /// * A `MaxNominatorCount` and `MaxValidatorCount` must be set which is used to determine
2407 /// how close we are to the threshold.
2408 /// * A `MinNominatorBond` and `MinValidatorBond` must be set and checked, which determines
2409 /// if this is a person that should be chilled because they have not met the threshold
2410 /// bond required.
2411 ///
2412 /// This can be helpful if bond requirements are updated, and we need to remove old users
2413 /// who do not satisfy these requirements.
2414 #[pallet::call_index(23)]
2415 #[pallet::weight(T::WeightInfo::chill_other())]
2416 pub fn chill_other(origin: OriginFor<T>, stash: T::AccountId) -> DispatchResult {
2417 // Anyone can call this function.
2418 let caller = ensure_signed(origin)?;
2419 let ledger = Self::ledger(Stash(stash.clone()))?;
2420 let controller = ledger
2421 .controller()
2422 .defensive_proof(
2423 "Ledger's controller field didn't exist. The controller should have been fetched using StakingLedger.",
2424 )
2425 .ok_or(Error::<T>::NotController)?;
2426
2427 // In order for one user to chill another user, the following conditions must be met:
2428 //
2429 // * `controller` belongs to a nominator who has become non-decodable,
2430 //
2431 // Or
2432 //
2433 // * A `ChillThreshold` is set which defines how close to the max nominators or
2434 // validators we must reach before users can start chilling one-another.
2435 // * A `MaxNominatorCount` and `MaxValidatorCount` which is used to determine how close
2436 // we are to the threshold.
2437 // * A `MinNominatorBond` and `MinValidatorBond` which is the final condition checked to
2438 // determine this is a person that should be chilled because they have not met the
2439 // threshold bond required.
2440 //
2441 // Otherwise, if caller is the same as the controller, this is just like `chill`.
2442
2443 if Nominators::<T>::contains_key(&stash) && Nominators::<T>::get(&stash).is_none() {
2444 Self::chill_stash(&stash);
2445 return Ok(());
2446 }
2447
2448 if caller != controller {
2449 let threshold = ChillThreshold::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
2450 let min_active_bond = if Nominators::<T>::contains_key(&stash) {
2451 let max_nominator_count =
2452 MaxNominatorsCount::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
2453 let current_nominator_count = Nominators::<T>::count();
2454 ensure!(
2455 threshold * max_nominator_count < current_nominator_count,
2456 Error::<T>::CannotChillOther
2457 );
2458 Self::min_nominator_bond()
2459 } else if Validators::<T>::contains_key(&stash) {
2460 let max_validator_count =
2461 MaxValidatorsCount::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
2462 let current_validator_count = Validators::<T>::count();
2463 ensure!(
2464 threshold * max_validator_count < current_validator_count,
2465 Error::<T>::CannotChillOther
2466 );
2467 Self::min_validator_bond()
2468 } else {
2469 Zero::zero()
2470 };
2471
2472 ensure!(ledger.active < min_active_bond, Error::<T>::CannotChillOther);
2473 }
2474
2475 Self::chill_stash(&stash);
2476 Ok(())
2477 }
2478
2479 /// Force a validator to have at least the minimum commission. This will not affect a
2480 /// validator who already has a commission greater than or equal to the minimum. Any account
2481 /// can call this.
2482 #[pallet::call_index(24)]
2483 #[pallet::weight(T::WeightInfo::force_apply_min_commission())]
2484 pub fn force_apply_min_commission(
2485 origin: OriginFor<T>,
2486 validator_stash: T::AccountId,
2487 ) -> DispatchResult {
2488 ensure_signed(origin)?;
2489 let min_commission = MinCommission::<T>::get();
2490 Validators::<T>::try_mutate_exists(validator_stash, |maybe_prefs| {
2491 maybe_prefs
2492 .as_mut()
2493 .map(|prefs| {
2494 (prefs.commission < min_commission)
2495 .then(|| prefs.commission = min_commission)
2496 })
2497 .ok_or(Error::<T>::NotStash)
2498 })?;
2499 Ok(())
2500 }
2501
2502 /// Sets the minimum amount of commission that each validators must maintain.
2503 ///
2504 /// This call has lower privilege requirements than `set_staking_config` and can be called
2505 /// by the `T::AdminOrigin`. Root can always call this.
2506 #[pallet::call_index(25)]
2507 #[pallet::weight(T::WeightInfo::set_min_commission())]
2508 pub fn set_min_commission(origin: OriginFor<T>, new: Perbill) -> DispatchResult {
2509 T::AdminOrigin::ensure_origin(origin)?;
2510 MinCommission::<T>::put(new);
2511 Ok(())
2512 }
2513
2514 /// Pay out a page of the stakers behind a validator for the given era and page.
2515 ///
2516 /// - `validator_stash` is the stash account of the validator.
2517 /// - `era` may be any era between `[current_era - history_depth; current_era]`.
2518 /// - `page` is the page index of nominators to pay out with value between 0 and
2519 /// `num_nominators / T::MaxExposurePageSize`.
2520 ///
2521 /// The origin of this call must be _Signed_. Any account can call this function, even if
2522 /// it is not one of the stakers.
2523 ///
2524 /// If a validator has more than [`Config::MaxExposurePageSize`] nominators backing
2525 /// them, then the list of nominators is paged, with each page being capped at
2526 /// [`Config::MaxExposurePageSize`.] If a validator has more than one page of nominators,
2527 /// the call needs to be made for each page separately in order for all the nominators
2528 /// backing a validator to receive the reward. The nominators are not sorted across pages
2529 /// and so it should not be assumed the highest staker would be on the topmost page and vice
2530 /// versa. If rewards are not claimed in [`Config::HistoryDepth`] eras, they are lost.
2531 #[pallet::call_index(26)]
2532 #[pallet::weight(T::WeightInfo::payout_stakers_alive_staked(T::MaxExposurePageSize::get()))]
2533 pub fn payout_stakers_by_page(
2534 origin: OriginFor<T>,
2535 validator_stash: T::AccountId,
2536 era: EraIndex,
2537 page: Page,
2538 ) -> DispatchResultWithPostInfo {
2539 ensure_signed(origin)?;
2540 Self::do_payout_stakers_by_page(validator_stash, era, page)
2541 }
2542
2543 /// Migrates an account's `RewardDestination::Controller` to
2544 /// `RewardDestination::Account(controller)`.
2545 ///
2546 /// Effects will be felt instantly (as soon as this function is completed successfully).
2547 ///
2548 /// This will waive the transaction fee if the `payee` is successfully migrated.
2549 #[pallet::call_index(27)]
2550 #[pallet::weight(T::WeightInfo::update_payee())]
2551 pub fn update_payee(
2552 origin: OriginFor<T>,
2553 controller: T::AccountId,
2554 ) -> DispatchResultWithPostInfo {
2555 let _ = ensure_signed(origin)?;
2556 let ledger = Self::ledger(StakingAccount::Controller(controller.clone()))?;
2557
2558 ensure!(
2559 (Payee::<T>::get(&ledger.stash) == {
2560 #[allow(deprecated)]
2561 Some(RewardDestination::Controller)
2562 }),
2563 Error::<T>::NotController
2564 );
2565
2566 let _ = ledger
2567 .set_payee(RewardDestination::Account(controller))
2568 .defensive_proof("ledger should have been previously retrieved from storage.")?;
2569
2570 Ok(Pays::No.into())
2571 }
2572
2573 /// Updates a batch of controller accounts to their corresponding stash account if they are
2574 /// not the same. Ignores any controller accounts that do not exist, and does not operate if
2575 /// the stash and controller are already the same.
2576 ///
2577 /// Effects will be felt instantly (as soon as this function is completed successfully).
2578 ///
2579 /// The dispatch origin must be `T::AdminOrigin`.
2580 #[pallet::call_index(28)]
2581 #[pallet::weight(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32))]
2582 pub fn deprecate_controller_batch(
2583 origin: OriginFor<T>,
2584 controllers: BoundedVec<T::AccountId, T::MaxControllersInDeprecationBatch>,
2585 ) -> DispatchResultWithPostInfo {
2586 T::AdminOrigin::ensure_origin(origin)?;
2587
2588 // Ignore controllers that do not exist or are already the same as stash.
2589 let filtered_batch_with_ledger: Vec<_> = controllers
2590 .iter()
2591 .filter_map(|controller| {
2592 let ledger = Self::ledger(StakingAccount::Controller(controller.clone()));
2593 ledger.ok().map_or(None, |ledger| {
2594 // If the controller `RewardDestination` is still the deprecated
2595 // `Controller` variant, skip deprecating this account.
2596 let payee_deprecated = Payee::<T>::get(&ledger.stash) == {
2597 #[allow(deprecated)]
2598 Some(RewardDestination::Controller)
2599 };
2600
2601 if ledger.stash != *controller && !payee_deprecated {
2602 Some(ledger)
2603 } else {
2604 None
2605 }
2606 })
2607 })
2608 .collect();
2609
2610 // Update unique pairs.
2611 let mut failures = 0;
2612 for ledger in filtered_batch_with_ledger {
2613 let _ = ledger.clone().set_controller_to_stash().map_err(|_| failures += 1);
2614 }
2615 Self::deposit_event(Event::<T>::ControllerBatchDeprecated { failures });
2616
2617 Ok(Some(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32)).into())
2618 }
2619
2620 /// Restores the state of a ledger which is in an inconsistent state.
2621 ///
2622 /// The requirements to restore a ledger are the following:
2623 /// * The stash is bonded; or
2624 /// * The stash is not bonded but it has a staking lock left behind; or
2625 /// * If the stash has an associated ledger and its state is inconsistent; or
2626 /// * If the ledger is not corrupted *but* its staking lock is out of sync.
2627 ///
2628 /// The `maybe_*` input parameters will overwrite the corresponding data and metadata of the
2629 /// ledger associated with the stash. If the input parameters are not set, the ledger will
2630 /// be reset values from on-chain state.
2631 #[pallet::call_index(29)]
2632 #[pallet::weight(T::WeightInfo::restore_ledger())]
2633 pub fn restore_ledger(
2634 origin: OriginFor<T>,
2635 stash: T::AccountId,
2636 maybe_controller: Option<T::AccountId>,
2637 maybe_total: Option<BalanceOf<T>>,
2638 maybe_unlocking: Option<BoundedVec<UnlockChunk<BalanceOf<T>>, T::MaxUnlockingChunks>>,
2639 ) -> DispatchResult {
2640 T::AdminOrigin::ensure_origin(origin)?;
2641
2642 // cannot restore ledger for virtual stakers.
2643 ensure!(!Self::is_virtual_staker(&stash), Error::<T>::VirtualStakerNotAllowed);
2644
2645 let current_lock = asset::staked::<T>(&stash);
2646 let stash_balance = asset::stakeable_balance::<T>(&stash);
2647
2648 let (new_controller, new_total) = match Self::inspect_bond_state(&stash) {
2649 Ok(LedgerIntegrityState::Corrupted) => {
2650 let new_controller = maybe_controller.unwrap_or(stash.clone());
2651
2652 let new_total = if let Some(total) = maybe_total {
2653 let new_total = total.min(stash_balance);
2654 // enforce hold == ledger.amount.
2655 asset::update_stake::<T>(&stash, new_total)?;
2656 new_total
2657 } else {
2658 current_lock
2659 };
2660
2661 Ok((new_controller, new_total))
2662 },
2663 Ok(LedgerIntegrityState::CorruptedKilled) => {
2664 if current_lock == Zero::zero() {
2665 // this case needs to restore both lock and ledger, so the new total needs
2666 // to be given by the called since there's no way to restore the total
2667 // on-chain.
2668 ensure!(maybe_total.is_some(), Error::<T>::CannotRestoreLedger);
2669 Ok((
2670 stash.clone(),
2671 maybe_total.expect("total exists as per the check above; qed."),
2672 ))
2673 } else {
2674 Ok((stash.clone(), current_lock))
2675 }
2676 },
2677 Ok(LedgerIntegrityState::LockCorrupted) => {
2678 // ledger is not corrupted but its locks are out of sync. In this case, we need
2679 // to enforce a new ledger.total and staking lock for this stash.
2680 let new_total =
2681 maybe_total.ok_or(Error::<T>::CannotRestoreLedger)?.min(stash_balance);
2682 asset::update_stake::<T>(&stash, new_total)?;
2683
2684 Ok((stash.clone(), new_total))
2685 },
2686 Err(Error::<T>::BadState) => {
2687 // the stash and ledger do not exist but lock is lingering.
2688 asset::kill_stake::<T>(&stash)?;
2689 ensure!(
2690 Self::inspect_bond_state(&stash) == Err(Error::<T>::NotStash),
2691 Error::<T>::BadState
2692 );
2693
2694 return Ok(());
2695 },
2696 Ok(LedgerIntegrityState::Ok) | Err(_) => Err(Error::<T>::CannotRestoreLedger),
2697 }?;
2698
2699 // re-bond stash and controller tuple.
2700 Bonded::<T>::insert(&stash, &new_controller);
2701
2702 // resoter ledger state.
2703 let mut ledger = StakingLedger::<T>::new(stash.clone(), new_total);
2704 ledger.controller = Some(new_controller);
2705 ledger.unlocking = maybe_unlocking.unwrap_or_default();
2706 ledger.update()?;
2707
2708 ensure!(
2709 Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok),
2710 Error::<T>::BadState
2711 );
2712 Ok(())
2713 }
2714
2715 /// Migrates permissionlessly a stash from locks to holds.
2716 ///
2717 /// This removes the old lock on the stake and creates a hold on it atomically. If all
2718 /// stake cannot be held, the best effort is made to hold as much as possible. The remaining
2719 /// stake is removed from the ledger.
2720 ///
2721 /// The fee is waived if the migration is successful.
2722 #[pallet::call_index(30)]
2723 #[pallet::weight(T::WeightInfo::migrate_currency())]
2724 pub fn migrate_currency(
2725 origin: OriginFor<T>,
2726 stash: T::AccountId,
2727 ) -> DispatchResultWithPostInfo {
2728 let _ = ensure_signed(origin)?;
2729 Self::do_migrate_currency(&stash)?;
2730
2731 // Refund the transaction fee if successful.
2732 Ok(Pays::No.into())
2733 }
2734
2735 /// Manually and permissionlessly applies a deferred slash for a given era.
2736 ///
2737 /// Normally, slashes are automatically applied shortly after the start of the `slash_era`.
2738 /// The automatic application of slashes is handled by the pallet's internal logic, and it
2739 /// tries to apply one slash page per block of the era.
2740 /// If for some reason, one era is not enough for applying all slash pages, the remaining
2741 /// slashes need to be manually (permissionlessly) applied.
2742 ///
2743 /// For a given era x, if at era x+1, slashes are still unapplied, all withdrawals get
2744 /// blocked, and these need to be manually applied by calling this function.
2745 /// This function exists as a **fallback mechanism** for this extreme situation, but we
2746 /// never expect to encounter this in normal scenarios.
2747 ///
2748 /// The parameters for this call can be queried by looking at the `UnappliedSlashes` storage
2749 /// for eras older than the active era.
2750 ///
2751 /// ## Parameters
2752 /// - `slash_era`: The staking era in which the slash was originally scheduled.
2753 /// - `slash_key`: A unique identifier for the slash, represented as a tuple:
2754 /// - `stash`: The stash account of the validator being slashed.
2755 /// - `slash_fraction`: The fraction of the stake that was slashed.
2756 /// - `page_index`: The index of the exposure page being processed.
2757 ///
2758 /// ## Behavior
2759 /// - The function is **permissionless**—anyone can call it.
2760 /// - The `slash_era` **must be the current era or a past era**.
2761 /// If it is in the future, the
2762 /// call fails with `EraNotStarted`.
2763 /// - The fee is waived if the slash is successfully applied.
2764 ///
2765 /// ## Future Improvement
2766 /// - Implement an **off-chain worker (OCW) task** to automatically apply slashes when there
2767 /// is unused block space, improving efficiency.
2768 #[pallet::call_index(31)]
2769 #[pallet::weight(T::WeightInfo::apply_slash(T::MaxExposurePageSize::get()))]
2770 pub fn apply_slash(
2771 origin: OriginFor<T>,
2772 slash_era: EraIndex,
2773 slash_key: (T::AccountId, Perbill, u32),
2774 ) -> DispatchResultWithPostInfo {
2775 let _ = ensure_signed(origin)?;
2776 let active_era = ActiveEra::<T>::get().map(|a| a.index).unwrap_or_default();
2777 ensure!(slash_era <= active_era, Error::<T>::EraNotStarted);
2778
2779 // Check if this slash has been cancelled
2780 ensure!(
2781 !Self::check_slash_cancelled(slash_era, &slash_key.0, slash_key.1),
2782 Error::<T>::CancelledSlash
2783 );
2784
2785 let unapplied_slash = UnappliedSlashes::<T>::take(&slash_era, &slash_key)
2786 .ok_or(Error::<T>::InvalidSlashRecord)?;
2787 slashing::apply_slash::<T>(unapplied_slash, slash_era);
2788
2789 Ok(Pays::No.into())
2790 }
2791
2792 /// Perform one step of era pruning to prevent PoV size exhaustion from unbounded deletions.
2793 ///
2794 /// This extrinsic enables permissionless lazy pruning of era data by performing
2795 /// incremental deletion of storage items. Each call processes a limited number
2796 /// of items based on available block weight to avoid exceeding block limits.
2797 ///
2798 /// Returns `Pays::No` when work is performed to incentivize regular maintenance.
2799 /// Anyone can call this to help maintain the chain's storage health.
2800 ///
2801 /// The era must be eligible for pruning (older than HistoryDepth + 1).
2802 /// Check `EraPruningState` storage to see if an era needs pruning before calling.
2803 #[pallet::call_index(32)]
2804 // NOTE: as pre-dispatch weight, use the maximum of all possible pruning step weights
2805 #[pallet::weight({
2806 let v = T::MaxValidatorSet::get();
2807 T::WeightInfo::prune_era_stakers_paged(v)
2808 .max(T::WeightInfo::prune_era_stakers_overview(v))
2809 .max(T::WeightInfo::prune_era_validator_prefs(v))
2810 .max(T::WeightInfo::prune_era_claimed_rewards(v))
2811 .max(T::WeightInfo::prune_era_validator_reward())
2812 .max(T::WeightInfo::prune_era_reward_points())
2813 .max(T::WeightInfo::prune_era_single_entry_cleanups())
2814 .max(T::WeightInfo::prune_era_validator_slash_in_era(v))
2815 })]
2816 pub fn prune_era_step(origin: OriginFor<T>, era: EraIndex) -> DispatchResultWithPostInfo {
2817 let _ = ensure_signed(origin)?;
2818
2819 // Verify era is eligible for pruning: era <= active_era - history_depth - 1
2820 let active_era = crate::session_rotation::Rotator::<T>::active_era();
2821 let history_depth = T::HistoryDepth::get();
2822 let earliest_prunable_era = active_era.saturating_sub(history_depth).saturating_sub(1);
2823 ensure!(era <= earliest_prunable_era, Error::<T>::EraNotPrunable);
2824
2825 let actual_weight = Self::do_prune_era_step(era)?;
2826
2827 Ok(frame_support::dispatch::PostDispatchInfo {
2828 actual_weight: Some(actual_weight),
2829 pays_fee: frame_support::dispatch::Pays::No,
2830 })
2831 }
2832 }
2833}