Newer
Older
.offchain_election_ext()
.validator_count(4)
.has_stakers(false)
.build()
.execute_with(|| {
build_offchain_election_test_ext();
// finalize the round with fallback. This is needed since all nominator submission
// are in era zero and we want this one to pass with no problems.
run_to_block(15);
// go to the next session to trigger mock::start_era and bump the active era
run_to_block(20);
// slash 10. This must happen outside of the election window.
let offender_expo = Staking::eras_stakers(Staking::active_era().unwrap().index, 11);
on_offence_now(
&[OffenceDetails {
offender: (11, offender_expo.clone()),
reporters: vec![],
}],
&[Perbill::from_percent(50)],
);
// validate 10 again for the next round. But this guy will not have the votes that
// it should have had from 1 and 2.
assert_ok!(Staking::validate(
Origin::signed(10),
Default::default()
));
// open the election window and create snapshots.
run_to_block(32);
// a solution that has been prepared after the slash.
let (compact, winners, score) = prepare_submission_with(true, false, 0, |a| {
// no one is allowed to vote for 10, except for itself.
a.into_iter()
.filter(|s| s.who != 11)
.for_each(|s|
assert!(s.distribution.iter().find(|(t, _)| *t == 11).is_none())
);
});
// can be submitted.
assert_ok!(submit_solution(
Origin::signed(10),
winners,
compact,
score,
));
// a wrong solution.
let (compact, winners, score) = prepare_submission_with(true, false, 0, |a| {
// add back the vote that has been filtered out.
a.push(StakedAssignment {
who: 1,
distribution: vec![(11, 100)]
});
});
// is rejected.
assert_noop!(
Origin::signed(10),
winners,
compact,
score,
),
Error::<Test>::OffchainElectionSlashedNomination,
fn invalid_election_wrong_score() {
// A valid voter who's total distributed stake is more than what they bond
ExtBuilder::default()
.offchain_election_ext()
.validator_count(4)
.has_stakers(false)
.build()
.execute_with(|| {
build_offchain_election_test_ext();
let (compact, winners, mut score) = prepare_submission_with(true, true, 2, |_| {});
score[0] += 1;
assert_noop!(
Origin::signed(10),
winners,
compact,
score,
),
Error::<Test>::OffchainElectionBogusScore,
);
})
}
#[test]
fn offchain_storage_is_set() {
let mut ext = ExtBuilder::default()
.offchain_election_ext()
ext.execute_with(|| {
use offchain_election::OFFCHAIN_HEAD_DB;
use sp_runtime::offchain::storage::StorageValueRef;
run_to_block(12);
Staking::offchain_worker(12);
// it works
assert_eq!(state.read().transactions.len(), 1);
// and it is set
let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB);
assert_eq!(storage.get::<BlockNumber>().unwrap().unwrap(), 12);
})
}
#[test]
fn offchain_storage_prevents_duplicate() {
let mut ext = ExtBuilder::default()
.offchain_election_ext()
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
ext.execute_with(|| {
use offchain_election::OFFCHAIN_HEAD_DB;
use sp_runtime::offchain::storage::StorageValueRef;
let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB);
run_to_block(12);
// first run -- ok
assert_eq!(
offchain_election::set_check_offchain_execution_status::<Test>(12),
Ok(()),
);
assert_eq!(storage.get::<BlockNumber>().unwrap().unwrap(), 12);
// re-execute after the next. not allowed.
assert_eq!(
offchain_election::set_check_offchain_execution_status::<Test>(13),
Err("recently executed."),
);
// a fork like situation -- re-execute 10, 11, 12. But it won't go through.
assert_eq!(
offchain_election::set_check_offchain_execution_status::<Test>(10),
Err("fork."),
);
assert_eq!(
offchain_election::set_check_offchain_execution_status::<Test>(11),
Err("fork."),
);
assert_eq!(
offchain_election::set_check_offchain_execution_status::<Test>(12),
Err("recently executed."),
);
})
}
#[test]
#[should_panic]
fn offence_is_blocked_when_window_open() {
ExtBuilder::default()
.offchain_election_ext()
.validator_count(4)
.has_stakers(false)
.build()
.execute_with(|| {
run_to_block(12);
assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12));
let offender_expo = Staking::eras_stakers(Staking::active_era().unwrap().index, 10);
// panic from the impl in mock
on_offence_now(
&[OffenceDetails {
offender: (10, offender_expo.clone()),
reporters: vec![],
}],
&[Perbill::from_percent(10)],
);
})
}
}
fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_validator() {
ExtBuilder::default().build_and_execute(|| {
mock::start_active_era(1);
assert_eq_uvec!(Session::validators(), vec![11, 21]);
assert_eq!(Balances::free_balance(11), 1000);
assert_eq!(Balances::free_balance(101), 2000);
// 11 and 21 both have the support of 100
let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11);
let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21);
assert_eq!(exposure_11.total, 1000 + 125);
assert_eq!(exposure_21.total, 1000 + 375);
on_offence_now(
&[OffenceDetails {
offender: (11, exposure_11.clone()),
reporters: vec![],
}],
&[Perbill::from_percent(10)],
);
// post-slash balance
let nominator_slash_amount_11 = 125 / 10;
assert_eq!(Balances::free_balance(11), 900);
assert_eq!(
Balances::free_balance(101),
2000 - nominator_slash_amount_11
);
// 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 be ignored even if the validator
// re-registers.
let last_slash = <Staking as Store>::SlashingSpans::get(&11)
.unwrap()
.last_nonzero_slash();
assert!(nominations.submitted_in < last_slash);
// actually re-bond the slashed validator
assert_ok!(Staking::validate(Origin::signed(10), Default::default()));
mock::start_active_era(2);
let exposure_11 = Staking::eras_stakers(Staking::active_era().unwrap().index, &11);
let exposure_21 = Staking::eras_stakers(Staking::active_era().unwrap().index, &21);
// 10 is re-elected, but without the support of 100
assert_eq!(exposure_11.total, 900);
// 20 is re-elected, with the (almost) entire support of 100
assert_eq!(exposure_21.total, 1000 + 500 - nominator_slash_amount_11);
}
#[test]
fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() {
// should check that:
// * rewards get paid until history_depth for both validators and nominators
// * an invalid era to claim doesn't update last_reward
// * double claim of one era fails
ExtBuilder::default().nominate(true).build_and_execute(|| {
let init_balance_10 = Balances::total_balance(&10);
let init_balance_100 = Balances::total_balance(&100);
let part_for_10 = Perbill::from_rational_approximation::<u32>(1000, 1125);
let part_for_100 = Perbill::from_rational_approximation::<u32>(125, 1125);
// Check state
Payee::<Test>::insert(11, RewardDestination::Controller);
Payee::<Test>::insert(101, RewardDestination::Controller);
<Module<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);
<Module<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);
<Module<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),
// Fail: Era out of history
Error::<Test>::InvalidEraToReward
);
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),
Staking::payout_stakers(Origin::signed(1337), 11, active_era),
// Fail: Era not finished yet
Error::<Test>::InvalidEraToReward
);
// 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);
// 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);
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
}
// 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(|| {
// 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);
// Wrong Era, too big
assert_noop!(Staking::payout_stakers(Origin::signed(1337), 11, 2), Error::<Test>::InvalidEraToReward);
// Wrong Staker
assert_noop!(Staking::payout_stakers(Origin::signed(1337), 10, 1), Error::<Test>::NotStash);
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);
assert_noop!(Staking::payout_stakers(Origin::signed(1337), 11, 99), Error::<Test>::InvalidEraToReward);
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 15));
assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 98));
// Can't claim again
assert_noop!(Staking::payout_stakers(Origin::signed(1337), 11, 15), Error::<Test>::AlreadyClaimed);
assert_noop!(Staking::payout_stakers(Origin::signed(1337), 11, 98), Error::<Test>::AlreadyClaimed);
});
}
#[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), Ok(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), Ok(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), Ok(one_offence_unapplied_weight));
});
}
#[test]
fn on_initialize_weight_is_correct() {
ExtBuilder::default().has_stakers(false).build_and_execute(|| {
assert_eq!(Validators::<Test>::iter().count(), 0);
assert_eq!(Nominators::<Test>::iter().count(), 0);
// When this pallet has nothing, we do 4 reads each block
let base_weight = <Test as frame_system::Config>::DbWeight::get().reads(4);
assert_eq!(base_weight, Staking::on_initialize(0));
});
ExtBuilder::default()
.offchain_election_ext()
.validator_count(4)
.has_stakers(false)
.build()
.execute_with(|| {
crate::tests::offchain_election::build_offchain_election_test_ext();
run_to_block(11);
Staking::on_finalize(System::block_number());
System::set_block_number((System::block_number() + 1).into());
Timestamp::set_timestamp(System::block_number() * 1000 + INIT_TIMESTAMP);
Session::on_initialize(System::block_number());
assert_eq!(Validators::<Test>::iter().count(), 4);
assert_eq!(Nominators::<Test>::iter().count(), 5);
// With 4 validators and 5 nominator, we should increase weight by:
// - (4 + 5) reads
// - 3 Writes
let final_weight = <Test as frame_system::Config>::DbWeight::get().reads_writes(4 + 9, 3);
assert_eq!(final_weight, Staking::on_initialize(System::block_number()));
});
}
#[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]
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
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() {
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
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() {
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
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,
);
})
}