Skip to content
tests.rs 211 KiB
Newer Older
			bond_nominator(1000 + i, bond_amount, vec![11]);
			// with multi page reward payout, payout exposure is same as total exposure.
			total_exposure += bond_amount;
		mock::start_active_era(1);
		Staking::reward_by_ids(vec![(11, 1)]);

		// Since `MaxExposurePageSize = 64`, there are two pages of validator exposure.
		assert_eq!(EraInfo::<Test>::get_page_count(1, &11), 2);

		// compute and ensure the reward amount is greater than zero.
		let payout = current_total_payout_for_duration(reward_time_per_era());
		mock::start_active_era(2);

		// verify the exposures are calculated correctly.
		let actual_exposure_0 = EraInfo::<Test>::get_paged_exposure(1, &11, 0).unwrap();
		assert_eq!(actual_exposure_0.total(), total_exposure);
		assert_eq!(actual_exposure_0.own(), 1000);
		assert_eq!(actual_exposure_0.others().len(), 64);
		let actual_exposure_1 = EraInfo::<Test>::get_paged_exposure(1, &11, 1).unwrap();
		assert_eq!(actual_exposure_1.total(), total_exposure);
		// own stake is only included once in the first page
		assert_eq!(actual_exposure_1.own(), 0);
		assert_eq!(actual_exposure_1.others().len(), 100 - 64);

		let pre_payout_total_issuance = Balances::total_issuance();
		RewardOnUnbalanceWasCalled::set(false);

		let controller_balance_before_p0_payout = Balances::free_balance(&11);
		// Payout rewards for first exposure page
		assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1));
		// page 0 is claimed
		assert_noop!(
			Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0),
			Error::<Test>::AlreadyClaimed.with_weight(err_weight)
		);

		let controller_balance_after_p0_payout = Balances::free_balance(&11);

		// verify rewards have been paid out but still some left
		assert!(Balances::total_issuance() > pre_payout_total_issuance);
		assert!(Balances::total_issuance() < pre_payout_total_issuance + payout);

		// verify the validator has been rewarded
		assert!(controller_balance_after_p0_payout > controller_balance_before_p0_payout);

		// This should payout the second and last page of nominators
		assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1));

		// cannot claim any more pages
		assert_noop!(
			Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1),
			Error::<Test>::AlreadyClaimed.with_weight(err_weight)
		);

		// verify the validator was not rewarded the second time
		assert_eq!(Balances::free_balance(&11), controller_balance_after_p0_payout);

		// verify all rewards have been paid out
		assert_eq_error_rate!(Balances::total_issuance(), pre_payout_total_issuance + payout, 2);
		assert!(RewardOnUnbalanceWasCalled::get());

		// verify all nominators of validator 11 are paid out, including the validator
		// Validator payout goes to controller.
		assert!(Balances::free_balance(&11) > balance);
		for i in 0..100 {
			assert!(Balances::free_balance(&(1000 + i)) > balance + i as Balance);
		}

		// verify we no longer track rewards in `legacy_claimed_rewards` vec
		let ledger = Staking::ledger(11.into());
		assert_eq!(
			Staking::ledger(11.into()).unwrap(),
			StakingLedgerInspect {
				stash: 11,
				total: 1000,
				active: 1000,
				unlocking: Default::default(),
				legacy_claimed_rewards: bounded_vec![]
		// verify rewards are tracked to prevent double claims
		for page in 0..EraInfo::<Test>::get_page_count(1, &11) {
			assert_eq!(
				EraInfo::<Test>::is_rewards_claimed_with_legacy_fallback(
					1,
					ledger.as_ref().unwrap(),
					&11,
					page
				),
				true
			);
		}

		for i in 3..16 {
			Staking::reward_by_ids(vec![(11, 1)]);

			// compute and ensure the reward amount is greater than zero.
			let payout = current_total_payout_for_duration(reward_time_per_era());
			let pre_payout_total_issuance = Balances::total_issuance();

			mock::start_active_era(i);
			RewardOnUnbalanceWasCalled::set(false);
			mock::make_all_reward_payment(i - 1);
			assert_eq_error_rate!(
				Balances::total_issuance(),
				pre_payout_total_issuance + payout,
				2
			);
			assert!(RewardOnUnbalanceWasCalled::get());

			// verify we track rewards for each era and page
			for page in 0..EraInfo::<Test>::get_page_count(i - 1, &11) {
				assert_eq!(
					EraInfo::<Test>::is_rewards_claimed_with_legacy_fallback(
						i - 1,
						Staking::ledger(11.into()).as_ref().unwrap(),
						&11,
						page
					),
					true
				);
			}
		}

		assert_eq!(Staking::claimed_rewards(14, &11), vec![0, 1]);

		let last_era = 99;
		let history_depth = HistoryDepth::get();
		let last_reward_era = last_era - 1;
		let first_claimable_reward_era = last_era - history_depth;
		for i in 16..=last_era {
			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);
		// verify we clean up history as we go
		for era in 0..15 {
			assert_eq!(Staking::claimed_rewards(era, &11), Vec::<sp_staking::Page>::new());
		}

		// verify only page 0 is marked as claimed
		assert_ok!(Staking::payout_stakers(
			RuntimeOrigin::signed(1337),
			11,
		assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0]);

		// verify page 0 and 1 are marked as claimed
		assert_ok!(Staking::payout_stakers(
			RuntimeOrigin::signed(1337),
			11,
		assert_eq!(Staking::claimed_rewards(first_claimable_reward_era, &11), vec![0, 1]);

		// change order and verify only page 1 is marked as claimed
		assert_ok!(Staking::payout_stakers_by_page(
			RuntimeOrigin::signed(1337),
			11,
			last_reward_era,
			1
		));
		assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![1]);

		// verify page 0 is claimed even when explicit page is not passed
		assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era,));

		assert_eq!(Staking::claimed_rewards(last_reward_era, &11), vec![1, 0]);

		// cannot claim any more pages
		assert_noop!(
			Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, last_reward_era),
			Error::<Test>::AlreadyClaimed.with_weight(err_weight)
		// Create 4 nominator pages
		for i in 100..200 {
			let bond_amount = balance + i as Balance;
			bond_nominator(1000 + i, bond_amount, vec![11]);
		}

		let test_era = last_era + 1;
		mock::start_active_era(test_era);

		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(test_era + 1);

		// Out of order claims works.
		assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, test_era, 2));
		assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2]);

		assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era));
		assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0]);

		// cannot claim page 2 again
		assert_noop!(
			Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, test_era, 2),
			Error::<Test>::AlreadyClaimed.with_weight(err_weight)

		assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era));
		assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0, 1]);

		assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, test_era));
		assert_eq!(Staking::claimed_rewards(test_era, &11), vec![2, 0, 1, 3]);
	});
}

