Skip to content
tests.rs 146 KiB
Newer Older
Gavin Wood's avatar
Gavin Wood committed
		assert_noop!(
			Staking::payout_stakers(Origin::signed(1337), 11, 2),
Gavin Wood's avatar
Gavin Wood committed
			// Fail: Double claim
			Error::<Test>::AlreadyClaimed
Gavin Wood's avatar
Gavin Wood committed
		);
		assert_noop!(
			Staking::payout_stakers(Origin::signed(1337), 11, active_era),
Gavin Wood's avatar
Gavin Wood committed
			// Fail: Era not finished yet
			Error::<Test>::InvalidEraToReward
		);
Gavin Wood's avatar
Gavin Wood committed
		// 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_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);
	});
}
Gavin Wood's avatar
Gavin Wood committed

#[test]
fn six_session_delay() {
	ExtBuilder::default().build_and_execute(|| {
Gavin Wood's avatar
Gavin Wood committed
		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!(Staking::active_era().unwrap().index, init_active_era);
		<Staking as SessionManager<_>>::end_session(init_session + 1);
		<Staking as SessionManager<_>>::start_session(init_session + 2);
		assert_eq!(Staking::active_era().unwrap().index, 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!(Staking::active_era().unwrap().index, init_active_era + 1);
		<Staking as SessionManager<_>>::end_session(init_session + 3);
		<Staking as SessionManager<_>>::start_session(init_session + 4);
		assert_eq!(Staking::active_era().unwrap().index, init_active_era + 1);
		<Staking as SessionManager<_>>::end_session(init_session + 4);
		<Staking as SessionManager<_>>::start_session(init_session + 5);
		assert_eq!(Staking::active_era().unwrap().index, 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!(Staking::active_era().unwrap().index, 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() {
	// Test:
	// * If nominator nomination is below the $MaxNominatorRewardedPerValidator other nominator
	//   then the nominator can't claim its reward
	// * A nominator can't claim another nominator reward
	ExtBuilder::default().build_and_execute(|| {
Gavin Wood's avatar
Gavin Wood committed
		for i in 0..=<Test as Trait>::MaxNominatorRewardedPerValidator::get() {
			let stash = 10_000 + i as AccountId;
			let controller = 20_000 + i as AccountId;
			let balance = 10_000 + i as Balance;
Gavin Wood's avatar
Gavin Wood committed
			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_era(1);

		<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(3 * 1000);
		assert!(total_payout_0 > 100); // Test is meaningful if reward something

		mock::start_era(2);
		mock::make_all_reward_payment(1);

		// Assert only nominators from 1 to Max are rewarded
		for i in 0..=<Test as Trait>::MaxNominatorRewardedPerValidator::get() {
			let stash = 10_000 + i as AccountId;
			let balance = 10_000 + i as Balance;
Gavin Wood's avatar
Gavin Wood committed
			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_era(10);
		Staking::set_history_depth(Origin::ROOT, 20, 0).unwrap();
Gavin Wood's avatar
Gavin Wood committed
		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();
Gavin Wood's avatar
Gavin Wood committed
		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();
Gavin Wood's avatar
Gavin Wood committed
		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();
Gavin Wood's avatar
Gavin Wood committed
		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(|| {
		let balance = 1000;
		// Create three validators:
		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_era(1);
		Staking::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(3 * 1000);
		assert!(total_payout_0 > 100); // Test is meaningful if reward something
		mock::start_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 total payout now for whole duration as other parameter won't change
			let total_payout_0 = current_total_payout_for_duration(3 * 1000);
			assert!(total_payout_0 > 100); // Test is meaningful if reward something
			mock::start_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 total payout now for whole duration as other parameter won't change
			let total_payout_0 = current_total_payout_for_duration(3 * 1000);
			assert!(total_payout_0 > 100); // Test is meaningful if reward something
			mock::start_era(i);
		}

		// 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_era(1);
		Staking::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(3 * 1000);
		assert!(total_payout_0 > 100); // Test is meaningful if reward something
		mock::start_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 total payout now for whole duration as other parameter won't change
			let total_payout_0 = current_total_payout_for_duration(3 * 1000);
			assert!(total_payout_0 > 100); // Test is meaningful if reward something
			mock::start_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_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_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(),
			})
		);
	});
}

/* These migration tests below can be removed once migration code is removed */

#[test]
fn rewards_should_work_before_migration() {
	// should check that before migration:
	// * rewards get recorded per session
	// * rewards get paid per Era
	// * Check that nominators are also rewarded
	ExtBuilder::default().nominate(true).build_and_execute(|| {
		MigrateEra::put(10);
		let init_balance_10 = Balances::total_balance(&10);
		let init_balance_11 = Balances::total_balance(&11);
		let init_balance_20 = Balances::total_balance(&20);
		let init_balance_21 = Balances::total_balance(&21);
		let init_balance_100 = Balances::total_balance(&100);
		let init_balance_101 = Balances::total_balance(&101);

		// Check state
		Payee::<Test>::insert(11, RewardDestination::Controller);
		Payee::<Test>::insert(21, RewardDestination::Controller);
		Payee::<Test>::insert(101, RewardDestination::Controller);

		<Module<Test>>::reward_by_ids(vec![(11, 50)]);
		<Module<Test>>::reward_by_ids(vec![(11, 50)]);
		// This is the second validator of the current elected set.
		<Module<Test>>::reward_by_ids(vec![(21, 50)]);

		// Compute total payout now for whole duration as other parameter won't change
		let total_payout_0 = current_total_payout_for_duration(3 * 1000);
		assert!(total_payout_0 > 10); // Test is meaningful if reward something

		start_session(1);

		assert_eq!(Balances::total_balance(&10), init_balance_10);
		assert_eq!(Balances::total_balance(&11), init_balance_11);
		assert_eq!(Balances::total_balance(&20), init_balance_20);
		assert_eq!(Balances::total_balance(&21), init_balance_21);
		assert_eq!(Balances::total_balance(&100), init_balance_100);
		assert_eq!(Balances::total_balance(&101), init_balance_101);
		assert_eq_uvec!(Session::validators(), vec![11, 21]);
		assert_eq!(Staking::eras_reward_points(Staking::active_era().unwrap().index), EraRewardPoints {
			total: 50*3,
			individual: vec![(11, 100), (21, 50)].into_iter().collect(),
		});
		let part_for_10 = Perbill::from_rational_approximation::<u32>(1000, 1125);
		let part_for_20 = Perbill::from_rational_approximation::<u32>(1000, 1375);
		let part_for_100_from_10 = Perbill::from_rational_approximation::<u32>(125, 1125);
		let part_for_100_from_20 = Perbill::from_rational_approximation::<u32>(375, 1375);

		start_session(2);
		start_session(3);

		assert_eq!(Staking::active_era().unwrap().index, 1);
		mock::make_all_reward_payment_before_migration(0);

		assert_eq_error_rate!(Balances::total_balance(&10), init_balance_10 + part_for_10 * total_payout_0*2/3, 2);
		assert_eq_error_rate!(Balances::total_balance(&11), init_balance_11, 2);
		assert_eq_error_rate!(Balances::total_balance(&20), init_balance_20 + part_for_20 * total_payout_0*1/3, 2);
		assert_eq_error_rate!(Balances::total_balance(&21), init_balance_21, 2);
		assert_eq_error_rate!(
			Balances::total_balance(&100),
			init_balance_100
				+ part_for_100_from_10 * total_payout_0 * 2/3
				+ part_for_100_from_20 * total_payout_0 * 1/3,
			2
		);
		assert_eq_error_rate!(Balances::total_balance(&101), init_balance_101, 2);

		assert_eq_uvec!(Session::validators(), vec![11, 21]);
		<Module<Test>>::reward_by_ids(vec![(11, 1)]);

		// Compute total payout now for whole duration as other parameter won't change
		let total_payout_1 = current_total_payout_for_duration(3 * 1000);
		assert!(total_payout_1 > 10); // Test is meaningful if reward something

		mock::start_era(2);
		mock::make_all_reward_payment_before_migration(1);

		assert_eq_error_rate!(Balances::total_balance(&10), init_balance_10 + part_for_10 * (total_payout_0 * 2/3 + total_payout_1), 2);
		assert_eq_error_rate!(Balances::total_balance(&11), init_balance_11, 2);
		assert_eq_error_rate!(Balances::total_balance(&20), init_balance_20 + part_for_20 * total_payout_0 * 1/3, 2);
		assert_eq_error_rate!(Balances::total_balance(&21), init_balance_21, 2);
		assert_eq_error_rate!(
			Balances::total_balance(&100),
			init_balance_100
				+ part_for_100_from_10 * (total_payout_0 * 2/3 + total_payout_1)
				+ part_for_100_from_20 * total_payout_0 * 1/3,
			2
		);
		assert_eq_error_rate!(Balances::total_balance(&101), init_balance_101, 2);
	});
}

#[test]
fn migrate_era_should_work() {
	// should check that before and after migration:
	// * rewards get recorded per session
	// * rewards get paid per Era
	// * Check that nominators are also rewarded
	ExtBuilder::default().nominate(true).build_and_execute(|| {
		MigrateEra::put(1);
		let init_balance_10 = Balances::total_balance(&10);
		let init_balance_11 = Balances::total_balance(&11);
		let init_balance_20 = Balances::total_balance(&20);
		let init_balance_21 = Balances::total_balance(&21);
		let init_balance_100 = Balances::total_balance(&100);
		let init_balance_101 = Balances::total_balance(&101);

		// Check state
		Payee::<Test>::insert(11, RewardDestination::Controller);
		Payee::<Test>::insert(21, RewardDestination::Controller);
		Payee::<Test>::insert(101, RewardDestination::Controller);

		<Module<Test>>::reward_by_ids(vec![(11, 50)]);
		<Module<Test>>::reward_by_ids(vec![(11, 50)]);
		// This is the second validator of the current elected set.
		<Module<Test>>::reward_by_ids(vec![(21, 50)]);

		// Compute total payout now for whole duration as other parameter won't change
		let total_payout_0 = current_total_payout_for_duration(3 * 1000);
		assert!(total_payout_0 > 10); // Test is meaningful if reward something

		start_session(1);

		assert_eq!(Balances::total_balance(&10), init_balance_10);
		assert_eq!(Balances::total_balance(&11), init_balance_11);
		assert_eq!(Balances::total_balance(&20), init_balance_20);
		assert_eq!(Balances::total_balance(&21), init_balance_21);
		assert_eq!(Balances::total_balance(&100), init_balance_100);
		assert_eq!(Balances::total_balance(&101), init_balance_101);
		assert_eq_uvec!(Session::validators(), vec![11, 21]);
		assert_eq!(Staking::eras_reward_points(Staking::active_era().unwrap().index), EraRewardPoints {
			total: 50*3,
			individual: vec![(11, 100), (21, 50)].into_iter().collect(),
		});
		let part_for_10 = Perbill::from_rational_approximation::<u32>(1000, 1125);
		let part_for_20 = Perbill::from_rational_approximation::<u32>(1000, 1375);
		let part_for_100_from_10 = Perbill::from_rational_approximation::<u32>(125, 1125);
		let part_for_100_from_20 = Perbill::from_rational_approximation::<u32>(375, 1375);

		start_session(2);
		start_session(3);

		assert_eq!(Staking::active_era().unwrap().index, 1);
		mock::make_all_reward_payment_before_migration(0);

		assert_eq_error_rate!(Balances::total_balance(&10), init_balance_10 + part_for_10 * total_payout_0*2/3, 2);
		assert_eq_error_rate!(Balances::total_balance(&11), init_balance_11, 2);
		assert_eq_error_rate!(Balances::total_balance(&20), init_balance_20 + part_for_20 * total_payout_0*1/3, 2);
		assert_eq_error_rate!(Balances::total_balance(&21), init_balance_21, 2);
		assert_eq_error_rate!(
			Balances::total_balance(&100),
			init_balance_100
				+ part_for_100_from_10 * total_payout_0 * 2/3
				+ part_for_100_from_20 * total_payout_0 * 1/3,
			2
		);
		assert_eq_error_rate!(Balances::total_balance(&101), init_balance_101, 2);

		assert_eq_uvec!(Session::validators(), vec![11, 21]);
		<Module<Test>>::reward_by_ids(vec![(11, 1)]);

		// Compute total payout now for whole duration as other parameter won't change
		let total_payout_1 = current_total_payout_for_duration(3 * 1000);
		assert!(total_payout_1 > 10); // Test is meaningful if reward something

		mock::start_era(2);
		mock::make_all_reward_payment(1);

		assert_eq_error_rate!(Balances::total_balance(&10), init_balance_10 + part_for_10 * (total_payout_0 * 2/3 + total_payout_1), 2);
		assert_eq_error_rate!(Balances::total_balance(&11), init_balance_11, 2);
		assert_eq_error_rate!(Balances::total_balance(&20), init_balance_20 + part_for_20 * total_payout_0 * 1/3, 2);
		assert_eq_error_rate!(Balances::total_balance(&21), init_balance_21, 2);
		assert_eq_error_rate!(
			Balances::total_balance(&100),
			init_balance_100
				+ part_for_100_from_10 * (total_payout_0 * 2/3 + total_payout_1)
				+ part_for_100_from_20 * total_payout_0 * 1/3,
			2
		);
		assert_eq_error_rate!(Balances::total_balance(&101), init_balance_101, 2);
	});
}

#[test]
#[should_panic]
fn migrate_era_should_handle_error() {
	ExtBuilder::default().nominate(true).build_and_execute(|| {
		MigrateEra::put(1);
		let init_balance_10 = Balances::total_balance(&10);
		let init_balance_11 = Balances::total_balance(&11);
		let init_balance_20 = Balances::total_balance(&20);
		let init_balance_21 = Balances::total_balance(&21);
		let init_balance_100 = Balances::total_balance(&100);
		let init_balance_101 = Balances::total_balance(&101);

		// Check state
		Payee::<Test>::insert(11, RewardDestination::Controller);
		Payee::<Test>::insert(21, RewardDestination::Controller);
		Payee::<Test>::insert(101, RewardDestination::Controller);

		<Module<Test>>::reward_by_ids(vec![(11, 50)]);
		<Module<Test>>::reward_by_ids(vec![(11, 50)]);
		// This is the second validator of the current elected set.
		<Module<Test>>::reward_by_ids(vec![(21, 50)]);

		// Compute total payout now for whole duration as other parameter won't change
		let total_payout_0 = current_total_payout_for_duration(3 * 1000);
		assert!(total_payout_0 > 10); // Test is meaningful if reward something

		start_session(1);

		assert_eq!(Balances::total_balance(&10), init_balance_10);
		assert_eq!(Balances::total_balance(&11), init_balance_11);
		assert_eq!(Balances::total_balance(&20), init_balance_20);
		assert_eq!(Balances::total_balance(&21), init_balance_21);
		assert_eq!(Balances::total_balance(&100), init_balance_100);
		assert_eq!(Balances::total_balance(&101), init_balance_101);
		assert_eq_uvec!(Session::validators(), vec![11, 21]);
		assert_eq!(Staking::eras_reward_points(Staking::active_era().unwrap().index), EraRewardPoints {
			total: 50*3,
			individual: vec![(11, 100), (21, 50)].into_iter().collect(),
		});

		start_session(2);
		start_session(3);

		assert_eq!(Staking::active_era().unwrap().index, 1);
		mock::make_all_reward_payment(0);
	});
}

#[test]
#[should_panic]
fn migrate_era_should_handle_errors_2() {
	// should check that before and after migration:
	// * rewards get recorded per session
	// * rewards get paid per Era
	// * Check that nominators are also rewarded
	ExtBuilder::default().nominate(true).build_and_execute(|| {
		MigrateEra::put(1);
		let init_balance_10 = Balances::total_balance(&10);
		let init_balance_11 = Balances::total_balance(&11);
		let init_balance_20 = Balances::total_balance(&20);
		let init_balance_21 = Balances::total_balance(&21);
		let init_balance_100 = Balances::total_balance(&100);
		let init_balance_101 = Balances::total_balance(&101);

		// Check state
		Payee::<Test>::insert(11, RewardDestination::Controller);
		Payee::<Test>::insert(21, RewardDestination::Controller);
		Payee::<Test>::insert(101, RewardDestination::Controller);

		<Module<Test>>::reward_by_ids(vec![(11, 50)]);
		<Module<Test>>::reward_by_ids(vec![(11, 50)]);
		// This is the second validator of the current elected set.
		<Module<Test>>::reward_by_ids(vec![(21, 50)]);

		// Compute total payout now for whole duration as other parameter won't change
		let total_payout_0 = current_total_payout_for_duration(3 * 1000);
		assert!(total_payout_0 > 10); // Test is meaningful if reward something

		start_session(1);

		assert_eq!(Balances::total_balance(&10), init_balance_10);
		assert_eq!(Balances::total_balance(&11), init_balance_11);
		assert_eq!(Balances::total_balance(&20), init_balance_20);
		assert_eq!(Balances::total_balance(&21), init_balance_21);
		assert_eq!(Balances::total_balance(&100), init_balance_100);
		assert_eq!(Balances::total_balance(&101), init_balance_101);
		assert_eq_uvec!(Session::validators(), vec![11, 21]);
		assert_eq!(Staking::eras_reward_points(Staking::active_era().unwrap().index), EraRewardPoints {
			total: 50*3,
			individual: vec![(11, 100), (21, 50)].into_iter().collect(),
		});
		let part_for_10 = Perbill::from_rational_approximation::<u32>(1000, 1125);
		let part_for_20 = Perbill::from_rational_approximation::<u32>(1000, 1375);
		let part_for_100_from_10 = Perbill::from_rational_approximation::<u32>(125, 1125);
		let part_for_100_from_20 = Perbill::from_rational_approximation::<u32>(375, 1375);

		start_session(2);
		start_session(3);

		assert_eq!(Staking::active_era().unwrap().index, 1);
		mock::make_all_reward_payment_before_migration(0);

		assert_eq_error_rate!(Balances::total_balance(&10), init_balance_10 + part_for_10 * total_payout_0*2/3, 2);
		assert_eq_error_rate!(Balances::total_balance(&11), init_balance_11, 2);
		assert_eq_error_rate!(Balances::total_balance(&20), init_balance_20 + part_for_20 * total_payout_0*1/3, 2);
		assert_eq_error_rate!(Balances::total_balance(&21), init_balance_21, 2);
		assert_eq_error_rate!(
			Balances::total_balance(&100),
			init_balance_100
				+ part_for_100_from_10 * total_payout_0 * 2/3
				+ part_for_100_from_20 * total_payout_0 * 1/3,
			2
		);
		assert_eq_error_rate!(Balances::total_balance(&101), init_balance_101, 2);

		assert_eq_uvec!(Session::validators(), vec![11, 21]);
		<Module<Test>>::reward_by_ids(vec![(11, 1)]);

		// Compute total payout now for whole duration as other parameter won't change
		let total_payout_1 = current_total_payout_for_duration(3 * 1000);
		assert!(total_payout_1 > 10); // Test is meaningful if reward something

		mock::start_era(2);
		mock::make_all_reward_payment_before_migration(1);

		assert_eq_error_rate!(Balances::total_balance(&10), init_balance_10 + part_for_10 * (total_payout_0 * 2/3 + total_payout_1), 2);
		assert_eq_error_rate!(Balances::total_balance(&11), init_balance_11, 2);
		assert_eq_error_rate!(Balances::total_balance(&20), init_balance_20 + part_for_20 * total_payout_0 * 1/3, 2);
		assert_eq_error_rate!(Balances::total_balance(&21), init_balance_21, 2);
		assert_eq_error_rate!(
			Balances::total_balance(&100),
			init_balance_100
				+ part_for_100_from_10 * (total_payout_0 * 2/3 + total_payout_1)
				+ part_for_100_from_20 * total_payout_0 * 1/3,
			2
		);
		assert_eq_error_rate!(Balances::total_balance(&101), init_balance_101, 2);
	});
}

#[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::Trait>::DbWeight::get().reads(4);
		assert_eq!(base_weight, Staking::on_initialize(0));
	});

	ExtBuilder::default()
	.offchain_phragmen_ext()
	.validator_count(4)
	.has_stakers(false)
	.build()
	.execute_with(|| {
		crate::tests::offchain_phragmen::build_offchain_phragmen_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::Trait>::DbWeight::get().reads_writes(4 + 9, 3);
		assert_eq!(final_weight, Staking::on_initialize(System::block_number()));
	});
}