Newer
Older
let part_for_10 = Perbill::from_rational::<u32>(1000, 1125);
let part_for_100 = Perbill::from_rational::<u32>(125, 1125);
// Check state
Payee::<Test>::insert(11, RewardDestination::Controller);
Payee::<Test>::insert(101, RewardDestination::Controller);
<Pallet<Test>>::reward_by_ids(vec![(11, 1)]);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_0 = current_total_payout_for_duration(reward_time_per_era());
mock::start_active_era(1);
<Pallet<Test>>::reward_by_ids(vec![(11, 1)]);
// Change total issuance in order to modify total payout
let _ = Balances::deposit_creating(&999, 1_000_000_000);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_1 = current_total_payout_for_duration(reward_time_per_era());
mock::start_active_era(2);
<Pallet<Test>>::reward_by_ids(vec![(11, 1)]);
// Change total issuance in order to modify total payout
let _ = Balances::deposit_creating(&999, 1_000_000_000);
// Compute total payout now for whole duration as other parameter won't change
let total_payout_2 = current_total_payout_for_duration(reward_time_per_era());
assert!(total_payout_2 != total_payout_0);
assert!(total_payout_2 != total_payout_1);
mock::start_active_era(Staking::history_depth() + 1);
let active_era = Staking::active_era().unwrap().index;
// This is the latest planned era in staking, not the active era
let current_era = Staking::current_era().unwrap();
// Last kept is 1:
assert!(current_era - Staking::history_depth() == 1);
assert_noop!(
Staking::payout_stakers(Origin::signed(1337), 11, 0),
Error::<Test>::InvalidEraToReward.with_weight(err_weight)
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1));
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 2));
Staking::payout_stakers(Origin::signed(1337), 11, 2),
Error::<Test>::AlreadyClaimed.with_weight(err_weight)
Staking::payout_stakers(Origin::signed(1337), 11, active_era),
Error::<Test>::InvalidEraToReward.with_weight(err_weight)
// Era 0 can't be rewarded anymore and current era can't be rewarded yet
// only era 1 and 2 can be rewarded.
assert_eq!(
Balances::total_balance(&10),
init_balance_10 + part_for_10 * (total_payout_1 + total_payout_2),
);
assert_eq!(
Balances::total_balance(&100),
init_balance_100 + part_for_100 * (total_payout_1 + total_payout_2),
);
});
}
#[test]
fn zero_slash_keeps_nominators() {
ExtBuilder::default().build_and_execute(|| {
mock::start_active_era(1);
assert_eq!(Balances::free_balance(11), 1000);
let exposure = Staking::eras_stakers(Staking::active_era().unwrap().index, 11);
assert_eq!(Balances::free_balance(101), 2000);
on_offence_now(
&[
OffenceDetails {
offender: (11, exposure.clone()),
reporters: vec![],
},
],
&[Perbill::from_percent(0)],
);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(101), 2000);
// This is the best way to check that the validator was chilled; `get` will
// return default value.
for (stash, _) in <Staking as Store>::Validators::iter() {
assert!(stash != 11);
}
let nominations = <Staking as Store>::Nominators::get(&101).unwrap();
// and make sure that the vote will not be ignored, because the slash was
// zero.
let last_slash = <Staking as Store>::SlashingSpans::get(&11).unwrap().last_nonzero_slash();
assert!(nominations.submitted_in >= last_slash);
});
}
ExtBuilder::default().initialize_first_session(false).build_and_execute(|| {
use pallet_session::SessionManager;
let val_set = Session::validators();
let init_session = Session::current_index();
let init_active_era = Staking::active_era().unwrap().index;
// pallet-session is delaying session by one, thus the next session to plan is +2.
assert_eq!(<Staking as SessionManager<_>>::new_session(init_session + 2), None);
assert_eq!(<Staking as SessionManager<_>>::new_session(init_session + 3), Some(val_set.clone()));
assert_eq!(<Staking as SessionManager<_>>::new_session(init_session + 4), None);
assert_eq!(<Staking as SessionManager<_>>::new_session(init_session + 5), None);
assert_eq!(<Staking as SessionManager<_>>::new_session(init_session + 6), Some(val_set.clone()));
<Staking as SessionManager<_>>::end_session(init_session);
<Staking as SessionManager<_>>::start_session(init_session + 1);
assert_eq!(active_era(), init_active_era);
<Staking as SessionManager<_>>::end_session(init_session + 1);
<Staking as SessionManager<_>>::start_session(init_session + 2);
assert_eq!(active_era(), init_active_era);
// Reward current era
Staking::reward_by_ids(vec![(11, 1)]);
// New active era is triggered here.
<Staking as SessionManager<_>>::end_session(init_session + 2);
<Staking as SessionManager<_>>::start_session(init_session + 3);
assert_eq!(active_era(), init_active_era + 1);
<Staking as SessionManager<_>>::end_session(init_session + 3);
<Staking as SessionManager<_>>::start_session(init_session + 4);
assert_eq!(active_era(), init_active_era + 1);
<Staking as SessionManager<_>>::end_session(init_session + 4);
<Staking as SessionManager<_>>::start_session(init_session + 5);
assert_eq!(active_era(), init_active_era + 1);
// Reward current era
Staking::reward_by_ids(vec![(21, 2)]);
// New active era is triggered here.
<Staking as SessionManager<_>>::end_session(init_session + 5);
<Staking as SessionManager<_>>::start_session(init_session + 6);
assert_eq!(active_era(), init_active_era + 2);
// That reward are correct
assert_eq!(Staking::eras_reward_points(init_active_era).total, 1);
assert_eq!(Staking::eras_reward_points(init_active_era + 1).total, 2);
});
}
#[test]
fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward() {
ExtBuilder::default().build_and_execute(|| {
for i in 0..=<Test as Config>::MaxNominatorRewardedPerValidator::get() {
let stash = 10_000 + i as AccountId;
let controller = 20_000 + i as AccountId;
let balance = 10_000 + i as Balance;
Balances::make_free_balance_be(&stash, balance);
assert_ok!(
Staking::bond(
Origin::signed(stash),
controller,
balance,
RewardDestination::Stash
)
);
assert_ok!(Staking::nominate(Origin::signed(controller), vec![11]));
}
mock::start_active_era(1);
<Pallet<Test>>::reward_by_ids(vec![(11, 1)]);
// compute and ensure the reward amount is greater than zero.
let _ = current_total_payout_for_duration(reward_time_per_era());
mock::start_active_era(2);
mock::make_all_reward_payment(1);
// Assert only nominators from 1 to Max are rewarded
for i in 0..=<Test as Config>::MaxNominatorRewardedPerValidator::get() {
let stash = 10_000 + i as AccountId;
let balance = 10_000 + i as Balance;
if stash == 10_000 {
assert!(Balances::free_balance(&stash) == balance);
} else {
assert!(Balances::free_balance(&stash) > balance);
}
}
});
}
#[test]
fn set_history_depth_works() {
ExtBuilder::default().build_and_execute(|| {
mock::start_active_era(10);
Staking::set_history_depth(Origin::root(), 20, 0).unwrap();
assert!(<Staking as Store>::ErasTotalStake::contains_key(10 - 4));
assert!(<Staking as Store>::ErasTotalStake::contains_key(10 - 5));
Staking::set_history_depth(Origin::root(), 4, 0).unwrap();
assert!(<Staking as Store>::ErasTotalStake::contains_key(10 - 4));
assert!(!<Staking as Store>::ErasTotalStake::contains_key(10 - 5));
Staking::set_history_depth(Origin::root(), 3, 0).unwrap();
assert!(!<Staking as Store>::ErasTotalStake::contains_key(10 - 4));
assert!(!<Staking as Store>::ErasTotalStake::contains_key(10 - 5));
Staking::set_history_depth(Origin::root(), 8, 0).unwrap();
assert!(!<Staking as Store>::ErasTotalStake::contains_key(10 - 4));
assert!(!<Staking as Store>::ErasTotalStake::contains_key(10 - 5));
});
}
#[test]
fn test_payout_stakers() {
// Here we will test validator can set `max_nominators_payout` and it works.
// We also test that `payout_extra_nominators` works.
ExtBuilder::default().has_stakers(false).build_and_execute(|| {
bond_validator(11, 10, balance); // Default(64)
// Create nominators, targeting stash of validators
for i in 0..100 {
bond_nominator(1000 + i, 100 + i, balance + i as Balance, vec![11]);
mock::start_active_era(1);
// compute and ensure the reward amount is greater than zero.
let _ = current_total_payout_for_duration(reward_time_per_era());
mock::start_active_era(2);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1));
// Top 64 nominators of validator 11 automatically paid out, including the validator
// Validator payout goes to controller.
assert!(Balances::free_balance(&10) > balance);
for i in 36..100 {
assert!(Balances::free_balance(&(100 + i)) > balance + i as Balance);
}
// The bottom 36 do not
for i in 0..36 {
assert_eq!(Balances::free_balance(&(100 + i)), balance + i as Balance);
}
// We track rewards in `claimed_rewards` vec
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![], claimed_rewards: vec![1] })
);
for i in 3..16 {
Staking::reward_by_ids(vec![(11, 1)]);
// compute and ensure the reward amount is greater than zero.
let _ = current_total_payout_for_duration(reward_time_per_era());
mock::start_active_era(i);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, i - 1));
}
// We track rewards in `claimed_rewards` vec
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![], claimed_rewards: (1..=14).collect() })
);
for i in 16..100 {
Staking::reward_by_ids(vec![(11, 1)]);
// compute and ensure the reward amount is greater than zero.
let _ = current_total_payout_for_duration(reward_time_per_era());
mock::start_active_era(i);
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
}
// We clean it up as history passes
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 15));
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 98));
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![], claimed_rewards: vec![15, 98] })
);
// Out of order claims works.
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 69));
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 23));
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 42));
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![], claimed_rewards: vec![15, 23, 42, 69, 98] })
);
});
}
#[test]
fn payout_stakers_handles_basic_errors() {
// Here we will test payouts handle all errors.
ExtBuilder::default().has_stakers(false).build_and_execute(|| {
// Consumed weight for all payout_stakers dispatches that fail
let err_weight = weights::SubstrateWeight::<Test>::payout_stakers_alive_staked(0);
// Same setup as the test above
let balance = 1000;
bond_validator(11, 10, balance); // Default(64)
// Create nominators, targeting stash
for i in 0..100 {
bond_nominator(1000 + i, 100 + i, balance + i as Balance, vec![11]);
mock::start_active_era(1);
// compute and ensure the reward amount is greater than zero.
let _ = current_total_payout_for_duration(reward_time_per_era());
mock::start_active_era(2);
assert_noop!(
Staking::payout_stakers(Origin::signed(1337), 11, 2),
Error::<Test>::InvalidEraToReward.with_weight(err_weight)
);
assert_noop!(
Staking::payout_stakers(Origin::signed(1337), 10, 1),
Error::<Test>::NotStash.with_weight(err_weight)
);
for i in 3..100 {
Staking::reward_by_ids(vec![(11, 1)]);
// compute and ensure the reward amount is greater than zero.
let _ = current_total_payout_for_duration(reward_time_per_era());
mock::start_active_era(i);
}
// We are at era 99, with history depth of 84
// We should be able to payout era 15 through 98 (84 total eras), but not 14 or 99.
assert_noop!(
Staking::payout_stakers(Origin::signed(1337), 11, 14),
Error::<Test>::InvalidEraToReward.with_weight(err_weight)
);
assert_noop!(
Staking::payout_stakers(Origin::signed(1337), 11, 99),
Error::<Test>::InvalidEraToReward.with_weight(err_weight)
);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 15));
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 98));
// Can't claim again
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
assert_noop!(
Staking::payout_stakers(Origin::signed(1337), 11, 15),
Error::<Test>::AlreadyClaimed.with_weight(err_weight)
);
assert_noop!(
Staking::payout_stakers(Origin::signed(1337), 11, 98),
Error::<Test>::AlreadyClaimed.with_weight(err_weight)
);
});
}
#[test]
fn payout_stakers_handles_weight_refund() {
// Note: this test relies on the assumption that `payout_stakers_alive_staked` is solely used by
// `payout_stakers` to calculate the weight of each payout op.
ExtBuilder::default().has_stakers(false).build_and_execute(|| {
let max_nom_rewarded = <Test as Config>::MaxNominatorRewardedPerValidator::get();
// Make sure the configured value is meaningful for our use.
assert!(max_nom_rewarded >= 4);
let half_max_nom_rewarded = max_nom_rewarded / 2;
// Sanity check our max and half max nominator quantities.
assert!(half_max_nom_rewarded > 0);
assert!(max_nom_rewarded > half_max_nom_rewarded);
let max_nom_rewarded_weight
= <Test as Config>::WeightInfo::payout_stakers_alive_staked(max_nom_rewarded);
let half_max_nom_rewarded_weight
= <Test as Config>::WeightInfo::payout_stakers_alive_staked(half_max_nom_rewarded);
let zero_nom_payouts_weight = <Test as Config>::WeightInfo::payout_stakers_alive_staked(0);
assert!(zero_nom_payouts_weight > 0);
assert!(half_max_nom_rewarded_weight > zero_nom_payouts_weight);
assert!(max_nom_rewarded_weight > half_max_nom_rewarded_weight);
let balance = 1000;
bond_validator(11, 10, balance);
/* Era 1 */
start_active_era(1);
// Reward just the validator.
Staking::reward_by_ids(vec![(11, 1)]);
// Add some `half_max_nom_rewarded` nominators who will start backing the validator in the
// next era.
for i in 0..half_max_nom_rewarded {
bond_nominator((1000 + i).into(), (100 + i).into(), balance + i as Balance, vec![11]);
}
/* Era 2 */
start_active_era(2);
// Collect payouts when there are no nominators
let call = TestRuntimeCall::Staking(StakingCall::payout_stakers(11, 1));
let info = call.get_dispatch_info();
let result = call.dispatch(Origin::signed(20));
assert_ok!(result);
assert_eq!(
extract_actual_weight(&result, &info),
zero_nom_payouts_weight
);
// The validator is not rewarded in this era; so there will be zero payouts to claim for this era.
/* Era 3 */
start_active_era(3);
// Collect payouts for an era where the validator did not receive any points.
let call = TestRuntimeCall::Staking(StakingCall::payout_stakers(11, 2));
let info = call.get_dispatch_info();
let result = call.dispatch(Origin::signed(20));
assert_ok!(result);
assert_eq!(extract_actual_weight(&result, &info), zero_nom_payouts_weight);
// Reward the validator and its nominators.
Staking::reward_by_ids(vec![(11, 1)]);
/* Era 4 */
start_active_era(4);
// Collect payouts when the validator has `half_max_nom_rewarded` nominators.
let call = TestRuntimeCall::Staking(StakingCall::payout_stakers(11, 3));
let info = call.get_dispatch_info();
let result = call.dispatch(Origin::signed(20));
assert_ok!(result);
assert_eq!(extract_actual_weight(&result, &info), half_max_nom_rewarded_weight);
// Add enough nominators so that we are at the limit. They will be active nominators
// in the next era.
for i in half_max_nom_rewarded..max_nom_rewarded {
bond_nominator((1000 + i).into(), (100 + i).into(), balance + i as Balance, vec![11]);
}
/* Era 5 */
start_active_era(5);
// We now have `max_nom_rewarded` nominators actively nominating our validator.
// Reward the validator so we can collect for everyone in the next era.
Staking::reward_by_ids(vec![(11, 1)]);
/* Era 6 */
start_active_era(6);
// Collect payouts when the validator had `half_max_nom_rewarded` nominators.
let call = TestRuntimeCall::Staking(StakingCall::payout_stakers(11, 5));
let info = call.get_dispatch_info();
let result = call.dispatch(Origin::signed(20));
assert_ok!(result);
assert_eq!(extract_actual_weight(&result, &info), max_nom_rewarded_weight);
// Try and collect payouts for an era that has already been collected.
let call = TestRuntimeCall::Staking(StakingCall::payout_stakers(11, 5));
let info = call.get_dispatch_info();
let result = call.dispatch(Origin::signed(20));
assert!(result.is_err());
// When there is an error the consumed weight == weight when there are 0 nominator payouts.
assert_eq!(extract_actual_weight(&result, &info), zero_nom_payouts_weight);
});
}
#[test]
fn bond_during_era_correctly_populates_claimed_rewards() {
ExtBuilder::default().has_stakers(false).build_and_execute(|| {
// Era = None
bond_validator(9, 8, 1000);
assert_eq!(
Staking::ledger(&8),
Some(StakingLedger {
stash: 9,
total: 1000,
active: 1000,
unlocking: vec![],
claimed_rewards: vec![],
})
);
mock::start_active_era(5);
bond_validator(11, 10, 1000);
assert_eq!(
Staking::ledger(&10),
Some(StakingLedger {
stash: 11,
total: 1000,
active: 1000,
unlocking: vec![],
claimed_rewards: (0..5).collect(),
})
);
mock::start_active_era(99);
bond_validator(13, 12, 1000);
assert_eq!(
Staking::ledger(&12),
Some(StakingLedger {
stash: 13,
total: 1000,
active: 1000,
unlocking: vec![],
claimed_rewards: (15..99).collect(),
})
);
});
}
#[test]
fn offences_weight_calculated_correctly() {
ExtBuilder::default().nominate(true).build_and_execute(|| {
// On offence with zero offenders: 4 Reads, 1 Write
let zero_offence_weight = <Test as frame_system::Config>::DbWeight::get().reads_writes(4, 1);
assert_eq!(Staking::on_offence(&[], &[Perbill::from_percent(50)], 0), zero_offence_weight);
// On Offence with N offenders, Unapplied: 4 Reads, 1 Write + 4 Reads, 5 Writes
let n_offence_unapplied_weight = <Test as frame_system::Config>::DbWeight::get().reads_writes(4, 1)
+ <Test as frame_system::Config>::DbWeight::get().reads_writes(4, 5);
let offenders: Vec<OffenceDetails<<Test as frame_system::Config>::AccountId, pallet_session::historical::IdentificationTuple<Test>>>
= (1..10).map(|i|
OffenceDetails {
offender: (i, Staking::eras_stakers(Staking::active_era().unwrap().index, i)),
reporters: vec![],
}
).collect();
assert_eq!(Staking::on_offence(&offenders, &[Perbill::from_percent(50)], 0), n_offence_unapplied_weight);
// On Offence with one offenders, Applied
let one_offender = [
OffenceDetails {
offender: (11, Staking::eras_stakers(Staking::active_era().unwrap().index, 11)),
reporters: vec![1],
},
];
let n = 1; // Number of offenders
let rw = 3 + 3 * n; // rw reads and writes
let one_offence_unapplied_weight = <Test as frame_system::Config>::DbWeight::get().reads_writes(4, 1)
+ <Test as frame_system::Config>::DbWeight::get().reads_writes(rw, rw)
+ <Test as frame_system::Config>::DbWeight::get().reads_writes(6, 5)
// `slash_cost` * nominators (1)
+ <Test as frame_system::Config>::DbWeight::get().reads_writes(6, 5)
// `reward_cost` * reporters (1)
+ <Test as frame_system::Config>::DbWeight::get().reads_writes(2, 2);
assert_eq!(Staking::on_offence(&one_offender, &[Perbill::from_percent(50)], 0), one_offence_unapplied_weight);
#[test]
fn payout_creates_controller() {
ExtBuilder::default().has_stakers(false).build_and_execute(|| {
let balance = 1000;
// Create a validator:
bond_validator(11, 10, balance);
// Create a stash/controller pair
bond_nominator(1234, 1337, 100, vec![11]);
// kill controller
assert_ok!(Balances::transfer(Origin::signed(1337), 1234, 100));
assert_eq!(Balances::free_balance(1337), 0);
mock::start_active_era(1);
Staking::reward_by_ids(vec![(11, 1)]);
// compute and ensure the reward amount is greater than zero.
let _ = current_total_payout_for_duration(reward_time_per_era());
mock::start_active_era(2);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1));
// Controller is created
assert!(Balances::free_balance(1337) > 0);
})
}
#[test]
fn payout_to_any_account_works() {
ExtBuilder::default().has_stakers(false).build_and_execute(|| {
let balance = 1000;
// Create a validator:
bond_validator(11, 10, balance); // Default(64)
// Create a stash/controller pair
bond_nominator(1234, 1337, 100, vec![11]);
// Update payout location
assert_ok!(Staking::set_payee(Origin::signed(1337), RewardDestination::Account(42)));
// Reward Destination account doesn't exist
assert_eq!(Balances::free_balance(42), 0);
mock::start_active_era(1);
Staking::reward_by_ids(vec![(11, 1)]);
// compute and ensure the reward amount is greater than zero.
let _ = current_total_payout_for_duration(reward_time_per_era());
mock::start_active_era(2);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1));
// Payment is successful
assert!(Balances::free_balance(42) > 0);
})
}
#[test]
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
fn session_buffering_with_offset() {
// similar to live-chains, have some offset for the first session
ExtBuilder::default()
.offset(2)
.period(5)
.session_per_era(5)
.build_and_execute(|| {
assert_eq!(current_era(), 0);
assert_eq!(active_era(), 0);
assert_eq!(Session::current_index(), 0);
start_session(1);
assert_eq!(current_era(), 0);
assert_eq!(active_era(), 0);
assert_eq!(Session::current_index(), 1);
assert_eq!(System::block_number(), 2);
start_session(2);
assert_eq!(current_era(), 0);
assert_eq!(active_era(), 0);
assert_eq!(Session::current_index(), 2);
assert_eq!(System::block_number(), 7);
start_session(3);
assert_eq!(current_era(), 0);
assert_eq!(active_era(), 0);
assert_eq!(Session::current_index(), 3);
assert_eq!(System::block_number(), 12);
// active era is lagging behind by one session, because of how session module works.
start_session(4);
assert_eq!(current_era(), 1);
assert_eq!(active_era(), 0);
assert_eq!(Session::current_index(), 4);
assert_eq!(System::block_number(), 17);
start_session(5);
assert_eq!(current_era(), 1);
assert_eq!(active_era(), 1);
assert_eq!(Session::current_index(), 5);
assert_eq!(System::block_number(), 22);
// go all the way to active 2.
start_active_era(2);
assert_eq!(current_era(), 2);
assert_eq!(active_era(), 2);
assert_eq!(Session::current_index(), 10);
});
}
#[test]
fn session_buffering_no_offset() {
// no offset, first session starts immediately
ExtBuilder::default()
.offset(0)
.period(5)
.session_per_era(5)
.build_and_execute(|| {
assert_eq!(current_era(), 0);
assert_eq!(active_era(), 0);
assert_eq!(Session::current_index(), 0);
start_session(1);
assert_eq!(current_era(), 0);
assert_eq!(active_era(), 0);
assert_eq!(Session::current_index(), 1);
assert_eq!(System::block_number(), 5);
start_session(2);
assert_eq!(current_era(), 0);
assert_eq!(active_era(), 0);
assert_eq!(Session::current_index(), 2);
assert_eq!(System::block_number(), 10);
start_session(3);
assert_eq!(current_era(), 0);
assert_eq!(active_era(), 0);
assert_eq!(Session::current_index(), 3);
assert_eq!(System::block_number(), 15);
// active era is lagging behind by one session, because of how session module works.
start_session(4);
assert_eq!(current_era(), 1);
assert_eq!(active_era(), 0);
assert_eq!(Session::current_index(), 4);
assert_eq!(System::block_number(), 20);
start_session(5);
assert_eq!(current_era(), 1);
assert_eq!(active_era(), 1);
assert_eq!(Session::current_index(), 5);
assert_eq!(System::block_number(), 25);
// go all the way to active 2.
start_active_era(2);
assert_eq!(current_era(), 2);
assert_eq!(active_era(), 2);
assert_eq!(Session::current_index(), 10);
});
}
#[test]
fn cannot_rebond_to_lower_than_ed() {
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
ExtBuilder::default()
.existential_deposit(10)
.build_and_execute(|| {
// stash must have more balance than bonded for this to work.
assert_eq!(Balances::free_balance(&21), 512_000);
// initial stuff.
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
total: 1000,
active: 1000,
unlocking: vec![],
claimed_rewards: vec![]
}
);
// unbond all of it.
assert_ok!(Staking::unbond(Origin::signed(20), 1000));
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
total: 1000,
active: 0,
unlocking: vec![UnlockChunk { value: 1000, era: 3 }],
claimed_rewards: vec![]
}
);
// now bond a wee bit more
assert_noop!(
Staking::rebond(Origin::signed(20), 5),
Error::<Test>::InsufficientValue,
);
})
}
#[test]
fn cannot_bond_extra_to_lower_than_ed() {
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
ExtBuilder::default()
.existential_deposit(10)
.build_and_execute(|| {
// stash must have more balance than bonded for this to work.
assert_eq!(Balances::free_balance(&21), 512_000);
// initial stuff.
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
total: 1000,
active: 1000,
unlocking: vec![],
claimed_rewards: vec![]
}
);
// unbond all of it.
assert_ok!(Staking::unbond(Origin::signed(20), 1000));
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
total: 1000,
active: 0,
unlocking: vec![UnlockChunk {
value: 1000,
era: 3
}],
claimed_rewards: vec![]
}
);
// now bond a wee bit more
assert_noop!(
Staking::bond_extra(Origin::signed(21), 5),
Error::<Test>::InsufficientValue,
);
})
}
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
#[test]
fn do_not_die_when_active_is_ed() {
let ed = 10;
ExtBuilder::default()
.existential_deposit(ed)
.build_and_execute(|| {
// initial stuff.
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
total: 1000,
active: 1000,
unlocking: vec![],
claimed_rewards: vec![]
}
);
// unbond all of it except ed.
assert_ok!(Staking::unbond(Origin::signed(20), 1000 - ed));
start_active_era(3);
assert_ok!(Staking::withdraw_unbonded(Origin::signed(20), 100));
// initial stuff.
assert_eq!(
Staking::ledger(&20).unwrap(),
StakingLedger {
stash: 21,
total: ed,
active: ed,
unlocking: vec![],
claimed_rewards: vec![]
}
);
})
}
#[test]
fn on_finalize_weight_is_nonzero() {
ExtBuilder::default().build_and_execute(|| {
let on_finalize_weight = <Test as frame_system::Config>::DbWeight::get().reads(1);
assert!(<Staking as Hooks<u64>>::on_initialize(1) >= on_finalize_weight);
mod election_data_provider {
use super::*;
use frame_election_provider_support::ElectionDataProvider;
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
#[test]
fn targets_2sec_block() {
let mut validators = 1000;
while <Test as Config>::WeightInfo::get_npos_targets(validators)
< 2 * frame_support::weights::constants::WEIGHT_PER_SECOND
{
validators += 1;
}
println!("Can create a snapshot of {} validators in 2sec block", validators);
}
#[test]
fn voters_2sec_block() {
// we assume a network only wants up to 1000 validators in most cases, thus having 2000
// candidates is as high as it gets.
let validators = 2000;
// we assume the worse case: each validator also has a slashing span.
let slashing_spans = validators;
let mut nominators = 1000;
while <Test as Config>::WeightInfo::get_npos_voters(validators, nominators, slashing_spans)
< 2 * frame_support::weights::constants::WEIGHT_PER_SECOND
{
nominators += 1;
}
println!(
"Can create a snapshot of {} nominators [{} validators, each 1 slashing] in 2sec block",
nominators, validators
);
}
#[test]
fn voters_include_self_vote() {
ExtBuilder::default().nominate(false).build().execute_with(|| {
assert!(<Validators<Test>>::iter().map(|(x, _)| x).all(|v| Staking::voters(None)
.unwrap()
.0
.into_iter()
.find(|(w, _, t)| { v == *w && t[0] == *w })
.is_some()))
})
}
#[test]
fn voters_exclude_slashed() {
ExtBuilder::default().build().execute_with(|| {
assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]);
assert_eq!(
<Staking as ElectionDataProvider<AccountId, BlockNumber>>::voters(None)
.unwrap()
.0
.iter()
.find(|x| x.0 == 101)
.unwrap()
.2,
vec![11, 21]
);
start_active_era(1);
add_slash(&11);
// 11 is gone.
start_active_era(2);
assert_eq!(
<Staking as ElectionDataProvider<AccountId, BlockNumber>>::voters(None)
.unwrap()
.0
.iter()
.find(|x| x.0 == 101)
.unwrap()
.2,
vec![21]
);
// resubmit and it is back
assert_ok!(Staking::nominate(Origin::signed(100), vec![11, 21]));
assert_eq!(
<Staking as ElectionDataProvider<AccountId, BlockNumber>>::voters(None)
.unwrap()
.0
.iter()
.find(|x| x.0 == 101)
.unwrap()
.2,
vec![11, 21]
);
})
}
#[test]
fn respects_len_limits() {
ExtBuilder::default().build().execute_with(|| {
assert_eq!(Staking::voters(Some(1)).unwrap_err(), "Voter snapshot too big");
assert_eq!(Staking::targets(Some(1)).unwrap_err(), "Target snapshot too big");
});
}
#[test]
fn estimate_next_election_works() {
ExtBuilder::default().session_per_era(5).period(5).build().execute_with(|| {
// first session is always length 0.
for b in 1..20 {
run_to_block(b);
assert_eq!(Staking::next_election_prediction(System::block_number()), 20);
}
// election
run_to_block(20);
assert_eq!(Staking::next_election_prediction(System::block_number()), 45);
assert_eq!(staking_events().len(), 1);
assert_eq!(
*staking_events().last().unwrap(),
Event::StakingElection
);
for b in 21..45 {
run_to_block(b);
assert_eq!(Staking::next_election_prediction(System::block_number()), 45);
}
// election
run_to_block(45);
assert_eq!(Staking::next_election_prediction(System::block_number()), 70);
assert_eq!(staking_events().len(), 3);
assert_eq!(
*staking_events().last().unwrap(),
Event::StakingElection
thiolliere
committed
Staking::force_no_eras(Origin::root()).unwrap();
assert_eq!(Staking::next_election_prediction(System::block_number()), u64::max_value());
Staking::force_new_era_always(Origin::root()).unwrap();
assert_eq!(Staking::next_election_prediction(System::block_number()), 45 + 5);
Staking::force_new_era(Origin::root()).unwrap();
assert_eq!(Staking::next_election_prediction(System::block_number()), 45 + 5);
// Do a fail election
MinimumValidatorCount::<Test>::put(1000);
run_to_block(50);
// Election: failed, next session is a new election
assert_eq!(Staking::next_election_prediction(System::block_number()), 50 + 5);