#[test]
fn test_page_count_and_size() {
	// Test that payout_stakers work in general and that it pays the correct amount of reward.
	ExtBuilder::default().has_stakers(false).build_and_execute(|| {
		let balance = 1000;
		// Track the exposure of the validator and all nominators.
		// Create a validator:
		bond_validator(11, balance); // Default(64)
		assert_eq!(Validators::<Test>::count(), 1);

		// Create nominators, targeting stash of validators
		for i in 0..100 {
			let bond_amount = balance + i as Balance;
			bond_nominator(1000 + i, bond_amount, vec![11]);
		}

		mock::start_active_era(1);

		// Since max exposure page size is 64, 2 pages of nominators are created.
		assert_eq!(EraInfo::<Test>::get_page_count(1, &11), 2);

		// first page has 64 nominators
		assert_eq!(EraInfo::<Test>::get_paged_exposure(1, &11, 0).unwrap().others().len(), 64);
		// second page has 36 nominators
		assert_eq!(EraInfo::<Test>::get_paged_exposure(1, &11, 1).unwrap().others().len(), 36);

		// now lets decrease page size
		MaxExposurePageSize::set(32);
		mock::start_active_era(2);
		// now we expect 4 pages.
		assert_eq!(EraInfo::<Test>::get_page_count(2, &11), 4);
		// first 3 pages have 32 nominators each
		assert_eq!(EraInfo::<Test>::get_paged_exposure(2, &11, 0).unwrap().others().len(), 32);
		assert_eq!(EraInfo::<Test>::get_paged_exposure(2, &11, 1).unwrap().others().len(), 32);
		assert_eq!(EraInfo::<Test>::get_paged_exposure(2, &11, 2).unwrap().others().len(), 32);
		assert_eq!(EraInfo::<Test>::get_paged_exposure(2, &11, 3).unwrap().others().len(), 4);

		// now lets decrease page size even more
		MaxExposurePageSize::set(5);
		mock::start_active_era(3);

		// now we expect the max 20 pages (100/5).
		assert_eq!(EraInfo::<Test>::get_page_count(3, &11), 20);
	});
}

