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
151 Ok((v_stash, nominators, planned_era))
152}
153
154struct ListScenario<T: Config> {
155 origin_stash1: T::AccountId,
157 origin_controller1: T::AccountId,
159 dest_weight: BalanceOf<T>,
160}
161
162impl<T: Config> ListScenario<T> {
163 fn new(origin_weight: BalanceOf<T>, is_increase: bool) -> Result<Self, &'static str> {
178 ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0");
179
180 let i = asset::burn::<T>(asset::total_issuance::<T>());
182 core::mem::forget(i);
183
184 let validator_account = account("random_validator", 0, SEED);
186 let validator_stake = asset::existential_deposit::<T>() * 1000u32.into();
187 asset::set_stakeable_balance::<T>(&validator_account, validator_stake);
188 assert_ok!(Staking::<T>::bond(
189 RawOrigin::Signed(validator_account.clone()).into(),
190 validator_stake / 2u32.into(),
191 RewardDestination::Staked
192 ));
193 assert_ok!(Staking::<T>::validate(
194 RawOrigin::Signed(validator_account.clone()).into(),
195 Default::default()
196 ));
197
198 let (origin_stash1, origin_controller1) = create_stash_controller_with_balance::<T>(
200 USER_SEED + 2,
201 origin_weight,
202 RewardDestination::Staked,
203 )?;
204 Staking::<T>::nominate(
205 RawOrigin::Signed(origin_controller1.clone()).into(),
206 vec![T::Lookup::unlookup(validator_account.clone())],
208 )?;
209
210 let (_origin_stash2, origin_controller2) = create_stash_controller_with_balance::<T>(
211 USER_SEED + 3,
212 origin_weight,
213 RewardDestination::Staked,
214 )?;
215 Staking::<T>::nominate(
216 RawOrigin::Signed(origin_controller2).into(),
217 vec![T::Lookup::unlookup(validator_account.clone())],
218 )?;
219
220 let dest_weight_as_vote =
222 T::VoterList::score_update_worst_case(&origin_stash1, is_increase);
223
224 let total_issuance = asset::total_issuance::<T>();
225
226 let dest_weight =
227 T::CurrencyToVote::to_currency(dest_weight_as_vote as u128, total_issuance);
228
229 let (_dest_stash1, dest_controller1) = create_stash_controller_with_balance::<T>(
231 USER_SEED + 1,
232 dest_weight,
233 RewardDestination::Staked,
234 )?;
235 Staking::<T>::nominate(
236 RawOrigin::Signed(dest_controller1).into(),
237 vec![T::Lookup::unlookup(validator_account)],
238 )?;
239
240 Ok(ListScenario { origin_stash1, origin_controller1, dest_weight })
241 }
242}
243
244const USER_SEED: u32 = 999666;
245
246#[benchmarks]
247mod benchmarks {
248 use super::*;
249 use alloc::format;
250
251 #[benchmark]
252 fn bond() {
253 let stash = create_funded_user::<T>("stash", USER_SEED, 100);
254 let reward_destination = RewardDestination::Staked;
255 let amount = asset::existential_deposit::<T>() * 10u32.into();
256 whitelist_account!(stash);
257
258 #[extrinsic_call]
259 _(RawOrigin::Signed(stash.clone()), amount, reward_destination);
260
261 assert!(Bonded::<T>::contains_key(stash.clone()));
262 assert!(Ledger::<T>::contains_key(stash));
263 }
264
265 #[benchmark]
266 fn bond_extra() -> Result<(), BenchmarkError> {
267 clear_validators_and_nominators::<T>();
269
270 let origin_weight = Staking::<T>::min_nominator_bond();
271
272 let scenario = ListScenario::<T>::new(origin_weight, true)?;
276
277 let max_additional = scenario.dest_weight - origin_weight;
278
279 let stash = scenario.origin_stash1.clone();
280 let controller = scenario.origin_controller1;
281 let original_bonded: BalanceOf<T> = Ledger::<T>::get(&controller)
282 .map(|l| l.active)
283 .ok_or("ledger not created after")?;
284
285 let _ = asset::mint_into_existing::<T>(
286 &stash,
287 max_additional + asset::existential_deposit::<T>(),
288 )
289 .unwrap();
290
291 whitelist_account!(stash);
292
293 #[extrinsic_call]
294 _(RawOrigin::Signed(stash), max_additional);
295
296 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
297 let new_bonded: BalanceOf<T> = ledger.active;
298 assert!(original_bonded < new_bonded);
299
300 Ok(())
301 }
302
303 #[benchmark]
304 fn unbond() -> Result<(), BenchmarkError> {
305 clear_validators_and_nominators::<T>();
307
308 let origin_weight = BalanceOf::<T>::try_from(952_994_955_240_703u128)
311 .map_err(|_| "balance expected to be a u128")
312 .unwrap();
313 let scenario = ListScenario::<T>::new(origin_weight, false)?;
314
315 let controller = scenario.origin_controller1.clone();
316 let amount = origin_weight - scenario.dest_weight;
317 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created before")?;
318 let original_bonded: BalanceOf<T> = ledger.active;
319
320 whitelist_account!(controller);
321
322 #[extrinsic_call]
323 _(RawOrigin::Signed(controller.clone()), amount);
324
325 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
326 let new_bonded: BalanceOf<T> = ledger.active;
327 assert!(original_bonded > new_bonded);
328
329 Ok(())
330 }
331
332 #[benchmark]
333 fn withdraw_unbonded_update() -> Result<(), BenchmarkError> {
335 let (_, controller) = create_stash_controller::<T>(0, 100, RewardDestination::Staked)?;
336 let amount = asset::existential_deposit::<T>() * 5u32.into(); Staking::<T>::unbond(RawOrigin::Signed(controller.clone()).into(), amount)?;
338 set_active_era::<T>(EraIndex::max_value());
339 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created before")?;
340 let original_total: BalanceOf<T> = ledger.total;
341 whitelist_account!(controller);
342
343 #[extrinsic_call]
344 withdraw_unbonded(RawOrigin::Signed(controller.clone()), 0);
345
346 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
347 let new_total: BalanceOf<T> = ledger.total;
348 assert!(original_total > new_total);
349
350 Ok(())
351 }
352
353 #[benchmark]
354 fn withdraw_unbonded_kill() -> Result<(), BenchmarkError> {
356 clear_validators_and_nominators::<T>();
358
359 let origin_weight = Staking::<T>::min_nominator_bond();
360
361 let scenario = ListScenario::<T>::new(origin_weight, true)?;
364 let controller = scenario.origin_controller1.clone();
365 let stash = scenario.origin_stash1;
366 assert!(T::VoterList::contains(&stash));
367
368 let ed = asset::existential_deposit::<T>();
369 let mut ledger = Ledger::<T>::get(&controller).unwrap();
370 ledger.active = ed - One::one();
371 Ledger::<T>::insert(&controller, ledger);
372 set_active_era::<T>(EraIndex::max_value());
373
374 whitelist_account!(controller);
375
376 #[extrinsic_call]
377 withdraw_unbonded(RawOrigin::Signed(controller.clone()), 0);
378
379 assert!(!Ledger::<T>::contains_key(controller));
380 assert!(!T::VoterList::contains(&stash));
381
382 Ok(())
383 }
384
385 #[benchmark]
386 fn validate() -> Result<(), BenchmarkError> {
387 let (stash, controller) = create_stash_controller::<T>(
388 MaxNominationsOf::<T>::get() - 1,
389 100,
390 RewardDestination::Staked,
391 )?;
392 assert!(!T::VoterList::contains(&stash));
394
395 let prefs = ValidatorPrefs::default();
396 whitelist_account!(controller);
397
398 #[extrinsic_call]
399 _(RawOrigin::Signed(controller), prefs);
400
401 assert!(Validators::<T>::contains_key(&stash));
402 assert!(T::VoterList::contains(&stash));
403
404 Ok(())
405 }
406
407 #[benchmark]
408 fn kick(
409 k: Linear<1, 128>,
414 ) -> Result<(), BenchmarkError> {
415 let rest_of_validators =
418 create_validators_with_seed::<T>(MaxNominationsOf::<T>::get() - 1, 100, 415)?;
419
420 let (stash, controller) = create_stash_controller::<T>(
422 MaxNominationsOf::<T>::get() - 1,
423 100,
424 RewardDestination::Staked,
425 )?;
426 let stash_lookup = T::Lookup::unlookup(stash.clone());
427
428 Staking::<T>::validate(RawOrigin::Signed(controller.clone()).into(), Default::default())?;
430
431 let mut nominator_stashes = Vec::with_capacity(k as usize);
434 for i in 0..k {
435 let (n_stash, n_controller) = create_stash_controller::<T>(
437 MaxNominationsOf::<T>::get() + i,
438 100,
439 RewardDestination::Staked,
440 )?;
441
442 let mut nominations = rest_of_validators.clone();
444 nominations.insert(i as usize % (nominations.len() + 1), stash_lookup.clone());
447 Staking::<T>::nominate(RawOrigin::Signed(n_controller.clone()).into(), nominations)?;
449
450 nominator_stashes.push(n_stash);
451 }
452
453 for n in nominator_stashes.iter() {
455 assert!(Nominators::<T>::get(n).unwrap().targets.contains(&stash));
456 }
457
458 let kicks = nominator_stashes
460 .iter()
461 .map(|n| T::Lookup::unlookup(n.clone()))
462 .collect::<Vec<_>>();
463
464 whitelist_account!(controller);
465
466 #[extrinsic_call]
467 _(RawOrigin::Signed(controller), kicks);
468
469 for n in nominator_stashes.iter() {
471 assert!(!Nominators::<T>::get(n).unwrap().targets.contains(&stash));
472 }
473
474 Ok(())
475 }
476
477 #[benchmark]
478 fn nominate(n: Linear<1, { MaxNominationsOf::<T>::get() }>) -> Result<(), BenchmarkError> {
480 clear_validators_and_nominators::<T>();
482
483 let origin_weight = Staking::<T>::min_nominator_bond();
484
485 ListScenario::<T>::new(origin_weight, true)?;
488 let (stash, controller) = create_stash_controller_with_balance::<T>(
489 SEED + MaxNominationsOf::<T>::get() + 1, origin_weight,
492 RewardDestination::Staked,
493 )
494 .unwrap();
495
496 assert!(!Nominators::<T>::contains_key(&stash));
497 assert!(!T::VoterList::contains(&stash));
498
499 let validators = create_validators::<T>(n, 100).unwrap();
500 whitelist_account!(controller);
501
502 #[extrinsic_call]
503 _(RawOrigin::Signed(controller), validators);
504
505 assert!(Nominators::<T>::contains_key(&stash));
506 assert!(T::VoterList::contains(&stash));
507
508 Ok(())
509 }
510
511 #[benchmark]
512 fn chill() -> Result<(), BenchmarkError> {
513 clear_validators_and_nominators::<T>();
515
516 let origin_weight = Staking::<T>::min_nominator_bond();
517
518 let scenario = ListScenario::<T>::new(origin_weight, true)?;
521 let controller = scenario.origin_controller1.clone();
522 let stash = scenario.origin_stash1;
523 assert!(T::VoterList::contains(&stash));
524
525 whitelist_account!(controller);
526
527 #[extrinsic_call]
528 _(RawOrigin::Signed(controller));
529
530 assert!(!T::VoterList::contains(&stash));
531
532 Ok(())
533 }
534
535 #[benchmark]
536 fn set_payee() -> Result<(), BenchmarkError> {
537 let (stash, controller) =
538 create_stash_controller::<T>(USER_SEED, 100, RewardDestination::Staked)?;
539 assert_eq!(Payee::<T>::get(&stash), Some(RewardDestination::Staked));
540 whitelist_account!(controller);
541
542 #[extrinsic_call]
543 _(RawOrigin::Signed(controller.clone()), RewardDestination::Account(controller.clone()));
544
545 assert_eq!(Payee::<T>::get(&stash), Some(RewardDestination::Account(controller)));
546
547 Ok(())
548 }
549
550 #[benchmark]
551 fn update_payee() -> Result<(), BenchmarkError> {
552 let (stash, controller) =
553 create_stash_controller::<T>(USER_SEED, 100, RewardDestination::Staked)?;
554 Payee::<T>::insert(&stash, {
555 #[allow(deprecated)]
556 RewardDestination::Controller
557 });
558 whitelist_account!(controller);
559
560 #[extrinsic_call]
561 _(RawOrigin::Signed(controller.clone()), controller.clone());
562
563 assert_eq!(Payee::<T>::get(&stash), Some(RewardDestination::Account(controller)));
564
565 Ok(())
566 }
567
568 #[benchmark]
569 fn set_controller() -> Result<(), BenchmarkError> {
570 let (stash, ctlr) =
571 create_unique_stash_controller::<T>(9000, 100, RewardDestination::Staked, false)?;
572 assert!(!Ledger::<T>::contains_key(&stash));
574 assert!(Ledger::<T>::contains_key(&ctlr));
575 assert_eq!(Bonded::<T>::get(&stash), Some(ctlr.clone()));
576
577 whitelist_account!(stash);
578
579 #[extrinsic_call]
580 _(RawOrigin::Signed(stash.clone()));
581
582 assert!(Ledger::<T>::contains_key(&stash));
583
584 Ok(())
585 }
586
587 #[benchmark]
588 fn set_validator_count() {
589 let validator_count = T::MaxValidatorSet::get() - 1;
590
591 #[extrinsic_call]
592 _(RawOrigin::Root, validator_count);
593
594 assert_eq!(ValidatorCount::<T>::get(), validator_count);
595 }
596
597 #[benchmark]
598 fn force_no_eras() {
599 #[extrinsic_call]
600 _(RawOrigin::Root);
601
602 assert_eq!(ForceEra::<T>::get(), Forcing::ForceNone);
603 }
604
605 #[benchmark]
606 fn force_new_era() {
607 #[extrinsic_call]
608 _(RawOrigin::Root);
609
610 assert_eq!(ForceEra::<T>::get(), Forcing::ForceNew);
611 }
612
613 #[benchmark]
614 fn force_new_era_always() {
615 #[extrinsic_call]
616 _(RawOrigin::Root);
617
618 assert_eq!(ForceEra::<T>::get(), Forcing::ForceAlways);
619 }
620
621 #[benchmark]
622 fn deprecate_controller_batch(
623 u: Linear<0, { T::MaxControllersInDeprecationBatch::get() }>,
626 ) -> Result<(), BenchmarkError> {
627 let mut controllers: Vec<_> = vec![];
628 let mut stashes: Vec<_> = vec![];
629 for i in 0..u as u32 {
630 let (stash, controller) =
631 create_unique_stash_controller::<T>(i, 100, RewardDestination::Staked, false)?;
632 controllers.push(controller);
633 stashes.push(stash);
634 }
635 let bounded_controllers: BoundedVec<_, T::MaxControllersInDeprecationBatch> =
636 BoundedVec::try_from(controllers.clone()).unwrap();
637
638 #[extrinsic_call]
639 _(RawOrigin::Root, bounded_controllers);
640
641 for i in 0..u as u32 {
642 let stash = &stashes[i as usize];
643 let controller = &controllers[i as usize];
644 assert_eq!(Ledger::<T>::get(controller), None);
646 assert_eq!(Bonded::<T>::get(stash), Some(stash.clone()));
648 assert_eq!(Ledger::<T>::get(stash).unwrap().stash, *stash);
650 }
651
652 Ok(())
653 }
654
655 #[benchmark]
656 fn force_unstake() -> Result<(), BenchmarkError> {
657 clear_validators_and_nominators::<T>();
659
660 let origin_weight = Staking::<T>::min_nominator_bond();
661
662 let scenario = ListScenario::<T>::new(origin_weight, true)?;
665 let controller = scenario.origin_controller1.clone();
666 let stash = scenario.origin_stash1;
667 assert!(T::VoterList::contains(&stash));
668
669 #[extrinsic_call]
670 _(RawOrigin::Root, stash.clone(), 0);
671
672 assert!(!Ledger::<T>::contains_key(&controller));
673 assert!(!T::VoterList::contains(&stash));
674
675 Ok(())
676 }
677
678 #[benchmark]
679 fn cancel_deferred_slash(s: Linear<1, { T::MaxValidatorSet::get() }>) {
680 let era = EraIndex::one();
681
682 let validators: Vec<_> = (0..s)
684 .map(|i| {
685 let validator: T::AccountId = account("validator", i, SEED);
686
687 let slash_key = (validator.clone(), Perbill::from_percent(10), 0);
689 let unapplied_slash = UnappliedSlash::<T> {
690 validator: validator.clone(),
691 own: Zero::zero(),
692 others: WeakBoundedVec::default(),
693 reporter: Default::default(),
694 payout: Zero::zero(),
695 };
696 UnappliedSlashes::<T>::insert(era, slash_key, unapplied_slash);
697
698 validator
699 })
700 .collect();
701
702 let validator_slashes: Vec<_> =
704 validators.into_iter().map(|v| (v, Perbill::from_percent(10))).collect();
705
706 #[extrinsic_call]
707 _(RawOrigin::Root, era, validator_slashes.clone());
708
709 let cancelled_slashes = CancelledSlashes::<T>::get(era);
711 assert_eq!(cancelled_slashes.len(), s as usize);
712 }
713
714 #[benchmark]
715 fn payout_stakers_alive_staked(
716 n: Linear<0, { T::MaxExposurePageSize::get() as u32 }>,
717 ) -> Result<(), BenchmarkError> {
718 let (validator, nominators, current_era) = create_validator_with_nominators::<T>(
719 n,
720 T::MaxExposurePageSize::get() as u32,
721 false,
722 true,
723 RewardDestination::Staked,
724 )?;
725
726 <ErasValidatorPrefs<T>>::insert(
728 current_era,
729 validator.clone(),
730 Validators::<T>::get(&validator),
731 );
732
733 let caller = whitelisted_caller();
734 let balance_before = asset::stakeable_balance::<T>(&validator);
735 let mut nominator_balances_before = Vec::new();
736 for (stash, _) in &nominators {
737 let balance = asset::stakeable_balance::<T>(stash);
738 nominator_balances_before.push(balance);
739 }
740
741 #[extrinsic_call]
742 payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era);
743
744 let balance_after = asset::stakeable_balance::<T>(&validator);
745 ensure!(
746 balance_before < balance_after,
747 "Balance of validator stash should have increased after payout.",
748 );
749 for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter())
750 {
751 let balance_after = asset::stakeable_balance::<T>(stash);
752 ensure!(
753 balance_before < &balance_after,
754 "Balance of nominator stash should have increased after payout.",
755 );
756 }
757
758 Ok(())
759 }
760
761 #[benchmark]
762 fn rebond(l: Linear<1, { T::MaxUnlockingChunks::get() as u32 }>) -> Result<(), BenchmarkError> {
763 clear_validators_and_nominators::<T>();
765
766 let origin_weight = Pallet::<T>::min_nominator_bond()
767 .max(100u32.into());
769
770 let scenario = ListScenario::<T>::new(origin_weight, true)?;
772 let dest_weight = scenario.dest_weight;
773
774 let rebond_amount = dest_weight - origin_weight;
776
777 let value = rebond_amount / l.into();
779 assert_ne!(value, Zero::zero());
781 assert!(value * l.into() + origin_weight > origin_weight);
783 assert!(value * l.into() + origin_weight <= dest_weight);
784 let unlock_chunk = UnlockChunk::<BalanceOf<T>> { value, era: EraIndex::zero() };
785
786 let controller = scenario.origin_controller1;
787 let mut staking_ledger = Ledger::<T>::get(controller.clone()).unwrap();
788
789 for _ in 0..l {
790 staking_ledger.unlocking.try_push(unlock_chunk.clone()).unwrap()
791 }
792 Ledger::<T>::insert(controller.clone(), staking_ledger.clone());
793 let original_bonded: BalanceOf<T> = staking_ledger.active;
794
795 whitelist_account!(controller);
796
797 #[extrinsic_call]
798 _(RawOrigin::Signed(controller.clone()), rebond_amount);
799
800 let ledger = Ledger::<T>::get(&controller).ok_or("ledger not created after")?;
801 let new_bonded: BalanceOf<T> = ledger.active;
802 assert!(original_bonded < new_bonded);
803
804 Ok(())
805 }
806
807 #[benchmark]
808 fn reap_stash() -> Result<(), BenchmarkError> {
809 clear_validators_and_nominators::<T>();
811
812 let origin_weight = Staking::<T>::min_nominator_bond();
813
814 let scenario = ListScenario::<T>::new(origin_weight, true)?;
817 let controller = scenario.origin_controller1.clone();
818 let stash = scenario.origin_stash1;
819
820 let l =
821 StakingLedger::<T>::new(stash.clone(), asset::existential_deposit::<T>() - One::one());
822 Ledger::<T>::insert(&controller, l);
823
824 assert!(Bonded::<T>::contains_key(&stash));
825 assert!(T::VoterList::contains(&stash));
826
827 whitelist_account!(controller);
828
829 #[extrinsic_call]
830 _(RawOrigin::Signed(controller), stash.clone(), 0);
831
832 assert!(!Bonded::<T>::contains_key(&stash));
833 assert!(!T::VoterList::contains(&stash));
834
835 Ok(())
836 }
837
838 #[benchmark]
839 fn set_staking_configs_all_set() {
840 #[extrinsic_call]
841 set_staking_configs(
842 RawOrigin::Root,
843 ConfigOp::Set(BalanceOf::<T>::max_value()),
844 ConfigOp::Set(BalanceOf::<T>::max_value()),
845 ConfigOp::Set(u32::MAX),
846 ConfigOp::Set(u32::MAX),
847 ConfigOp::Set(Percent::max_value()),
848 ConfigOp::Set(Perbill::max_value()),
849 ConfigOp::Set(Percent::max_value()),
850 ConfigOp::Set(false),
851 );
852
853 assert_eq!(MinNominatorBond::<T>::get(), BalanceOf::<T>::max_value());
854 assert_eq!(MinValidatorBond::<T>::get(), BalanceOf::<T>::max_value());
855 assert_eq!(MaxNominatorsCount::<T>::get(), Some(u32::MAX));
856 assert_eq!(MaxValidatorsCount::<T>::get(), Some(u32::MAX));
857 assert_eq!(ChillThreshold::<T>::get(), Some(Percent::from_percent(100)));
858 assert_eq!(MinCommission::<T>::get(), Perbill::from_percent(100));
859 assert_eq!(MaxStakedRewards::<T>::get(), Some(Percent::from_percent(100)));
860 assert_eq!(AreNominatorsSlashable::<T>::get(), false);
861 }
862
863 #[benchmark]
864 fn set_staking_configs_all_remove() {
865 #[extrinsic_call]
866 set_staking_configs(
867 RawOrigin::Root,
868 ConfigOp::Remove,
869 ConfigOp::Remove,
870 ConfigOp::Remove,
871 ConfigOp::Remove,
872 ConfigOp::Remove,
873 ConfigOp::Remove,
874 ConfigOp::Remove,
875 ConfigOp::Remove,
876 );
877
878 assert!(!MinNominatorBond::<T>::exists());
879 assert!(!MinValidatorBond::<T>::exists());
880 assert!(!MaxNominatorsCount::<T>::exists());
881 assert!(!MaxValidatorsCount::<T>::exists());
882 assert!(!ChillThreshold::<T>::exists());
883 assert!(!MinCommission::<T>::exists());
884 assert!(!MaxStakedRewards::<T>::exists());
885 assert!(!AreNominatorsSlashable::<T>::exists());
886 }
887
888 #[benchmark]
889 fn chill_other() -> Result<(), BenchmarkError> {
890 clear_validators_and_nominators::<T>();
892
893 let origin_weight = Staking::<T>::min_nominator_bond();
894
895 let scenario = ListScenario::<T>::new(origin_weight, true)?;
898 let stash = scenario.origin_stash1;
899 assert!(T::VoterList::contains(&stash));
900
901 Staking::<T>::set_staking_configs(
902 RawOrigin::Root.into(),
903 ConfigOp::Set(BalanceOf::<T>::max_value()),
904 ConfigOp::Set(BalanceOf::<T>::max_value()),
905 ConfigOp::Set(0),
906 ConfigOp::Set(0),
907 ConfigOp::Set(Percent::from_percent(0)),
908 ConfigOp::Set(Zero::zero()),
909 ConfigOp::Noop,
910 ConfigOp::Noop,
911 )?;
912
913 let caller = whitelisted_caller();
914
915 #[extrinsic_call]
916 _(RawOrigin::Signed(caller), stash.clone());
917
918 assert!(!T::VoterList::contains(&stash));
919
920 Ok(())
921 }
922
923 #[benchmark]
924 fn force_apply_min_commission() -> Result<(), BenchmarkError> {
925 clear_validators_and_nominators::<T>();
927
928 let (stash, controller) = create_stash_controller::<T>(1, 100, RewardDestination::Staked)?;
931 let validator_prefs =
932 ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() };
933 Staking::<T>::validate(RawOrigin::Signed(controller).into(), validator_prefs)?;
934
935 assert_eq!(
937 Validators::<T>::get(&stash),
938 ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }
939 );
940
941 MinCommission::<T>::set(Perbill::from_percent(75));
943 let caller = whitelisted_caller();
944
945 #[extrinsic_call]
946 _(RawOrigin::Signed(caller), stash.clone());
947
948 assert_eq!(
950 Validators::<T>::get(&stash),
951 ValidatorPrefs { commission: Perbill::from_percent(75), ..Default::default() }
952 );
953
954 Ok(())
955 }
956
957 #[benchmark]
958 fn set_min_commission() {
959 let min_commission = Perbill::max_value();
960
961 #[extrinsic_call]
962 _(RawOrigin::Root, min_commission);
963
964 assert_eq!(MinCommission::<T>::get(), Perbill::from_percent(100));
965 }
966
967 #[benchmark]
968 fn set_max_commission() {
969 let max_commission = Perbill::max_value();
970
971 #[extrinsic_call]
972 _(RawOrigin::Root, max_commission);
973
974 assert_eq!(MaxCommission::<T>::get(), Perbill::from_percent(100));
975 }
976
977 #[benchmark]
978 fn set_validator_self_stake_incentive_config() {
979 #[extrinsic_call]
980 _(
981 RawOrigin::Root,
982 ConfigOp::Set(30_000u32.into()),
983 ConfigOp::Set(100_000u32.into()),
984 ConfigOp::Set(Perbill::from_percent(50)),
985 );
986
987 assert_eq!(OptimumSelfStake::<T>::get(), 30_000u32.into());
988 assert_eq!(HardCapSelfStake::<T>::get(), 100_000u32.into());
989 assert_eq!(SelfStakeSlopeFactor::<T>::get(), Perbill::from_percent(50));
990 }
991
992 #[benchmark]
993 fn restore_ledger() -> Result<(), BenchmarkError> {
994 let (stash, controller) = create_stash_controller::<T>(0, 100, RewardDestination::Staked)?;
995 Ledger::<T>::remove(controller);
997
998 #[extrinsic_call]
999 _(RawOrigin::Root, stash.clone(), None, None, None);
1000
1001 assert_eq!(Staking::<T>::inspect_bond_state(&stash), Ok(LedgerIntegrityState::Ok));
1002
1003 Ok(())
1004 }
1005
1006 #[benchmark]
1007 fn migrate_currency() -> Result<(), BenchmarkError> {
1008 let (stash, _ctrl) =
1009 create_stash_controller::<T>(USER_SEED, 100, RewardDestination::Staked)?;
1010 let stake = asset::staked::<T>(&stash);
1011 migrate_to_old_currency::<T>(stash.clone());
1012 assert!(asset::staked::<T>(&stash).is_zero());
1014 whitelist_account!(stash);
1015
1016 #[extrinsic_call]
1017 _(RawOrigin::Signed(stash.clone()), stash.clone());
1018
1019 assert_eq!(asset::staked::<T>(&stash), stake);
1020 Ok(())
1021 }
1022
1023 #[benchmark]
1024 fn apply_slash(
1025 n: Linear<0, { T::MaxExposurePageSize::get() as u32 }>,
1026 ) -> Result<(), BenchmarkError> {
1027 let era = EraIndex::one();
1028 ActiveEra::<T>::put(ActiveEraInfo { index: era, start: None });
1029 let (validator, nominators, _current_era) = create_validator_with_nominators::<T>(
1030 T::MaxExposurePageSize::get() as u32,
1031 T::MaxExposurePageSize::get() as u32,
1032 false,
1033 true,
1034 RewardDestination::Staked,
1035 )?;
1036 let slash_fraction = Perbill::from_percent(10);
1037 let page_index = 0;
1038 let slashed_balance = BalanceOf::<T>::from(10u32);
1039
1040 let slash_key = (validator.clone(), slash_fraction, page_index);
1041 let slashed_nominators = nominators
1043 .iter()
1044 .take(n as usize)
1045 .map(|(nom, _)| (nom.clone(), slashed_balance))
1046 .collect::<Vec<_>>();
1047
1048 let unapplied_slash = UnappliedSlash::<T> {
1049 validator: validator.clone(),
1050 own: slashed_balance,
1051 others: WeakBoundedVec::force_from(slashed_nominators, None),
1052 reporter: Default::default(),
1053 payout: Zero::zero(),
1054 };
1055
1056 UnappliedSlashes::<T>::insert(era, slash_key.clone(), unapplied_slash);
1058
1059 #[extrinsic_call]
1060 _(RawOrigin::Signed(validator.clone()), era, slash_key.clone());
1061
1062 assert!(UnappliedSlashes::<T>::get(era, &slash_key).is_none());
1064
1065 Ok(())
1066 }
1067
1068 #[benchmark]
1069 fn process_offence_queue() -> Result<(), BenchmarkError> {
1070 #[cfg(test)]
1073 crate::mock::SlashDeferDuration::set(77);
1074
1075 let all_validators = crate::testing_utils::create_validators_with_nominators_for_era::<T>(
1077 ValidatorCount::<T>::get().max(1),
1079 2 * T::MaxExposurePageSize::get(),
1081 16,
1082 false,
1083 Some(1),
1084 )?;
1085 let offender =
1086 T::Lookup::lookup(all_validators.first().cloned().expect("must exist")).unwrap();
1087
1088 let _new_validators = Rotator::<T>::legacy_insta_plan_era();
1090 Rotator::<T>::start_era(
1092 crate::ActiveEraInfo { index: Rotator::<T>::planned_era() - 1, start: Some(1) },
1093 42, 2, );
1096
1097 let offender_exposure =
1099 Eras::<T>::get_full_exposure(Rotator::<T>::planned_era(), &offender);
1100 ensure!(
1101 offender_exposure.others.len() as u32 >= T::MaxExposurePageSize::get(),
1102 "exposure not created"
1103 );
1104
1105 let slash_session = 42;
1107 let offences = vec![rc_client::Offence {
1108 offender: offender.clone(),
1109 reporters: Default::default(),
1110 slash_fraction: Perbill::from_percent(50),
1111 }];
1112 <crate::Pallet<T> as rc_client::AHStakingInterface>::on_new_offences(
1113 slash_session,
1114 offences,
1115 );
1116
1117 ensure!(
1119 ValidatorSlashInEra::<T>::contains_key(Rotator::<T>::active_era(), offender),
1120 "offence not submitted"
1121 );
1122 ensure!(
1123 OffenceQueueEras::<T>::get().unwrap_or_default() == vec![Rotator::<T>::active_era()],
1124 "offence should be queued"
1125 );
1126
1127 #[block]
1128 {
1129 slashing::process_offence::<T>();
1130 }
1131
1132 ensure!(OffenceQueueEras::<T>::get().is_none(), "offence should not be queued");
1133
1134 Ok(())
1135 }
1136
1137 #[benchmark]
1138 fn rc_on_offence(
1139 v: Linear<2, { T::MaxValidatorSet::get() / 2 }>,
1140 ) -> Result<(), BenchmarkError> {
1141 let initial_era = Rotator::<T>::planned_era();
1142 let _ = crate::testing_utils::create_validators_with_nominators_for_era::<T>(
1143 2 * v,
1144 1000,
1146 16,
1147 false,
1148 None,
1149 )?;
1150
1151 let new_validators = Rotator::<T>::legacy_insta_plan_era();
1153 ensure!(Rotator::<T>::planned_era() == initial_era + 1, "era should be incremented");
1154 Rotator::<T>::start_era(
1156 crate::ActiveEraInfo { index: initial_era, start: Some(1) },
1157 42, 2, );
1160
1161 ensure!(Rotator::<T>::active_era_start_session_index() == 42, "BondedEra not set");
1163
1164 let to_slash_count = new_validators.len() / 2;
1166 let to_slash = new_validators.into_iter().take(to_slash_count).collect::<Vec<_>>();
1167 let one_slashed = to_slash.first().cloned().unwrap();
1168 let offences = to_slash
1169 .into_iter()
1170 .map(|offender| rc_client::Offence {
1171 offender,
1172 reporters: Default::default(),
1173 slash_fraction: Perbill::from_percent(50),
1174 })
1175 .collect::<Vec<_>>();
1176 let slash_session = 42;
1177
1178 ensure!(
1180 !ValidatorSlashInEra::<T>::contains_key(initial_era + 1, &one_slashed),
1181 "offence submitted???"
1182 );
1183
1184 #[block]
1185 {
1186 <crate::Pallet<T> as rc_client::AHStakingInterface>::on_new_offences(
1187 slash_session,
1188 offences,
1189 );
1190 }
1191
1192 ensure!(
1194 ValidatorSlashInEra::<T>::contains_key(initial_era + 1, one_slashed),
1195 "offence not submitted"
1196 );
1197
1198 Ok(())
1199 }
1200
1201 #[benchmark]
1202 fn rc_on_session_report() -> Result<(), BenchmarkError> {
1203 let initial_planned_era = Rotator::<T>::planned_era();
1204 let initial_active_era = Rotator::<T>::active_era();
1205
1206 crate::testing_utils::create_validators_with_nominators_for_era::<T>(
1209 10, 50, 2, false, None,
1210 )?;
1211
1212 let _new_validators = Rotator::<T>::legacy_insta_plan_era();
1214 ensure!(
1215 CurrentEra::<T>::get().unwrap() == initial_planned_era + 1,
1216 "era should be incremented"
1217 );
1218
1219 let validator_points = (0..T::MaxValidatorSet::get())
1221 .map(|v| (account::<T::AccountId>("random", v, SEED), v))
1222 .collect::<Vec<_>>();
1223 let activation_timestamp = Some((1u64, initial_planned_era + 1));
1224 let report = rc_client::SessionReport {
1225 end_index: 42,
1226 leftover: false,
1227 validator_points,
1228 activation_timestamp,
1229 };
1230
1231 #[block]
1232 {
1233 <crate::Pallet<T> as rc_client::AHStakingInterface>::on_relay_session_report(report);
1234 }
1235
1236 ensure!(Rotator::<T>::active_era() == initial_active_era + 1, "active era not bumped");
1237 Ok(())
1238 }
1239
1240 fn setup_era_for_pruning<T: Config>(v: u32) -> EraIndex {
1242 let validators = v;
1243 let era = 7;
1244
1245 let history_depth = T::HistoryDepth::get();
1248 let active_era = era + history_depth + 1;
1249 crate::ActiveEra::<T>::put(crate::ActiveEraInfo { index: active_era, start: Some(0) });
1250
1251 let max_total_nominators_per_validator =
1252 <T::ElectionProvider as ElectionProvider>::MaxBackersPerWinnerFinal::get();
1253 let exposed_nominators_per_validator = max_total_nominators_per_validator / validators;
1254
1255 let pages: WeakBoundedVec<_, _> = (0..crate::ClaimedRewardsBound::<T>::get())
1256 .collect::<Vec<_>>()
1257 .try_into()
1258 .unwrap();
1259
1260 let slashed_validators = validators / 3;
1262
1263 let mut reward_points_individual = BTreeMap::new();
1264 let mut total_incentive_weight = BalanceOf::<T>::zero();
1265
1266 for i in 0..validators {
1267 let validator = account::<T::AccountId>("validator", i, SEED);
1268
1269 ErasValidatorPrefs::<T>::insert(era, validator.clone(), ValidatorPrefs::default());
1271
1272 ClaimedRewards::<T>::insert(era, validator.clone(), pages.clone());
1274
1275 let exposure = sp_staking::Exposure::<T::AccountId, BalanceOf<T>> {
1277 own: T::Currency::minimum_balance(),
1278 total: T::Currency::minimum_balance() *
1279 (exposed_nominators_per_validator + 1).into(),
1280 others: (0..exposed_nominators_per_validator)
1281 .map(|n| {
1282 let nominator = account::<T::AccountId>("nominator", n, SEED);
1283 IndividualExposure { who: nominator, value: T::Currency::minimum_balance() }
1284 })
1285 .collect::<Vec<_>>(),
1286 };
1287 Eras::<T>::upsert_exposure(era, &validator, exposure);
1288
1289 reward_points_individual.insert(validator.clone(), 7u32);
1291
1292 if i < slashed_validators {
1294 crate::ValidatorSlashInEra::<T>::insert(
1295 era,
1296 validator.clone(),
1297 (Perbill::from_percent(10), BalanceOf::<T>::max_value() / 10u32.into()),
1298 );
1299 }
1300
1301 let incentive_weight = BalanceOf::<T>::from(100u64);
1303 ErasValidatorIncentiveWeight::<T>::insert(era, validator, incentive_weight);
1304 total_incentive_weight += incentive_weight;
1305 }
1306
1307 ErasValidatorReward::<T>::insert(era, BalanceOf::<T>::max_value());
1309 ErasRewardPoints::<T>::insert(
1310 era,
1311 crate::EraRewardPoints::<T> {
1312 total: 77777,
1313 individual: reward_points_individual.try_into().unwrap(),
1314 },
1315 );
1316 ErasTotalStake::<T>::insert(era, BalanceOf::<T>::max_value());
1317 ErasNominatorsSlashable::<T>::insert(era, true);
1318 ErasSumValidatorIncentiveWeight::<T>::insert(era, total_incentive_weight);
1319 ErasValidatorIncentiveBudget::<T>::insert(era, BalanceOf::<T>::from(1_000_000u64));
1320
1321 era
1322 }
1323
1324 fn validate_pruning_weight<T: Config>(
1326 result: &frame_support::dispatch::DispatchResultWithPostInfo,
1327 step_name: &str,
1328 validator_count: u32,
1329 ) {
1330 assert!(
1331 result.is_ok(),
1332 "Benchmark {} should succeed with v={}",
1333 step_name,
1334 validator_count
1335 );
1336
1337 let post_info = result.unwrap();
1338 let actual_ref_time = post_info
1339 .actual_weight
1340 .expect(&format!(
1341 "Should report actual weight for {} with v={}",
1342 step_name, validator_count
1343 ))
1344 .ref_time();
1345
1346 assert!(
1347 actual_ref_time > 0,
1348 "Should report non-zero ref_time for {} with v={}",
1349 step_name,
1350 validator_count
1351 );
1352 }
1354
1355 #[benchmark(pov_mode = Measured)]
1357 fn prune_era_stakers_paged(
1358 v: Linear<1, { T::MaxValidatorSet::get() }>,
1359 ) -> Result<(), BenchmarkError> {
1360 let era = setup_era_for_pruning::<T>(v);
1361 EraPruningState::<T>::insert(era, PruningStep::ErasStakersPaged);
1362
1363 let caller: T::AccountId = whitelisted_caller();
1364
1365 let result;
1366 #[block]
1367 {
1368 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1369 }
1370
1371 validate_pruning_weight::<T>(&result, "ErasStakersPaged", v);
1372
1373 Ok(())
1374 }
1375
1376 #[benchmark(pov_mode = Measured)]
1378 fn prune_era_stakers_overview(
1379 v: Linear<1, { T::MaxValidatorSet::get() }>,
1380 ) -> Result<(), BenchmarkError> {
1381 let era = setup_era_for_pruning::<T>(v);
1382 EraPruningState::<T>::insert(era, PruningStep::ErasStakersOverview);
1383
1384 let caller: T::AccountId = whitelisted_caller();
1385
1386 let result;
1387 #[block]
1388 {
1389 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1390 }
1391
1392 validate_pruning_weight::<T>(&result, "ErasStakersOverview", v);
1393
1394 Ok(())
1395 }
1396
1397 #[benchmark(pov_mode = Measured)]
1399 fn prune_era_validator_prefs(
1400 v: Linear<1, { T::MaxValidatorSet::get() }>,
1401 ) -> Result<(), BenchmarkError> {
1402 let era = setup_era_for_pruning::<T>(v);
1403 EraPruningState::<T>::insert(era, PruningStep::ErasValidatorPrefs);
1404
1405 let caller: T::AccountId = whitelisted_caller();
1406
1407 let result;
1408 #[block]
1409 {
1410 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1411 }
1412
1413 validate_pruning_weight::<T>(&result, "ErasValidatorPrefs", v);
1414
1415 Ok(())
1416 }
1417
1418 #[benchmark(pov_mode = Measured)]
1420 fn prune_era_claimed_rewards(
1421 v: Linear<1, { T::MaxValidatorSet::get() }>,
1422 ) -> Result<(), BenchmarkError> {
1423 let era = setup_era_for_pruning::<T>(v);
1424 EraPruningState::<T>::insert(era, PruningStep::ClaimedRewards);
1425
1426 let caller: T::AccountId = whitelisted_caller();
1427
1428 let result;
1429 #[block]
1430 {
1431 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1432 }
1433
1434 validate_pruning_weight::<T>(&result, "ClaimedRewards", v);
1435
1436 Ok(())
1437 }
1438
1439 #[benchmark(pov_mode = Measured)]
1441 fn prune_era_validator_reward() -> Result<(), BenchmarkError> {
1442 let era = setup_era_for_pruning::<T>(1);
1443 EraPruningState::<T>::insert(era, PruningStep::ErasValidatorReward);
1444
1445 let caller: T::AccountId = whitelisted_caller();
1446
1447 let result;
1448 #[block]
1449 {
1450 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1451 }
1452
1453 validate_pruning_weight::<T>(&result, "ErasValidatorReward", 1);
1454
1455 Ok(())
1456 }
1457
1458 #[benchmark(pov_mode = Measured)]
1460 fn prune_era_reward_points() -> Result<(), BenchmarkError> {
1461 let era = setup_era_for_pruning::<T>(1);
1462 EraPruningState::<T>::insert(era, PruningStep::ErasRewardPoints);
1463
1464 let caller: T::AccountId = whitelisted_caller();
1465
1466 let result;
1467 #[block]
1468 {
1469 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1470 }
1471
1472 validate_pruning_weight::<T>(&result, "ErasRewardPoints", 1);
1473
1474 Ok(())
1475 }
1476
1477 #[benchmark(pov_mode = Measured)]
1479 fn prune_era_single_entry_cleanups() -> Result<(), BenchmarkError> {
1480 let era = setup_era_for_pruning::<T>(1);
1481 EraPruningState::<T>::insert(era, PruningStep::SingleEntryCleanups);
1482
1483 let caller: T::AccountId = whitelisted_caller();
1484
1485 let result;
1486 #[block]
1487 {
1488 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1489 }
1490
1491 validate_pruning_weight::<T>(&result, "SingleEntryCleanups", 1);
1492
1493 Ok(())
1494 }
1495
1496 #[benchmark(pov_mode = Measured)]
1498 fn prune_era_validator_slash_in_era(
1499 v: Linear<1, { T::MaxValidatorSet::get() }>,
1500 ) -> Result<(), BenchmarkError> {
1501 let era = setup_era_for_pruning::<T>(v);
1502 EraPruningState::<T>::insert(era, PruningStep::ValidatorSlashInEra);
1503
1504 let caller: T::AccountId = whitelisted_caller();
1505
1506 let result;
1507 #[block]
1508 {
1509 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1510 }
1511
1512 validate_pruning_weight::<T>(&result, "ValidatorSlashInEra", v);
1513
1514 Ok(())
1515 }
1516
1517 #[benchmark(pov_mode = Measured)]
1518 fn prune_era_validator_incentive_weight(
1519 v: Linear<1, { T::MaxValidatorSet::get() }>,
1520 ) -> Result<(), BenchmarkError> {
1521 let era = setup_era_for_pruning::<T>(v);
1522 EraPruningState::<T>::insert(era, PruningStep::ErasValidatorIncentiveWeight);
1523
1524 let caller: T::AccountId = whitelisted_caller();
1525
1526 let result;
1527 #[block]
1528 {
1529 result = Pallet::<T>::prune_era_step(RawOrigin::Signed(caller).into(), era);
1530 }
1531
1532 validate_pruning_weight::<T>(&result, "ErasValidatorIncentiveWeight", v);
1533
1534 Ok(())
1535 }
1536
1537 impl_benchmark_test_suite!(
1538 Staking,
1539 crate::mock::ExtBuilder::default().has_stakers(true),
1540 crate::mock::Test,
1541 exec_name = build_and_execute
1542 );
1543}
1544
1545#[cfg(test)]
1546mod tests {
1547 use super::*;
1548 use crate::mock::{ExtBuilder, RuntimeOrigin, Staking, Test};
1549 use frame_support::assert_ok;
1550
1551 #[test]
1552 fn create_validators_with_nominators_for_era_works() {
1553 ExtBuilder::default().build_and_execute(|| {
1554 let v = 10;
1555 let n = 100;
1556
1557 create_validators_with_nominators_for_era::<Test>(
1558 v,
1559 n,
1560 MaxNominationsOf::<Test>::get() as usize,
1561 false,
1562 None,
1563 )
1564 .unwrap();
1565
1566 let count_validators = Validators::<Test>::iter().count();
1567 let count_nominators = Nominators::<Test>::iter().count();
1568
1569 assert_eq!(count_validators, Validators::<Test>::count() as usize);
1570 assert_eq!(count_nominators, Nominators::<Test>::count() as usize);
1571
1572 assert_eq!(count_validators, v as usize);
1573 assert_eq!(count_nominators, n as usize);
1574 });
1575 }
1576
1577 #[test]
1578 fn create_validator_with_nominators_works() {
1579 ExtBuilder::default().build_and_execute(|| {
1580 let n = 10;
1581
1582 let (validator_stash, nominators, current_era) =
1583 create_validator_with_nominators::<Test>(
1584 n,
1585 <<Test as Config>::MaxExposurePageSize as Get<_>>::get(),
1586 false,
1587 false,
1588 RewardDestination::Staked,
1589 )
1590 .unwrap();
1591
1592 assert_eq!(nominators.len() as u32, n);
1593
1594 let original_stakeable_balance = asset::stakeable_balance::<Test>(&validator_stash);
1595 assert_ok!(Staking::payout_stakers_by_page(
1596 RuntimeOrigin::signed(1337),
1597 validator_stash,
1598 current_era,
1599 0
1600 ));
1601 let new_stakeable_balance = asset::stakeable_balance::<Test>(&validator_stash);
1602
1603 assert!(original_stakeable_balance < new_stakeable_balance);
1605 });
1606 }
1607}