1use super::*;
21use crate::{
22 asset,
23 session_rotation::{Eras, Rotator},
24 Pallet as Staking,
25};
26use alloc::collections::BTreeMap;
27pub use frame_benchmarking::{
28 impl_benchmark_test_suite, v2::*, whitelist_account, whitelisted_caller, BenchmarkError,
29};
30use frame_election_provider_support::SortedListProvider;
31use frame_support::{
32 assert_ok,
33 pallet_prelude::*,
34 storage::bounded_vec::BoundedVec,
35 traits::{fungible::Inspect, TryCollect},
36};
37use frame_system::RawOrigin;
38use pallet_staking_async_rc_client as rc_client;
39use sp_runtime::{
40 traits::{Bounded, One, StaticLookup, Zero},
41 Perbill, Percent, Saturating,
42};
43use sp_staking::currency_to_vote::CurrencyToVote;
44use testing_utils::*;
45
46const SEED: u32 = 0;
47
48pub(crate) fn create_validator_with_nominators<T: Config>(
53 n: u32,
54 upper_bound: u32,
55 dead_controller: bool,
56 unique_controller: bool,
57 destination: RewardDestination<T::AccountId>,
58) -> Result<(T::AccountId, Vec<(T::AccountId, T::AccountId)>, EraIndex), &'static str> {
59 clear_validators_and_nominators::<T>();
62
63 DisableMintingGuard::<T>::put(0);
65 let mut points_total = 0;
66 let mut points_individual = Vec::new();
67
68 let (v_stash, v_controller) = if unique_controller {
69 create_unique_stash_controller::<T>(0, 100, destination.clone(), false)?
70 } else {
71 create_stash_controller::<T>(0, 100, destination.clone())?
72 };
73
74 let validator_prefs =
75 ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() };
76 Staking::<T>::validate(RawOrigin::Signed(v_controller).into(), validator_prefs)?;
77 let stash_lookup = T::Lookup::unlookup(v_stash.clone());
78
79 points_total += 10;
80 points_individual.push((v_stash.clone(), 10));
81
82 let original_nominator_count = Nominators::<T>::count();
83 let mut nominators = Vec::new();
84
85 for i in 0..upper_bound {
87 let (n_stash, n_controller) = if !dead_controller {
88 create_stash_controller::<T>(u32::MAX - i, 100, destination.clone())?
89 } else {
90 create_unique_stash_controller::<T>(u32::MAX - i, 100, destination.clone(), true)?
91 };
92 if i < n {
93 Staking::<T>::nominate(
94 RawOrigin::Signed(n_controller.clone()).into(),
95 vec![stash_lookup.clone()],
96 )?;
97 nominators.push((n_stash, n_controller));
98 }
99 }
100
101 ValidatorCount::<T>::put(1);
102
103 let new_validators = Rotator::<T>::legacy_insta_plan_era();
105 let planned_era = CurrentEra::<T>::get().unwrap_or_default();
106
107 assert_eq!(new_validators.len(), 1, "New validators is not 1");
108 assert_eq!(new_validators[0], v_stash, "Our validator was not selected");
109 assert_ne!(Validators::<T>::count(), 0, "New validators count wrong");
110 assert_eq!(
111 Nominators::<T>::count(),
112 original_nominator_count + nominators.len() as u32,
113 "New nominators count wrong"
114 );
115
116 let reward = EraRewardPoints::<T> {
118 total: points_total,
119 individual: points_individual.into_iter().try_collect()?,
120 };
121
122 ErasRewardPoints::<T>::insert(planned_era, reward);
123
124 let total_payout = asset::existential_deposit::<T>()
126 .saturating_mul(upper_bound.into())
127 .saturating_mul(1000u32.into());
128 <ErasValidatorReward<T>>::insert(planned_era, total_payout);
129
130 let era_pot =
132 crate::reward::EraRewardManager::<T>::create(planned_era, RewardKind::StakerRewards);
133 let _ = asset::mint_creating::<T>(&era_pot, total_payout);
134
135 OptimumSelfStake::<T>::put(BalanceOf::<T>::from(30_000u64));
137 HardCapSelfStake::<T>::put(BalanceOf::<T>::from(100_000u64));
138 SelfStakeSlopeFactor::<T>::put(Perbill::from_percent(50));
139
140 let incentive_payout = total_payout / 10u32.into(); let incentive_pot =
142 crate::reward::EraRewardManager::<T>::create(planned_era, RewardKind::ValidatorSelfStake);
143 let _ = asset::mint_creating::<T>(&incentive_pot, incentive_payout);
144 ErasValidatorIncentiveBudget::<T>::insert(planned_era, incentive_payout);
145
146 let incentive_weight = BalanceOf::<T>::from(100u64);
148 ErasValidatorIncentiveWeight::<T>::insert(planned_era, &v_stash, incentive_weight);
149 ErasSumValidatorIncentiveWeight::<T>::insert(planned_era, incentive_weight);
150 let validator_points = BalanceOf::<T>::from(10u64);
154 ErasSumWeightedPoints::<T>::insert(
155 planned_era,
156 incentive_weight.saturating_mul(validator_points),
157 );
158
159 Ok((v_stash, nominators, planned_era))
160}
161
162struct ListScenario<T: Config> {
163 origin_stash1: T::AccountId,
165 origin_controller1: T::AccountId,
167 dest_weight: BalanceOf<T>,
168}
169
170impl<T: Config> ListScenario<T> {
171 fn new(origin_weight: BalanceOf<T>, is_increase: bool) -> Result<Self, &'static str> {
186 ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0");
187
188 let i = asset::burn::<T>(asset::total_issuance::<T>());
190 core::mem::forget(i);
191
192 let validator_account = account("random_validator", 0, SEED);
194 let validator_stake = asset::existential_deposit::<T>() * 1000u32.into();
195 asset::set_stakeable_balance::<T>(&validator_account, validator_stake);
196 assert_ok!(Staking::<T>::bond(
197 RawOrigin::Signed(validator_account.clone()).into(),
198 validator_stake / 2u32.into(),
199 RewardDestination::Staked
200 ));
201 assert_ok!(Staking::<T>::validate(
202 RawOrigin::Signed(validator_account.clone()).into(),
203 Default::default()
204 ));
205
206 let (origin_stash1, origin_controller1) = create_stash_controller_with_balance::<T>(
208 USER_SEED + 2,
209 origin_weight,
210 RewardDestination::Staked,
211 )?;
212 Staking::<T>::nominate(
213 RawOrigin::Signed(origin_controller1.clone()).into(),
214 vec![T::Lookup::unlookup(validator_account.clone())],
216 )?;
217
218 let (_origin_stash2, origin_controller2) = create_stash_controller_with_balance::<T>(
219 USER_SEED + 3,
220 origin_weight,
221 RewardDestination::Staked,
222 )?;
223 Staking::<T>::nominate(
224 RawOrigin::Signed(origin_controller2).into(),
225 vec![T::Lookup::unlookup(validator_account.clone())],
226 )?;
227
228 let dest_weight_as_vote =
230 T::VoterList::score_update_worst_case(&origin_stash1, is_increase);
231
232 let total_issuance = asset::total_issuance::<T>();
233
234 let dest_weight =
235 T::CurrencyToVote::to_currency(dest_weight_as_vote as u128, total_issuance);
236
237 let (_dest_stash1, dest_controller1) = create_stash_controller_with_balance::<T>(
239 USER_SEED + 1,
240 dest_weight,
241 RewardDestination::Staked,
242 )?;
243 Staking::<T>::nominate(
244 RawOrigin::Signed(dest_controller1).into(),
245 vec![T::Lookup::unlookup(validator_account)],
246 )?;
247
248 Ok(ListScenario { origin_stash1, origin_controller1, dest_weight })
249 }
250}
251
252const USER_SEED: u32 = 999666;
253
254#[benchmarks]
255mod benchmarks {
256 use super::*;
257 use alloc::format;
258
259 #[benchmark]
260 fn bond() {
261 let stash = create_funded_user::<T>("stash", USER_SEED, 100);
262 let reward_destination = RewardDestination::Staked;
263 let amount = asset::existential_deposit::<T>() * 10u32.into();
264 whitelist_account!(stash);
265
266 #[extrinsic_call]
267 _(RawOrigin::Signed(stash.clone()), amount, reward_destination);
268
269 assert!(Bonded::<T>::contains_key(stash.clone()));
270 assert!(Ledger::<T>::contains_key(stash));
271 }
272
273 #[benchmark]
274 fn bond_extra() -> Result<(), BenchmarkError> {
275 clear_validators_and_nominators::<T>();
277
278 let origin_weight = Staking::<T>::min_nominator_bond();
279
280 let scenario = ListScenario::<T>::new(origin_weight, true)?;
284
285 let max_additional = scenario.dest_weight - origin_weight;
286
287 let stash = scenario.origin_stash1.clone();
288 let controller = scenario.origin_controller1;
289 let original_bonded: BalanceOf<T> = Ledger::<T>::get(&controller)
290 .map(|l| l.active)
291 .ok_or("ledger not created after")?;
292
293 let _ = asset::mint_into_existing::<T>(
294 &stash,
295 max_additional + asset::existential_deposit::<T>(),
296 )
297 .unwrap();
298
299 whitelist_account!(stash);
300
301 #[extrinsic_call]
302 _(RawOrigin::Signed(stash), max_additional);
303
304 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
305 let new_bonded: BalanceOf<T> = ledger.active;
306 assert!(original_bonded < new_bonded);
307
308 Ok(())
309 }
310
311 #[benchmark]
312 fn unbond() -> Result<(), BenchmarkError> {
313 clear_validators_and_nominators::<T>();
315
316 let origin_weight = BalanceOf::<T>::try_from(952_994_955_240_703u128)
319 .map_err(|_| "balance expected to be a u128")
320 .unwrap();
321 let scenario = ListScenario::<T>::new(origin_weight, false)?;
322
323 let controller = scenario.origin_controller1.clone();
324 let amount = origin_weight - scenario.dest_weight;
325 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created before")?;
326 let original_bonded: BalanceOf<T> = ledger.active;
327
328 whitelist_account!(controller);
329
330 #[extrinsic_call]
331 _(RawOrigin::Signed(controller.clone()), amount);
332
333 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
334 let new_bonded: BalanceOf<T> = ledger.active;
335 assert!(original_bonded > new_bonded);
336
337 Ok(())
338 }
339
340 #[benchmark]
341 fn withdraw_unbonded_update() -> Result<(), BenchmarkError> {
343 let (_, controller) = create_stash_controller::<T>(0, 100, RewardDestination::Staked)?;
344 let amount = asset::existential_deposit::<T>() * 5u32.into(); Staking::<T>::unbond(RawOrigin::Signed(controller.clone()).into(), amount)?;
346 set_active_era::<T>(EraIndex::max_value());
347 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created before")?;
348 let original_total: BalanceOf<T> = ledger.total;
349 whitelist_account!(controller);
350
351 #[extrinsic_call]
352 withdraw_unbonded(RawOrigin::Signed(controller.clone()), 0);
353
354 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
355 let new_total: BalanceOf<T> = ledger.total;
356 assert!(original_total > new_total);
357
358 Ok(())
359 }
360
361 #[benchmark]
362 fn withdraw_unbonded_kill() -> Result<(), BenchmarkError> {
364 clear_validators_and_nominators::<T>();
366
367 let origin_weight = Staking::<T>::min_nominator_bond();
368
369 let scenario = ListScenario::<T>::new(origin_weight, true)?;
372 let controller = scenario.origin_controller1.clone();
373 let stash = scenario.origin_stash1;
374 assert!(T::VoterList::contains(&stash));
375
376 let ed = asset::existential_deposit::<T>();
377 let mut ledger = Ledger::<T>::get(&controller).unwrap();
378 ledger.active = ed - One::one();
379 Ledger::<T>::insert(&controller, ledger);
380 set_active_era::<T>(EraIndex::max_value());
381
382 whitelist_account!(controller);
383
384 #[extrinsic_call]
385 withdraw_unbonded(RawOrigin::Signed(controller.clone()), 0);
386
387 assert!(!Ledger::<T>::contains_key(controller));
388 assert!(!T::VoterList::contains(&stash));
389
390 Ok(())
391 }
392
393 #[benchmark]
394 fn validate() -> Result<(), BenchmarkError> {
395 let (stash, controller) = create_stash_controller::<T>(
396 MaxNominationsOf::<T>::get() - 1,
397 100,
398 RewardDestination::Staked,
399 )?;
400 assert!(!T::VoterList::contains(&stash));
402
403 let prefs = ValidatorPrefs::default();
404 whitelist_account!(controller);
405
406 #[extrinsic_call]
407 _(RawOrigin::Signed(controller), prefs);
408
409 assert!(Validators::<T>::contains_key(&stash));
410 assert!(T::VoterList::contains(&stash));
411
412 Ok(())
413 }
414
415 #[benchmark]
416 fn kick(
417 k: Linear<1, 128>,
422 ) -> Result<(), BenchmarkError> {
423 let rest_of_validators =
426 create_validators_with_seed::<T>(MaxNominationsOf::<T>::get() - 1, 100, 415)?;
427
428 let (stash, controller) = create_stash_controller::<T>(
430 MaxNominationsOf::<T>::get() - 1,
431 100,
432 RewardDestination::Staked,
433 )?;
434 let stash_lookup = T::Lookup::unlookup(stash.clone());
435
436 Staking::<T>::validate(RawOrigin::Signed(controller.clone()).into(), Default::default())?;
438
439 let mut nominator_stashes = Vec::with_capacity(k as usize);
442 for i in 0..k {
443 let (n_stash, n_controller) = create_stash_controller::<T>(
445 MaxNominationsOf::<T>::get() + i,
446 100,
447 RewardDestination::Staked,
448 )?;
449
450 let mut nominations = rest_of_validators.clone();
452 nominations.insert(i as usize % (nominations.len() + 1), stash_lookup.clone());
455 Staking::<T>::nominate(RawOrigin::Signed(n_controller.clone()).into(), nominations)?;
457
458 nominator_stashes.push(n_stash);
459 }
460
461 for n in nominator_stashes.iter() {
463 assert!(Nominators::<T>::get(n).unwrap().targets.contains(&stash));
464 }
465
466 let kicks = nominator_stashes
468 .iter()
469 .map(|n| T::Lookup::unlookup(n.clone()))
470 .collect::<Vec<_>>();
471
472 whitelist_account!(controller);
473
474 #[extrinsic_call]
475 _(RawOrigin::Signed(controller), kicks);
476
477 for n in nominator_stashes.iter() {
479 assert!(!Nominators::<T>::get(n).unwrap().targets.contains(&stash));
480 }
481
482 Ok(())
483 }
484
485 #[benchmark]
486 fn nominate(n: Linear<1, { MaxNominationsOf::<T>::get() }>) -> Result<(), BenchmarkError> {
488 clear_validators_and_nominators::<T>();
490
491 let origin_weight = Staking::<T>::min_nominator_bond();
492
493 ListScenario::<T>::new(origin_weight, true)?;
496 let (stash, controller) = create_stash_controller_with_balance::<T>(
497 SEED + MaxNominationsOf::<T>::get() + 1, origin_weight,
500 RewardDestination::Staked,
501 )
502 .unwrap();
503
504 assert!(!Nominators::<T>::contains_key(&stash));
505 assert!(!T::VoterList::contains(&stash));
506
507 let validators = create_validators::<T>(n, 100).unwrap();
508 whitelist_account!(controller);
509
510 #[extrinsic_call]
511 _(RawOrigin::Signed(controller), validators);
512
513 assert!(Nominators::<T>::contains_key(&stash));
514 assert!(T::VoterList::contains(&stash));
515
516 Ok(())
517 }
518
519 #[benchmark]
520 fn chill() -> Result<(), BenchmarkError> {
521 clear_validators_and_nominators::<T>();
523
524 let origin_weight = Staking::<T>::min_nominator_bond();
525
526 let scenario = ListScenario::<T>::new(origin_weight, true)?;
529 let controller = scenario.origin_controller1.clone();
530 let stash = scenario.origin_stash1;
531 assert!(T::VoterList::contains(&stash));
532
533 whitelist_account!(controller);
534
535 #[extrinsic_call]
536 _(RawOrigin::Signed(controller));
537
538 assert!(!T::VoterList::contains(&stash));
539
540 Ok(())
541 }
542
543 #[benchmark]
544 fn set_payee() -> Result<(), BenchmarkError> {
545 let (stash, controller) =
546 create_stash_controller::<T>(USER_SEED, 100, RewardDestination::Staked)?;
547 assert_eq!(Payee::<T>::get(&stash), Some(RewardDestination::Staked));
548 whitelist_account!(controller);
549
550 #[extrinsic_call]
551 _(RawOrigin::Signed(controller.clone()), RewardDestination::Account(controller.clone()));
552
553 assert_eq!(Payee::<T>::get(&stash), Some(RewardDestination::Account(controller)));
554
555 Ok(())
556 }
557
558 #[benchmark]
559 fn update_payee() -> Result<(), BenchmarkError> {
560 let (stash, controller) =
561 create_stash_controller::<T>(USER_SEED, 100, RewardDestination::Staked)?;
562 Payee::<T>::insert(&stash, {
563 #[allow(deprecated)]
564 RewardDestination::Controller
565 });
566 whitelist_account!(controller);
567
568 #[extrinsic_call]
569 _(RawOrigin::Signed(controller.clone()), controller.clone());
570
571 assert_eq!(Payee::<T>::get(&stash), Some(RewardDestination::Account(controller)));
572
573 Ok(())
574 }
575
576 #[benchmark]
577 fn set_controller() -> Result<(), BenchmarkError> {
578 let (stash, ctlr) =
579 create_unique_stash_controller::<T>(9000, 100, RewardDestination::Staked, false)?;
580 assert!(!Ledger::<T>::contains_key(&stash));
582 assert!(Ledger::<T>::contains_key(&ctlr));
583 assert_eq!(Bonded::<T>::get(&stash), Some(ctlr.clone()));
584
585 whitelist_account!(stash);
586
587 #[extrinsic_call]
588 _(RawOrigin::Signed(stash.clone()));
589
590 assert!(Ledger::<T>::contains_key(&stash));
591
592 Ok(())
593 }
594
595 #[benchmark]
596 fn set_validator_count() {
597 let validator_count = T::MaxValidatorSet::get() - 1;
598
599 #[extrinsic_call]
600 _(RawOrigin::Root, validator_count);
601
602 assert_eq!(ValidatorCount::<T>::get(), validator_count);
603 }
604
605 #[benchmark]
606 fn force_no_eras() {
607 #[extrinsic_call]
608 _(RawOrigin::Root);
609
610 assert_eq!(ForceEra::<T>::get(), Forcing::ForceNone);
611 }
612
613 #[benchmark]
614 fn force_new_era() {
615 #[extrinsic_call]
616 _(RawOrigin::Root);
617
618 assert_eq!(ForceEra::<T>::get(), Forcing::ForceNew);
619 }
620
621 #[benchmark]
622 fn force_new_era_always() {
623 #[extrinsic_call]
624 _(RawOrigin::Root);
625
626 assert_eq!(ForceEra::<T>::get(), Forcing::ForceAlways);
627 }
628
629 #[benchmark]
630 fn deprecate_controller_batch(
631 u: Linear<0, { T::MaxControllersInDeprecationBatch::get() }>,
634 ) -> Result<(), BenchmarkError> {
635 let mut controllers: Vec<_> = vec![];
636 let mut stashes: Vec<_> = vec![];
637 for i in 0..u as u32 {
638 let (stash, controller) =
639 create_unique_stash_controller::<T>(i, 100, RewardDestination::Staked, false)?;
640 controllers.push(controller);
641 stashes.push(stash);
642 }
643 let bounded_controllers: BoundedVec<_, T::MaxControllersInDeprecationBatch> =
644 BoundedVec::try_from(controllers.clone()).unwrap();
645
646 #[extrinsic_call]
647 _(RawOrigin::Root, bounded_controllers);
648
649 for i in 0..u as u32 {
650 let stash = &stashes[i as usize];
651 let controller = &controllers[i as usize];
652 assert_eq!(Ledger::<T>::get(controller), None);
654 assert_eq!(Bonded::<T>::get(stash), Some(stash.clone()));
656 assert_eq!(Ledger::<T>::get(stash).unwrap().stash, *stash);
658 }
659
660 Ok(())
661 }
662
663 #[benchmark]
664 fn force_unstake() -> Result<(), BenchmarkError> {
665 clear_validators_and_nominators::<T>();
667
668 let origin_weight = Staking::<T>::min_nominator_bond();
669
670 let scenario = ListScenario::<T>::new(origin_weight, true)?;
673 let controller = scenario.origin_controller1.clone();
674 let stash = scenario.origin_stash1;
675 assert!(T::VoterList::contains(&stash));
676
677 #[extrinsic_call]
678 _(RawOrigin::Root, stash.clone(), 0);
679
680 assert!(!Ledger::<T>::contains_key(&controller));
681 assert!(!T::VoterList::contains(&stash));
682
683 Ok(())
684 }
685
686 #[benchmark]
687 fn cancel_deferred_slash(s: Linear<1, { T::MaxValidatorSet::get() }>) {
688 let era = EraIndex::one();
689
690 let validators: Vec<_> = (0..s)
692 .map(|i| {
693 let validator: T::AccountId = account("validator", i, SEED);
694
695 let slash_key = (validator.clone(), Perbill::from_percent(10), 0);
697 let unapplied_slash = UnappliedSlash::<T> {
698 validator: validator.clone(),
699 own: Zero::zero(),
700 others: WeakBoundedVec::default(),
701 reporter: Default::default(),
702 payout: Zero::zero(),
703 };
704 UnappliedSlashes::<T>::insert(era, slash_key, unapplied_slash);
705
706 validator
707 })
708 .collect();
709
710 let validator_slashes: Vec<_> =
712 validators.into_iter().map(|v| (v, Perbill::from_percent(10))).collect();
713
714 #[extrinsic_call]
715 _(RawOrigin::Root, era, validator_slashes.clone());
716
717 let cancelled_slashes = CancelledSlashes::<T>::get(era);
719 assert_eq!(cancelled_slashes.len(), s as usize);
720 }
721
722 #[benchmark]
723 fn payout_stakers_alive_staked(
724 n: Linear<0, { T::MaxExposurePageSize::get() as u32 }>,
725 ) -> Result<(), BenchmarkError> {
726 let (validator, nominators, current_era) = create_validator_with_nominators::<T>(
727 n,
728 T::MaxExposurePageSize::get() as u32,
729 false,
730 true,
731 RewardDestination::Staked,
732 )?;
733
734 <ErasValidatorPrefs<T>>::insert(
736 current_era,
737 validator.clone(),
738 Validators::<T>::get(&validator),
739 );
740
741 let caller = whitelisted_caller();
742 let balance_before = asset::stakeable_balance::<T>(&validator);
743 let incentive_pot = crate::reward::EraRewardManager::<T>::create(
747 current_era,
748 RewardKind::ValidatorSelfStake,
749 );
750 let incentive_pot_before = asset::stakeable_balance::<T>(&incentive_pot);
751 let mut nominator_balances_before = Vec::new();
752 for (stash, _) in &nominators {
753 let balance = asset::stakeable_balance::<T>(stash);
754 nominator_balances_before.push(balance);
755 }
756
757 #[extrinsic_call]
758 payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era);
759
760 let balance_after = asset::stakeable_balance::<T>(&validator);
761 ensure!(
762 balance_before < balance_after,
763 "Balance of validator stash should have increased after payout.",
764 );
765 ensure!(
766 asset::stakeable_balance::<T>(&incentive_pot) < incentive_pot_before,
767 "Incentive pot should have decreased: the validator-incentive transfer must run \
768 so its cost is captured by this benchmark.",
769 );
770 for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter())
771 {
772 let balance_after = asset::stakeable_balance::<T>(stash);
773 ensure!(
774 balance_before < &balance_after,
775 "Balance of nominator stash should have increased after payout.",
776 );
777 }
778
779 Ok(())
780 }
781
782 #[benchmark]
783 fn rebond(l: Linear<1, { T::MaxUnlockingChunks::get() as u32 }>) -> Result<(), BenchmarkError> {
784 clear_validators_and_nominators::<T>();
786
787 let origin_weight = Pallet::<T>::min_nominator_bond()
788 .max(100u32.into());
790
791 let scenario = ListScenario::<T>::new(origin_weight, true)?;
793 let dest_weight = scenario.dest_weight;
794
795 let rebond_amount = dest_weight - origin_weight;
797
798 let value = rebond_amount / l.into();
800 assert_ne!(value, Zero::zero());
802 assert!(value * l.into() + origin_weight > origin_weight);
804 assert!(value * l.into() + origin_weight <= dest_weight);
805 let unlock_chunk = UnlockChunk::<BalanceOf<T>> { value, era: EraIndex::zero() };
806
807 let controller = scenario.origin_controller1;
808 let mut staking_ledger = Ledger::<T>::get(controller.clone()).unwrap();
809
810 for _ in 0..l {
811 staking_ledger.unlocking.try_push(unlock_chunk.clone()).unwrap()
812 }
813 Ledger::<T>::insert(controller.clone(), staking_ledger.clone());
814 let original_bonded: BalanceOf<T> = staking_ledger.active;
815
816 whitelist_account!(controller);
817
818 #[extrinsic_call]
819 _(RawOrigin::Signed(controller.clone()), rebond_amount);
820
821 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
822 let new_bonded: BalanceOf<T> = ledger.active;
823 assert!(original_bonded < new_bonded);
824
825 Ok(())
826 }
827
828 #[benchmark]
829 fn reap_stash() -> Result<(), BenchmarkError> {
830 clear_validators_and_nominators::<T>();
832
833 let origin_weight = Staking::<T>::min_nominator_bond();
834
835 let scenario = ListScenario::<T>::new(origin_weight, true)?;
838 let controller = scenario.origin_controller1.clone();
839 let stash = scenario.origin_stash1;
840
841 let l =
842 StakingLedger::<T>::new(stash.clone(), asset::existential_deposit::<T>() - One::one());
843 Ledger::<T>::insert(&controller, l);
844
845 assert!(Bonded::<T>::contains_key(&stash));
846 assert!(T::VoterList::contains(&stash));
847
848 whitelist_account!(controller);
849
850 #[extrinsic_call]
851 _(RawOrigin::Signed(controller), stash.clone(), 0);
852
853 assert!(!Bonded::<T>::contains_key(&stash));
854 assert!(!T::VoterList::contains(&stash));
855
856 Ok(())
857 }
858
859 #[benchmark]
860 fn set_staking_configs_all_set() {
861 #[extrinsic_call]
862 set_staking_configs(
863 RawOrigin::Root,
864 ConfigOp::Set(BalanceOf::<T>::max_value()),
865 ConfigOp::Set(BalanceOf::<T>::max_value()),
866 ConfigOp::Set(u32::MAX),
867 ConfigOp::Set(u32::MAX),
868 ConfigOp::Set(Percent::max_value()),
869 ConfigOp::Set(Perbill::max_value()),
870 ConfigOp::Set(Percent::max_value()),
871 ConfigOp::Set(false),
872 ConfigOp::Set(10),
873 );
874
875 assert_eq!(MinNominatorBond::<T>::get(), BalanceOf::<T>::max_value());
876 assert_eq!(MinValidatorBond::<T>::get(), BalanceOf::<T>::max_value());
877 assert_eq!(MaxNominatorsCount::<T>::get(), Some(u32::MAX));
878 assert_eq!(MaxValidatorsCount::<T>::get(), Some(u32::MAX));
879 assert_eq!(ChillThreshold::<T>::get(), Some(Percent::from_percent(100)));
880 assert_eq!(MinCommission::<T>::get(), Perbill::from_percent(100));
881 assert_eq!(MaxStakedRewards::<T>::get(), Some(Percent::from_percent(100)));
882 assert_eq!(AreNominatorsSlashable::<T>::get(), false);
883 assert_eq!(ChillInactiveThreshold::<T>::get(), 10);
884 }
885
886 #[benchmark]
887 fn set_staking_configs_all_remove() {
888 #[extrinsic_call]
889 set_staking_configs(
890 RawOrigin::Root,
891 ConfigOp::Remove,
892 ConfigOp::Remove,
893 ConfigOp::Remove,
894 ConfigOp::Remove,
895 ConfigOp::Remove,
896 ConfigOp::Remove,
897 ConfigOp::Remove,
898 ConfigOp::Remove,
899 ConfigOp::Remove,
900 );
901
902 assert!(!MinNominatorBond::<T>::exists());
903 assert!(!MinValidatorBond::<T>::exists());
904 assert!(!MaxNominatorsCount::<T>::exists());
905 assert!(!MaxValidatorsCount::<T>::exists());
906 assert!(!ChillThreshold::<T>::exists());
907 assert!(!MinCommission::<T>::exists());
908 assert!(!MaxStakedRewards::<T>::exists());
909 assert!(!AreNominatorsSlashable::<T>::exists());
910 }
911
912 #[benchmark]
913 fn chill_other() -> Result<(), BenchmarkError> {
914 clear_validators_and_nominators::<T>();
916
917 let origin_weight = Staking::<T>::min_nominator_bond();
918
919 let scenario = ListScenario::<T>::new(origin_weight, true)?;
922 let stash = scenario.origin_stash1;
923 assert!(T::VoterList::contains(&stash));
924
925 Staking::<T>::set_staking_configs(
926 RawOrigin::Root.into(),
927 ConfigOp::Set(BalanceOf::<T>::max_value()),
928 ConfigOp::Set(BalanceOf::<T>::max_value()),
929 ConfigOp::Set(0),
930 ConfigOp::Set(0),
931 ConfigOp::Set(Percent::from_percent(0)),
932 ConfigOp::Set(Zero::zero()),
933 ConfigOp::Noop,
934 ConfigOp::Noop,
935 ConfigOp::Noop,
936 )?;
937
938 let caller = whitelisted_caller();
939
940 #[extrinsic_call]
941 _(RawOrigin::Signed(caller), stash.clone());
942
943 assert!(!T::VoterList::contains(&stash));
944
945 Ok(())
946 }
947
948 #[benchmark]
949 fn force_apply_min_commission() -> Result<(), BenchmarkError> {
950 clear_validators_and_nominators::<T>();
952
953 let (stash, controller) = create_stash_controller::<T>(1, 100, RewardDestination::Staked)?;
956 let validator_prefs =
957 ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() };
958 Staking::<T>::validate(RawOrigin::Signed(controller).into(), validator_prefs)?;
959
960 assert_eq!(
962 Validators::<T>::get(&stash),
963 ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }
964 );
965
966 MinCommission::<T>::set(Perbill::from_percent(75));
968 let caller = whitelisted_caller();
969
970 #[extrinsic_call]
971 _(RawOrigin::Signed(caller), stash.clone());
972
973 assert_eq!(
975 Validators::<T>::get(&stash),
976 ValidatorPrefs { commission: Perbill::from_percent(75), ..Default::default() }
977 );
978
979 Ok(())
980 }
981
982 #[benchmark]
983 fn set_min_commission() {
984 let min_commission = Perbill::max_value();
985
986 #[extrinsic_call]
987 _(RawOrigin::Root, min_commission);
988
989 assert_eq!(MinCommission::<T>::get(), Perbill::from_percent(100));
990 }
991
992 #[benchmark]
993 fn set_max_commission() {
994 let max_commission = Perbill::max_value();
995
996 #[extrinsic_call]
997 _(RawOrigin::Root, max_commission);
998
999 assert_eq!(MaxCommission::<T>::get(), Perbill::from_percent(100));
1000 }
1001
1002 #[benchmark]
1003 fn set_validator_self_stake_incentive_config() {
1004 #[extrinsic_call]
1005 _(
1006 RawOrigin::Root,
1007 ConfigOp::Set(30_000u32.into()),
1008 ConfigOp::Set(100_000u32.into()),
1009 ConfigOp::Set(Perbill::from_percent(50)),
1010 );
1011
1012 assert_eq!(OptimumSelfStake::<T>::get(), 30_000u32.into());
1013 assert_eq!(HardCapSelfStake::<T>::get(), 100_000u32.into());
1014 assert_eq!(SelfStakeSlopeFactor::<T>::get(), Perbill::from_percent(50));
1015 }
1016
1017 #[benchmark]
1018 fn restore_ledger() -> Result<(), BenchmarkError> {
1019 let (stash, controller) = create_stash_controller::<T>(0, 100, RewardDestination::Staked)?;
1020 Ledger::<T>::remove(controller);
1022
1023 #[extrinsic_call]
1024 _(RawOrigin::Root, stash.clone(), None, None, None);
1025
1026 assert_eq!(Staking::<T>::inspect_bond_state(&stash), Ok(LedgerIntegrityState::Ok));
1027
1028 Ok(())
1029 }
1030
1031 #[benchmark]
1032 fn migrate_currency() -> Result<(), BenchmarkError> {
1033 let (stash, _ctrl) =
1034 create_stash_controller::<T>(USER_SEED, 100, RewardDestination::Staked)?;
1035 let stake = asset::staked::<T>(&stash);
1036 migrate_to_old_currency::<T>(stash.clone());
1037 assert!(asset::staked::<T>(&stash).is_zero());
1039 whitelist_account!(stash);
1040
1041 #[extrinsic_call]
1042 _(RawOrigin::Signed(stash.clone()), stash.clone());
1043
1044 assert_eq!(asset::staked::<T>(&stash), stake);
1045 Ok(())
1046 }
1047
1048 #[benchmark]
1049 fn apply_slash(
1050 n: Linear<0, { T::MaxExposurePageSize::get() as u32 }>,
1051 ) -> Result<(), BenchmarkError> {
1052 let era = EraIndex::one();
1053 ActiveEra::<T>::put(ActiveEraInfo { index: era, start: None });
1054 let (validator, nominators, _current_era) = create_validator_with_nominators::<T>(
1055 T::MaxExposurePageSize::get() as u32,
1056 T::MaxExposurePageSize::get() as u32,
1057 false,
1058 true,
1059 RewardDestination::Staked,
1060 )?;
1061 let slash_fraction = Perbill::from_percent(10);
1062 let page_index = 0;
1063 let slashed_balance = BalanceOf::<T>::from(10u32);
1064
1065 let slash_key = (validator.clone(), slash_fraction, page_index);
1066 let slashed_nominators = nominators
1068 .iter()
1069 .take(n as usize)
1070 .map(|(nom, _)| (nom.clone(), slashed_balance))
1071 .collect::<Vec<_>>();
1072
1073 let unapplied_slash = UnappliedSlash::<T> {
1074 validator: validator.clone(),
1075 own: slashed_balance,
1076 others: WeakBoundedVec::force_from(slashed_nominators, None),
1077 reporter: Default::default(),
1078 payout: Zero::zero(),
1079 };
1080
1081 UnappliedSlashes::<T>::insert(era, slash_key.clone(), unapplied_slash);
1083
1084 #[extrinsic_call]
1085 _(RawOrigin::Signed(validator.clone()), era, slash_key.clone());
1086
1087 assert!(UnappliedSlashes::<T>::get(era, &slash_key).is_none());
1089
1090 Ok(())
1091 }
1092
1093 #[benchmark]
1094 fn process_offence_queue() -> Result<(), BenchmarkError> {
1095 #[cfg(test)]
1098 crate::mock::SlashDeferDuration::set(77);
1099
1100 let all_validators = crate::testing_utils::create_validators_with_nominators_for_era::<T>(
1102 ValidatorCount::<T>::get().max(1),
1104 2 * T::MaxExposurePageSize::get(),
1106 16,
1107 false,
1108 Some(1),
1109 )?;
1110 let offender =
1111 T::Lookup::lookup(all_validators.first().cloned().expect("must exist")).unwrap();
1112
1113 let _new_validators = Rotator::<T>::legacy_insta_plan_era();
1115 Rotator::<T>::start_era(
1117 crate::ActiveEraInfo { index: Rotator::<T>::planned_era() - 1, start: Some(1) },
1118 42, 2, );
1121
1122 let offender_exposure =
1124 Eras::<T>::get_full_exposure(Rotator::<T>::planned_era(), &offender);
1125 ensure!(
1126 offender_exposure.others.len() as u32 >= T::MaxExposurePageSize::get(),
1127 "exposure not created"
1128 );
1129
1130 let slash_session = 42;
1132 let offences = vec![rc_client::Offence {
1133 offender: offender.clone(),
1134 reporters: Default::default(),
1135 slash_fraction: Perbill::from_percent(50),
1136 }];
1137 <crate::Pallet<T> as rc_client::AHStakingInterface>::on_new_offences(
1138 slash_session,
1139 offences,
1140 );
1141
1142 ensure!(
1144 ValidatorSlashInEra::<T>::contains_key(Rotator::<T>::active_era(), offender),
1145 "offence not submitted"
1146 );
1147 ensure!(
1148 OffenceQueueEras::<T>::get().unwrap_or_default() == vec![Rotator::<T>::active_era()],
1149 "offence should be queued"
1150 );
1151
1152 #[block]
1153 {
1154 slashing::process_offence::<T>();
1155 }
1156
1157 ensure!(OffenceQueueEras::<T>::get().is_none(), "offence should not be queued");
1158
1159 Ok(())
1160 }
1161
1162 #[benchmark]
1163 fn rc_on_offence(
1164 v: Linear<2, { T::MaxValidatorSet::get() / 2 }>,
1165 ) -> Result<(), BenchmarkError> {
1166 let initial_era = Rotator::<T>::planned_era();
1167 let _ = crate::testing_utils::create_validators_with_nominators_for_era::<T>(
1168 2 * v,
1169 1000,
1171 16,
1172 false,
1173 None,
1174 )?;
1175
1176 let new_validators = Rotator::<T>::legacy_insta_plan_era();
1178 ensure!(Rotator::<T>::planned_era() == initial_era + 1, "era should be incremented");
1179 Rotator::<T>::start_era(
1181 crate::ActiveEraInfo { index: initial_era, start: Some(1) },
1182 42, 2, );
1185
1186 ensure!(Rotator::<T>::active_era_start_session_index() == 42, "BondedEra not set");
1188
1189 let to_slash_count = new_validators.len() / 2;
1191 let to_slash = new_validators.into_iter().take(to_slash_count).collect::<Vec<_>>();
1192 let one_slashed = to_slash.first().cloned().unwrap();
1193 let offences = to_slash
1194 .into_iter()
1195 .map(|offender| rc_client::Offence {
1196 offender,
1197 reporters: Default::default(),
1198 slash_fraction: Perbill::from_percent(50),
1199 })
1200 .collect::<Vec<_>>();
1201 let slash_session = 42;
1202
1203 ensure!(
1205 !ValidatorSlashInEra::<T>::contains_key(initial_era + 1, &one_slashed),
1206 "offence submitted???"
1207 );
1208
1209 #[block]
1210 {
1211 <crate::Pallet<T> as rc_client::AHStakingInterface>::on_new_offences(
1212 slash_session,
1213 offences,
1214 );
1215 }
1216
1217 ensure!(
1219 ValidatorSlashInEra::<T>::contains_key(initial_era + 1, one_slashed),
1220 "offence not submitted"
1221 );
1222
1223 Ok(())
1224 }
1225
1226 #[benchmark]
1227 fn rc_on_session_report(
1228 v: Linear<1, { T::MaxValidatorSet::get() }>,
1229 ) -> Result<(), BenchmarkError> {
1230 let initial_planned_era = Rotator::<T>::planned_era();
1231 let initial_active_era = Rotator::<T>::active_era();
1232
1233 crate::testing_utils::create_validators_with_nominators_for_era::<T>(
1236 10, 50, 2, false, None,
1237 )?;
1238
1239 let _new_validators = Rotator::<T>::legacy_insta_plan_era();
1241 ensure!(
1242 CurrentEra::<T>::get().unwrap() == initial_planned_era + 1,
1243 "era should be incremented"
1244 );
1245
1246 let validator_points = (0..v)
1250 .map(|i| (account::<T::AccountId>("random", i, SEED), i))
1251 .collect::<Vec<_>>();
1252
1253 let active_era = Rotator::<T>::active_era();
1257 for (who, _) in &validator_points {
1258 ErasValidatorIncentiveWeight::<T>::insert(
1259 active_era,
1260 who,
1261 BalanceOf::<T>::from(100u64),
1262 );
1263 }
1264
1265 let activation_timestamp = Some((1u64, initial_planned_era + 1));
1266 let report = rc_client::SessionReport {
1267 end_index: 42,
1268 leftover: false,
1269 validator_points,
1270 activation_timestamp,
1271 };
1272
1273 #[block]
1274 {
1275 <crate::Pallet<T> as rc_client::AHStakingInterface>::on_relay_session_report(report);
1276 }
1277
1278 ensure!(Rotator::<T>::active_era() == initial_active_era + 1, "active era not bumped");
1279 Ok(())
1280 }
1281
1282 fn setup_era_for_pruning<T: Config>(v: u32) -> EraIndex {
1284 let validators = v;
1285 let era = 7;
1286
1287 let history_depth = T::HistoryDepth::get();
1290 let active_era = era + history_depth + 1;
1291 crate::ActiveEra::<T>::put(crate::ActiveEraInfo { index: active_era, start: Some(0) });
1292
1293 let max_total_nominators_per_validator =
1294 <T::ElectionProvider as ElectionProvider>::MaxBackersPerWinnerFinal::get();
1295 let exposed_nominators_per_validator = max_total_nominators_per_validator / validators;
1296
1297 let pages: WeakBoundedVec<_, _> = (0..crate::ClaimedRewardsBound::<T>::get())
1298 .collect::<Vec<_>>()
1299 .try_into()
1300 .unwrap();
1301
1302 let slashed_validators = validators / 3;
1304
1305 let mut reward_points_individual = BTreeMap::new();
1306 let mut total_incentive_weight = BalanceOf::<T>::zero();
1307
1308 for i in 0..validators {
1309 let validator = account::<T::AccountId>("validator", i, SEED);
1310
1311 ErasValidatorPrefs::<T>::insert(era, validator.clone(), ValidatorPrefs::default());
1313
1314 ClaimedRewards::<T>::insert(era, validator.clone(), pages.clone());
1316
1317 let exposure = sp_staking::Exposure::<T::AccountId, BalanceOf<T>> {
1319 own: T::Currency::minimum_balance(),
1320 total: T::Currency::minimum_balance() *
1321 (exposed_nominators_per_validator + 1).into(),
1322 others: (0..exposed_nominators_per_validator)
1323 .map(|n| {
1324 let nominator = account::<T::AccountId>("nominator", n, SEED);
1325 IndividualExposure { who: nominator, value: T::Currency::minimum_balance() }
1326 })
1327 .collect::<Vec<_>>(),
1328 };
1329 Eras::<T>::upsert_exposure(era, &validator, exposure);
1330
1331 reward_points_individual.insert(validator.clone(), 7u32);
1333
1334 if i < slashed_validators {
1336 crate::ValidatorSlashInEra::<T>::insert(
1337 era,
1338 validator.clone(),
1339 (Perbill::from_percent(10), BalanceOf::<T>::max_value() / 10u32.into()),
1340 );
1341 }
1342
1343 let incentive_weight = BalanceOf::<T>::from(100u64);
1345 ErasValidatorIncentiveWeight::<T>::insert(era, validator, incentive_weight);
1346 total_incentive_weight += incentive_weight;
1347 }
1348
1349 ErasValidatorReward::<T>::insert(era, BalanceOf::<T>::max_value());
1351 ErasRewardPoints::<T>::insert(
1352 era,
1353 crate::EraRewardPoints::<T> {
1354 total: 77777,
1355 individual: reward_points_individual.try_into().unwrap(),
1356 },
1357 );
1358 ErasTotalStake::<T>::insert(era, BalanceOf::<T>::max_value());
1359 ErasNominatorsSlashable::<T>::insert(era, true);
1360 ErasSumValidatorIncentiveWeight::<T>::insert(era, total_incentive_weight);
1361 ErasSumWeightedPoints::<T>::insert(
1362 era,
1363 total_incentive_weight.saturating_mul(BalanceOf::<T>::from(7u32)),
1364 );
1365 ErasValidatorIncentiveBudget::<T>::insert(era, BalanceOf::<T>::from(1_000_000u64));
1366
1367 era
1368 }
1369
1370 fn validate_pruning_weight<T: Config>(
1372 result: &frame_support::dispatch::DispatchResultWithPostInfo,
1373 step_name: &str,
1374 validator_count: u32,
1375 ) {
1376 assert!(
1377 result.is_ok(),
1378 "Benchmark {} should succeed with v={}",
1379 step_name,
1380 validator_count
1381 );
1382
1383 let post_info = result.unwrap();
1384 let actual_ref_time = post_info
1385 .actual_weight
1386 .expect(&format!(
1387 "Should report actual weight for {} with v={}",
1388 step_name, validator_count
1389 ))
1390 .ref_time();
1391
1392 assert!(
1393 actual_ref_time > 0,
1394 "Should report non-zero ref_time for {} with v={}",
1395 step_name,
1396 validator_count
1397 );
1398 }
1400
1401 #[benchmark(pov_mode = Measured)]
1403 fn prune_era_stakers_paged(
1404 v: Linear<1, { T::MaxValidatorSet::get() }>,
1405 ) -> Result<(), BenchmarkError> {
1406 let era = setup_era_for_pruning::<T>(v);
1407 EraPruningState::<T>::insert(era, PruningStep::ErasStakersPaged);
1408
1409 let caller: T::AccountId = whitelisted_caller();
1410
1411 let result;
1412 #[block]
1413 {
1414 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1415 }
1416
1417 validate_pruning_weight::<T>(&result, "ErasStakersPaged", v);
1418
1419 Ok(())
1420 }
1421
1422 #[benchmark(pov_mode = Measured)]
1424 fn prune_era_stakers_overview(
1425 v: Linear<1, { T::MaxValidatorSet::get() }>,
1426 ) -> Result<(), BenchmarkError> {
1427 let era = setup_era_for_pruning::<T>(v);
1428 EraPruningState::<T>::insert(era, PruningStep::ErasStakersOverview);
1429
1430 let caller: T::AccountId = whitelisted_caller();
1431
1432 let result;
1433 #[block]
1434 {
1435 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1436 }
1437
1438 validate_pruning_weight::<T>(&result, "ErasStakersOverview", v);
1439
1440 Ok(())
1441 }
1442
1443 #[benchmark(pov_mode = Measured)]
1445 fn prune_era_validator_prefs(
1446 v: Linear<1, { T::MaxValidatorSet::get() }>,
1447 ) -> Result<(), BenchmarkError> {
1448 let era = setup_era_for_pruning::<T>(v);
1449 EraPruningState::<T>::insert(era, PruningStep::ErasValidatorPrefs);
1450
1451 let caller: T::AccountId = whitelisted_caller();
1452
1453 let result;
1454 #[block]
1455 {
1456 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1457 }
1458
1459 validate_pruning_weight::<T>(&result, "ErasValidatorPrefs", v);
1460
1461 Ok(())
1462 }
1463
1464 #[benchmark(pov_mode = Measured)]
1466 fn prune_era_claimed_rewards(
1467 v: Linear<1, { T::MaxValidatorSet::get() }>,
1468 ) -> Result<(), BenchmarkError> {
1469 let era = setup_era_for_pruning::<T>(v);
1470 EraPruningState::<T>::insert(era, PruningStep::ClaimedRewards);
1471
1472 let caller: T::AccountId = whitelisted_caller();
1473
1474 let result;
1475 #[block]
1476 {
1477 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1478 }
1479
1480 validate_pruning_weight::<T>(&result, "ClaimedRewards", v);
1481
1482 Ok(())
1483 }
1484
1485 #[benchmark(pov_mode = Measured)]
1487 fn prune_era_validator_reward() -> Result<(), BenchmarkError> {
1488 let era = setup_era_for_pruning::<T>(1);
1489 EraPruningState::<T>::insert(era, PruningStep::ErasValidatorReward);
1490
1491 let caller: T::AccountId = whitelisted_caller();
1492
1493 let result;
1494 #[block]
1495 {
1496 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1497 }
1498
1499 validate_pruning_weight::<T>(&result, "ErasValidatorReward", 1);
1500
1501 Ok(())
1502 }
1503
1504 #[benchmark(pov_mode = Measured)]
1506 fn prune_era_reward_points() -> Result<(), BenchmarkError> {
1507 let era = setup_era_for_pruning::<T>(1);
1508 EraPruningState::<T>::insert(era, PruningStep::ErasRewardPoints);
1509
1510 let caller: T::AccountId = whitelisted_caller();
1511
1512 let result;
1513 #[block]
1514 {
1515 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1516 }
1517
1518 validate_pruning_weight::<T>(&result, "ErasRewardPoints", 1);
1519
1520 Ok(())
1521 }
1522
1523 #[benchmark(pov_mode = Measured)]
1525 fn prune_era_single_entry_cleanups() -> Result<(), BenchmarkError> {
1526 let era = setup_era_for_pruning::<T>(1);
1527 EraPruningState::<T>::insert(era, PruningStep::SingleEntryCleanups);
1528
1529 let caller: T::AccountId = whitelisted_caller();
1530
1531 let result;
1532 #[block]
1533 {
1534 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1535 }
1536
1537 validate_pruning_weight::<T>(&result, "SingleEntryCleanups", 1);
1538
1539 Ok(())
1540 }
1541
1542 #[benchmark(pov_mode = Measured)]
1544 fn prune_era_validator_slash_in_era(
1545 v: Linear<1, { T::MaxValidatorSet::get() }>,
1546 ) -> Result<(), BenchmarkError> {
1547 let era = setup_era_for_pruning::<T>(v);
1548 EraPruningState::<T>::insert(era, PruningStep::ValidatorSlashInEra);
1549
1550 let caller: T::AccountId = whitelisted_caller();
1551
1552 let result;
1553 #[block]
1554 {
1555 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1556 }
1557
1558 validate_pruning_weight::<T>(&result, "ValidatorSlashInEra", v);
1559
1560 Ok(())
1561 }
1562
1563 #[benchmark(pov_mode = Measured)]
1564 fn prune_era_validator_incentive_weight(
1565 v: Linear<1, { T::MaxValidatorSet::get() }>,
1566 ) -> Result<(), BenchmarkError> {
1567 let era = setup_era_for_pruning::<T>(v);
1568 EraPruningState::<T>::insert(era, PruningStep::ErasValidatorIncentiveWeight);
1569
1570 let caller: T::AccountId = whitelisted_caller();
1571
1572 let result;
1573 #[block]
1574 {
1575 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1576 }
1577
1578 validate_pruning_weight::<T>(&result, "ErasValidatorIncentiveWeight", v);
1579
1580 Ok(())
1581 }
1582
1583 #[benchmark(pov_mode = Measured)]
1584 fn chill_inactive(
1585 l: Linear<2, { ChillInactiveThreshold::<T>::get() }>,
1586 ) -> Result<(), BenchmarkError> {
1587 let (stash, _, _) =
1588 create_validator_with_nominators::<T>(0, 0, false, true, RewardDestination::Staked)?;
1589 assert!(T::VoterList::contains(&stash));
1590
1591 Staking::<T>::set_staking_configs(
1592 RawOrigin::Root.into(),
1593 ConfigOp::Set(BalanceOf::<T>::max_value()),
1594 ConfigOp::Set(BalanceOf::<T>::max_value()),
1595 ConfigOp::Set(0),
1596 ConfigOp::Set(0),
1597 ConfigOp::Set(Percent::from_percent(0)),
1598 ConfigOp::Set(Zero::zero()),
1599 ConfigOp::Noop,
1600 ConfigOp::Noop,
1601 ConfigOp::Set(l),
1602 )?;
1603
1604 let caller = whitelisted_caller();
1605
1606 set_active_era::<T>(l);
1610
1611 let proof = (0..l)
1613 .inspect(|&era| {
1614 ErasRewardPoints::<T>::insert(
1615 era,
1616 EraRewardPoints { total: 0, individual: BoundedBTreeMap::new() },
1617 );
1618 Eras::<T>::upsert_exposure(era, &stash, Exposure::default());
1619 })
1620 .collect::<Vec<_>>();
1621 let proof = BoundedVec::truncate_from(proof);
1622
1623 assert!(Validators::<T>::contains_key(&stash));
1624
1625 #[extrinsic_call]
1626 _(RawOrigin::Signed(caller), stash.clone(), proof);
1627
1628 assert!(!Validators::<T>::contains_key(&stash));
1629
1630 Ok(())
1631 }
1632
1633 impl_benchmark_test_suite!(
1634 Staking,
1635 crate::mock::ExtBuilder::default().has_stakers(true),
1636 crate::mock::Test,
1637 exec_name = build_and_execute
1638 );
1639}
1640
1641#[cfg(test)]
1642mod tests {
1643 use super::*;
1644 use crate::mock::{ExtBuilder, RuntimeOrigin, Staking, Test};
1645 use frame_support::assert_ok;
1646
1647 #[test]
1648 fn create_validators_with_nominators_for_era_works() {
1649 ExtBuilder::default().build_and_execute(|| {
1650 let v = 10;
1651 let n = 100;
1652
1653 create_validators_with_nominators_for_era::<Test>(
1654 v,
1655 n,
1656 MaxNominationsOf::<Test>::get() as usize,
1657 false,
1658 None,
1659 )
1660 .unwrap();
1661
1662 let count_validators = Validators::<Test>::iter().count();
1663 let count_nominators = Nominators::<Test>::iter().count();
1664
1665 assert_eq!(count_validators, Validators::<Test>::count() as usize);
1666 assert_eq!(count_nominators, Nominators::<Test>::count() as usize);
1667
1668 assert_eq!(count_validators, v as usize);
1669 assert_eq!(count_nominators, n as usize);
1670 });
1671 }
1672
1673 #[test]
1674 fn create_validator_with_nominators_works() {
1675 ExtBuilder::default().build_and_execute(|| {
1676 let n = 10;
1677
1678 let (validator_stash, nominators, current_era) =
1679 create_validator_with_nominators::<Test>(
1680 n,
1681 <<Test as Config>::MaxExposurePageSize as Get<_>>::get(),
1682 false,
1683 false,
1684 RewardDestination::Staked,
1685 )
1686 .unwrap();
1687
1688 assert_eq!(nominators.len() as u32, n);
1689
1690 let original_stakeable_balance = asset::stakeable_balance::<Test>(&validator_stash);
1691 assert_ok!(Staking::payout_stakers_by_page(
1692 RuntimeOrigin::signed(1337),
1693 validator_stash,
1694 current_era,
1695 0
1696 ));
1697 let new_stakeable_balance = asset::stakeable_balance::<Test>(&validator_stash);
1698
1699 assert!(original_stakeable_balance < new_stakeable_balance);
1701 });
1702 }
1703}