#[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 = <Test as Config>::WeightInfo::payout_stakers_alive_staked(0);
		// Same setup as the test above
		let balance = 1000;
		bond_validator(11, balance); // Default(64)

		// Create nominators, targeting stash
		for i in 0..100 {
			bond_nominator(1000 + i, balance + i as Balance, vec![11]);
		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);

		// Wrong Era, too big
			Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 2, 0),
			Error::<Test>::InvalidEraToReward.with_weight(err_weight)
		);
		// Wrong Staker
			Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 10, 1, 0),
			Error::<Test>::NotStash.with_weight(err_weight)
		);
		let last_era = 99;
		for i in 3..=last_era {
			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);

		let history_depth = HistoryDepth::get();
		let expected_last_reward_era = last_era - 1;
		let expected_start_reward_era = last_era - history_depth;

		// We are at era last_era=99. Given history_depth=80, we should be able
		// to payout era starting from expected_start_reward_era=19 through
		// expected_last_reward_era=98 (80 total eras), but not 18 or 99.
			Staking::payout_stakers_by_page(
				RuntimeOrigin::signed(1337),
				11,
				expected_start_reward_era - 1,
				0
			),
			Error::<Test>::InvalidEraToReward.with_weight(err_weight)
		);
		assert_noop!(
			Staking::payout_stakers_by_page(
				RuntimeOrigin::signed(1337),
				11,
				expected_last_reward_era + 1,
				0
			),
			Error::<Test>::InvalidEraToReward.with_weight(err_weight)
		);
		assert_ok!(Staking::payout_stakers_by_page(
			RuntimeOrigin::signed(1337),
			11,
		assert_ok!(Staking::payout_stakers_by_page(
			RuntimeOrigin::signed(1337),
			11,
			expected_last_reward_era,
			0
		));

		// can call page 1
		assert_ok!(Staking::payout_stakers_by_page(
			RuntimeOrigin::signed(1337),
			11,

		// Can't claim again
			Staking::payout_stakers_by_page(
				RuntimeOrigin::signed(1337),
				11,
				expected_start_reward_era,
				0
			),
			Error::<Test>::AlreadyClaimed.with_weight(err_weight)
		);

		assert_noop!(
			Staking::payout_stakers_by_page(
				RuntimeOrigin::signed(1337),
				11,
				expected_last_reward_era,
				0
			),
			Error::<Test>::AlreadyClaimed.with_weight(err_weight)
		);
			Staking::payout_stakers_by_page(
				RuntimeOrigin::signed(1337),
				11,
				expected_last_reward_era,
				1
			),
			Error::<Test>::AlreadyClaimed.with_weight(err_weight)
		);

		// invalid page
		assert_noop!(
			Staking::payout_stakers_by_page(
				RuntimeOrigin::signed(1337),
				11,
				expected_last_reward_era,
				2
			),
			Error::<Test>::InvalidPage.with_weight(err_weight)
		);
	});
}

#[test]
fn test_commission_paid_across_pages() {
	ExtBuilder::default().has_stakers(false).build_and_execute(|| {
		let balance = 1;
		let commission = 50;
		// Create a validator:
		bond_validator(11, balance);
		assert_ok!(Staking::validate(
			RuntimeOrigin::signed(11),
			ValidatorPrefs { commission: Perbill::from_percent(commission), blocked: false }
		));
		assert_eq!(Validators::<Test>::count(), 1);

		// Create nominators, targeting stash of validators
		for i in 0..200 {
			let bond_amount = balance + i as Balance;
			bond_nominator(1000 + i, bond_amount, vec![11]);
		}

		mock::start_active_era(1);
		Staking::reward_by_ids(vec![(11, 1)]);

		// Since `MaxExposurePageSize = 64`, there are four pages of validator
		// exposure.
		assert_eq!(EraInfo::<Test>::get_page_count(1, &11), 4);

		// compute and ensure the reward amount is greater than zero.
		let payout = current_total_payout_for_duration(reward_time_per_era());
		mock::start_active_era(2);

		let initial_balance = Balances::free_balance(&11);
		// Payout rewards for first exposure page
		assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0));

		let controller_balance_after_p0_payout = Balances::free_balance(&11);

		// some commission is paid
		assert!(initial_balance < controller_balance_after_p0_payout);

		// payout all pages
		for i in 1..4 {
			let before_balance = Balances::free_balance(&11);
			assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, i));
			let after_balance = Balances::free_balance(&11);
			// some commission is paid for every page
			assert!(before_balance < after_balance);
		}

		assert_eq_error_rate!(Balances::free_balance(&11), initial_balance + payout / 2, 1,);
	});
}

#[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 = MaxExposurePageSize::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.any_gt(Weight::zero()));
		assert!(half_max_nom_rewarded_weight.any_gt(zero_nom_payouts_weight));
		assert!(max_nom_rewarded_weight.any_gt(half_max_nom_rewarded_weight));
		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(), balance + i as Balance, vec![11]);
		start_active_era(2);

		// Collect payouts when there are no nominators
		let call = TestCall::Staking(StakingCall::payout_stakers_by_page {
			validator_stash: 11,
			era: 1,
			page: 0,
		});
		let info = call.get_dispatch_info();
		let result = call.dispatch(RuntimeOrigin::signed(20));
		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.
		start_active_era(3);

		// Collect payouts for an era where the validator did not receive any points.
		let call = TestCall::Staking(StakingCall::payout_stakers_by_page {
			validator_stash: 11,
			era: 2,
			page: 0,
		});
		let info = call.get_dispatch_info();
		let result = call.dispatch(RuntimeOrigin::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)]);

		start_active_era(4);

		// Collect payouts when the validator has `half_max_nom_rewarded` nominators.
		let call = TestCall::Staking(StakingCall::payout_stakers_by_page {
			validator_stash: 11,
			era: 3,
			page: 0,
		});
		let info = call.get_dispatch_info();
		let result = call.dispatch(RuntimeOrigin::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(), balance + i as Balance, vec![11]);
		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)]);

		start_active_era(6);

		// Collect payouts when the validator had `half_max_nom_rewarded` nominators.
		let call = TestCall::Staking(StakingCall::payout_stakers_by_page {
			validator_stash: 11,
			era: 5,
			page: 0,
		});
		let info = call.get_dispatch_info();
		let result = call.dispatch(RuntimeOrigin::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 = TestCall::Staking(StakingCall::payout_stakers_by_page {
			validator_stash: 11,
			era: 5,
			page: 0,
		});
		let info = call.get_dispatch_info();
		let result = call.dispatch(RuntimeOrigin::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);
fn bond_during_era_does_not_populate_legacy_claimed_rewards() {
	ExtBuilder::default().has_stakers(false).build_and_execute(|| {
		// Era = None
		assert_eq!(
			Staking::ledger(9.into()).unwrap(),
			StakingLedgerInspect {
				stash: 9,
				total: 1000,
				active: 1000,
				unlocking: Default::default(),
				legacy_claimed_rewards: bounded_vec![],
		assert_eq!(
			Staking::ledger(11.into()).unwrap(),
			StakingLedgerInspect {
				stash: 11,
				total: 1000,
				active: 1000,
				unlocking: Default::default(),
				legacy_claimed_rewards: bounded_vec![],

		// make sure only era upto history depth is stored
		let current_era = 99;
		mock::start_active_era(current_era);
		assert_eq!(
			Staking::ledger(13.into()).unwrap(),
			StakingLedgerInspect {
				stash: 13,
				total: 1000,
				active: 1000,
				unlocking: Default::default(),
				legacy_claimed_rewards: Default::default(),
#[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, DisableStrategy::WhenSlashed),
			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(active_era(), &i)),
				reporters: vec![],
			})
			.collect();
		assert_eq!(
			Staking::on_offence(
				&offenders,
				&[Perbill::from_percent(50)],
				0,
				DisableStrategy::WhenSlashed
			),
			n_offence_unapplied_weight
		);

		// On Offence with one offenders, Applied
		let one_offender = [OffenceDetails {
			offender: (11, Staking::eras_stakers(active_era(), &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)
			// One `slash_cost`
			+ <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,
				DisableStrategy::WhenSlashed{}
			),
			one_offence_unapplied_weight
		);
#[test]
fn payout_creates_controller() {
	ExtBuilder::default().has_stakers(false).build_and_execute(|| {
		let balance = 1000;
		// Create a validator:
		// create a stash/controller pair and nominate
		let (stash, controller) = testing_utils::create_unique_stash_controller::<Test>(
			0,
			100,
			RewardDestination::Controller,
			false,
		)
		.unwrap();
		assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![11]));
		assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(controller), stash, 100));
		assert_eq!(Balances::free_balance(controller), 0);
		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_by_page(RuntimeOrigin::signed(1337), 11, 1, 0));

		// Controller is created
		assert!(Balances::free_balance(controller) > 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, balance); // Default(64)

		// Create a stash/controller pair
		bond_nominator(1234, 100, vec![11]);

		// Update payout location
		assert_ok!(Staking::set_payee(RuntimeOrigin::signed(1234), RewardDestination::Account(42)));

		// Reward Destination account doesn't exist
		assert_eq!(Balances::free_balance(42), 0);

		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_by_page(RuntimeOrigin::signed(1337), 11, 1, 0));

		// Payment is successful
		assert!(Balances::free_balance(42) > 0);
	})
}
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() {
		.existential_deposit(11)
		.balance_factor(11)
		.build_and_execute(|| {
			// initial stuff.
			assert_eq!(
				Staking::ledger(21.into()).unwrap(),
				StakingLedgerInspect {
					unlocking: Default::default(),
					legacy_claimed_rewards: bounded_vec![],
			// unbond all of it. must be chilled first.
			assert_ok!(Staking::chill(RuntimeOrigin::signed(21)));
			assert_ok!(Staking::unbond(RuntimeOrigin::signed(21), 11 * 1000));
				Staking::ledger(21.into()).unwrap(),
				StakingLedgerInspect {
					unlocking: bounded_vec![UnlockChunk { value: 11 * 1000, era: 3 }],
					legacy_claimed_rewards: bounded_vec![],
			assert_noop!(
				Staking::rebond(RuntimeOrigin::signed(21), 5),
				Error::<Test>::InsufficientBond
			);
fn cannot_bond_extra_to_lower_than_ed() {
		.existential_deposit(11)
		.balance_factor(11)
		.build_and_execute(|| {
			// initial stuff.
			assert_eq!(
				Staking::ledger(21.into()).unwrap(),
				StakingLedgerInspect {
					unlocking: Default::default(),
					legacy_claimed_rewards: bounded_vec![],
			// unbond all of it. must be chilled first.
			assert_ok!(Staking::chill(RuntimeOrigin::signed(21)));
			assert_ok!(Staking::unbond(RuntimeOrigin::signed(21), 11 * 1000));
				Staking::ledger(21.into()).unwrap(),
				StakingLedgerInspect {
					unlocking: bounded_vec![UnlockChunk { value: 11 * 1000, era: 3 }],
					legacy_claimed_rewards: bounded_vec![],
				Staking::bond_extra(RuntimeOrigin::signed(21), 5),
				Error::<Test>::InsufficientBond,

#[test]
fn do_not_die_when_active_is_ed() {
	let ed = 10;
	ExtBuilder::default()
		.existential_deposit(ed)
		.balance_factor(ed)
				Staking::ledger(21.into()).unwrap(),
				StakingLedgerInspect {
					total: 1000 * ed,
					active: 1000 * ed,
					unlocking: Default::default(),
					legacy_claimed_rewards: bounded_vec![],
			// when unbond all of it except ed.
			assert_ok!(Staking::unbond(RuntimeOrigin::signed(21), 999 * ed));
			assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(21), 100));
				Staking::ledger(21.into()).unwrap(),
				StakingLedgerInspect {
					unlocking: Default::default(),
					legacy_claimed_rewards: bounded_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).all_gte(on_finalize_weight));
mod election_data_provider {
	use super::*;
	use frame_election_provider_support::ElectionDataProvider;
	#[test]
	fn targets_2sec_block() {
		let mut validators = 1000;
		while <Test as Config>::WeightInfo::get_npos_targets(validators).all_lt(Weight::from_parts(
			2u64 * frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND,
			u64::MAX,
		)) {
			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;
		let mut nominators = 1000;