Skip to content
tests.rs 185 KiB
Newer Older
		// 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 { validator_stash: 11, era: 2 });
		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 { validator_stash: 11, era: 3 });
		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 { validator_stash: 11, era: 5 });
		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 { validator_stash: 11, era: 5 });
		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);
	});
}

#[test]
fn bond_during_era_correctly_populates_claimed_rewards() {
	ExtBuilder::default().has_stakers(false).build_and_execute(|| {
		// Era = None
		assert_eq!(
			Some(StakingLedger {
				stash: 9,
				total: 1000,
				active: 1000,
				unlocking: Default::default(),
				claimed_rewards: bounded_vec![],
		assert_eq!(
			Some(StakingLedger {
				stash: 11,
				total: 1000,
				active: 1000,
				unlocking: Default::default(),
				claimed_rewards: (0..5).collect::<Vec<_>>().try_into().unwrap(),

		// make sure only era upto history depth is stored
		let current_era = 99;
		let last_reward_era = 99 - HistoryDepth::get();
		mock::start_active_era(current_era);
		assert_eq!(
			Some(StakingLedger {
				stash: 13,
				total: 1000,
				active: 1000,
				unlocking: Default::default(),
				claimed_rewards: (last_reward_era..current_era)
					.collect::<Vec<_>>()
					.try_into()
					.unwrap(),
#[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(RuntimeOrigin::signed(controller), 11, 1));

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

		// 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!(
					unlocking: Default::default(),
					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));
					unlocking: bounded_vec![UnlockChunk { value: 11 * 1000, era: 3 }],
					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!(
					unlocking: Default::default(),
					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));
					unlocking: bounded_vec![UnlockChunk { value: 11 * 1000, era: 3 }],
					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)
					total: 1000 * ed,
					active: 1000 * ed,
					unlocking: Default::default(),
					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));
				StakingLedger {
					stash: 21,
					total: ed,
					active: ed,
					unlocking: Default::default(),
					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;

		while <Test as Config>::WeightInfo::get_npos_voters(validators, nominators).all_lt(
			Weight::from_parts(
				2u64 * frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND,
				u64::MAX,
			nominators += 1;
		}

		println!(
			"Can create a snapshot of {} nominators [{} validators, each 1 slashing] in 2sec block",
			nominators, validators
		);
	}

	#[test]
	fn set_minimum_active_stake_is_correct() {
		ExtBuilder::default()
			.nominate(false)
			.add_staker(61, 61, 2_000, StakerStatus::<AccountId>::Nominator(vec![21]))
			.add_staker(71, 71, 10, StakerStatus::<AccountId>::Nominator(vec![21]))
			.add_staker(81, 81, 50, StakerStatus::<AccountId>::Nominator(vec![21]))
				// default bounds are unbounded.
				assert_ok!(<Staking as ElectionDataProvider>::electing_voters(
					DataProviderBounds::default()
				));
				assert_eq!(MinimumActiveStake::<Test>::get(), 10);

				// remove staker with lower bond by limiting the number of voters and check
				// `MinimumActiveStake` again after electing voters.
				let bounds = ElectionBoundsBuilder::default().voters_count(5.into()).build();
				assert_ok!(<Staking as ElectionDataProvider>::electing_voters(bounds.voters));
				assert_eq!(MinimumActiveStake::<Test>::get(), 50);
			});
	}

	#[test]
	fn set_minimum_active_stake_lower_bond_works() {
		// if there are no voters, minimum active stake is zero (should not happen).
		ExtBuilder::default().has_stakers(false).build_and_execute(|| {
			// default bounds are unbounded.
			assert_ok!(<Staking as ElectionDataProvider>::electing_voters(
				DataProviderBounds::default()
			));
			assert_eq!(<Test as Config>::VoterList::count(), 0);
			assert_eq!(MinimumActiveStake::<Test>::get(), 0);
		});

		// lower non-zero active stake below `MinNominatorBond` is the minimum active stake if
		// it is selected as part of the npos voters.
		ExtBuilder::default().has_stakers(true).nominate(true).build_and_execute(|| {
			assert_eq!(MinNominatorBond::<Test>::get(), 1);
			assert_eq!(<Test as Config>::VoterList::count(), 4);

			assert_ok!(Staking::bond(RuntimeOrigin::signed(4), 5, Default::default(),));
			assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![1]));
			assert_eq!(<Test as Config>::VoterList::count(), 5);

			let voters_before =
				<Staking as ElectionDataProvider>::electing_voters(DataProviderBounds::default())
					.unwrap();
			assert_eq!(MinimumActiveStake::<Test>::get(), 5);

			// update minimum nominator bond.
			MinNominatorBond::<Test>::set(10);
			assert_eq!(MinNominatorBond::<Test>::get(), 10);
			// voter list still considers nominator 4 for voting, even though its active stake is
			// lower than `MinNominatorBond`.
			assert_eq!(<Test as Config>::VoterList::count(), 5);

			let voters =
				<Staking as ElectionDataProvider>::electing_voters(DataProviderBounds::default())
					.unwrap();
			assert_eq!(voters_before, voters);

			// minimum active stake is lower than `MinNominatorBond`.
			assert_eq!(MinimumActiveStake::<Test>::get(), 5);
		});
	}

	#[test]
	fn set_minimum_active_bond_corrupt_state() {
		ExtBuilder::default()
			.has_stakers(true)
			.nominate(true)
			.add_staker(61, 61, 2_000, StakerStatus::<AccountId>::Nominator(vec![21]))
			.build_and_execute(|| {
				assert_eq!(Staking::weight_of(&101), 500);
				let voters = <Staking as ElectionDataProvider>::electing_voters(
					DataProviderBounds::default(),
				)
				.unwrap();
				assert_eq!(voters.len(), 5);
				assert_eq!(MinimumActiveStake::<Test>::get(), 500);

				assert_ok!(Staking::unbond(RuntimeOrigin::signed(101), 200));
				start_active_era(10);
				assert_ok!(Staking::unbond(RuntimeOrigin::signed(101), 100));
				start_active_era(20);

				// corrupt ledger state by lowering max unlocking chunks bounds.
				MaxUnlockingChunks::set(1);

				let voters = <Staking as ElectionDataProvider>::electing_voters(
					DataProviderBounds::default(),
				)
				.unwrap();
				// number of returned voters decreases since ledger entry of stash 101 is now
				// corrupt.
				assert_eq!(voters.len(), 4);
				// minimum active stake does not take into consideration the corrupt entry.
				assert_eq!(MinimumActiveStake::<Test>::get(), 2_000);

				// voter weight of corrupted ledger entry is 0.
				assert_eq!(Staking::weight_of(&101), 0);

				// reset max unlocking chunks for try_state to pass.
				MaxUnlockingChunks::set(32);
			})
	#[test]
	fn voters_include_self_vote() {
		ExtBuilder::default().nominate(false).build_and_execute(|| {
			// default bounds are unbounded.
			assert!(<Validators<Test>>::iter().map(|(x, _)| x).all(|v| Staking::electing_voters(
				DataProviderBounds::default()
			)
			.unwrap()
			.into_iter()
			.any(|(w, _, t)| { v == w && t[0] == w })))
	// Tests the criteria that in `ElectionDataProvider::voters` function, we try to get at most
	// `maybe_max_len` voters, and if some of them end up being skipped, we iterate at most `2 *
	// maybe_max_len`.
	fn only_iterates_max_2_times_max_allowed_len() {
			// the best way to invalidate a bunch of nominators is to have them nominate a lot of
			// ppl, but then lower the MaxNomination limit.
			.add_staker(
				61,
				2_000,
				StakerStatus::<AccountId>::Nominator(vec![21, 22, 23, 24, 25]),
			)
			.add_staker(
				71,
				2_000,
				StakerStatus::<AccountId>::Nominator(vec![21, 22, 23, 24, 25]),
			)
			.add_staker(
				81,
				2_000,
				StakerStatus::<AccountId>::Nominator(vec![21, 22, 23, 24, 25]),
			)
				let bounds_builder = ElectionBoundsBuilder::default();
					<Test as Config>::VoterList::iter().collect::<Vec<_>>(),
					vec![61, 71, 81, 11, 21, 31]
				AbsoluteMaxNominations::set(2);
				// we want 2 voters now, and in maximum we allow 4 iterations. This is what happens:
				// 61 is pruned;
				// 71 is pruned;
				// 81 is pruned;
				// 11 is taken;
				// we finish since the 2x limit is reached.
					Staking::electing_voters(bounds_builder.voters_count(2.into()).build().voters)
						.unwrap()
						.iter()
						.map(|(stash, _, _)| stash)
						.copied()
						.collect::<Vec<_>>(),
	#[test]
	fn respects_snapshot_count_limits() {
		ExtBuilder::default()
			.set_status(41, StakerStatus::Validator)
			.build_and_execute(|| {
				// sum of all nominators who'd be voters (1), plus the self-votes (4).
				assert_eq!(<Test as Config>::VoterList::count(), 5);

				let bounds_builder = ElectionBoundsBuilder::default();

				// if voter count limit is less..
				assert_eq!(
					Staking::electing_voters(bounds_builder.voters_count(1.into()).build().voters)
						.unwrap()
						.len(),
					1
				);

				// if voter count limit is equal..
				assert_eq!(
					Staking::electing_voters(bounds_builder.voters_count(5.into()).build().voters)
						.unwrap()
						.len(),
					5
				);

				// if voter count limit is more.
				assert_eq!(
					Staking::electing_voters(bounds_builder.voters_count(55.into()).build().voters)
						.unwrap()
						.len(),
					5
				);

				// if target count limit is more..
				assert_eq!(
					Staking::electable_targets(
						bounds_builder.targets_count(6.into()).build().targets
					)
					.unwrap()
					.len(),
					4
				);

				// if target count limit is equal..
				assert_eq!(
					Staking::electable_targets(
						bounds_builder.targets_count(4.into()).build().targets
					)
					.unwrap()
					.len(),
					4
				);

				// if target limit count is less, then we return an error.
				assert_eq!(
					Staking::electable_targets(
						bounds_builder.targets_count(1.into()).build().targets
					)
					.unwrap_err(),
					"Target snapshot too big"
				);
			});
	}

	#[test]
	fn respects_snapshot_size_limits() {
		ExtBuilder::default().build_and_execute(|| {
			// voters: set size bounds that allows only for 1 voter.
			let bounds = ElectionBoundsBuilder::default().voters_size(26.into()).build();
			let elected = Staking::electing_voters(bounds.voters).unwrap();
			assert!(elected.encoded_size() == 26 as usize);
			let prev_len = elected.len();

			// larger size bounds means more quota for voters.
			let bounds = ElectionBoundsBuilder::default().voters_size(100.into()).build();
			let elected = Staking::electing_voters(bounds.voters).unwrap();
			assert!(elected.encoded_size() <= 100 as usize);
			assert!(elected.len() > 1 && elected.len() > prev_len);

			// targets: set size bounds that allows for only one target to fit in the snapshot.
			let bounds = ElectionBoundsBuilder::default().targets_size(10.into()).build();
			let elected = Staking::electable_targets(bounds.targets).unwrap();
			assert!(elected.encoded_size() == 9 as usize);
			let prev_len = elected.len();

			// larger size bounds means more space for targets.
			let bounds = ElectionBoundsBuilder::default().targets_size(100.into()).build();
			let elected = Staking::electable_targets(bounds.targets).unwrap();
			assert!(elected.encoded_size() <= 100 as usize);
			assert!(elected.len() > 1 && elected.len() > prev_len);
		});
	}

	#[test]
	fn nomination_quota_checks_at_nominate_works() {
		ExtBuilder::default().nominate(false).build_and_execute(|| {
			// stash bond of 222 has a nomination quota of 2 targets.
			bond(61, 222);
			assert_eq!(Staking::api_nominations_quota(222), 2);

			// nominating with targets below the nomination quota works.
			assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![11]));
			assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![11, 12]));

			// nominating with targets above the nomination quota returns error.
			assert_noop!(
				Staking::nominate(RuntimeOrigin::signed(61), vec![11, 12, 13]),
				Error::<Test>::TooManyTargets
			);
		});
	}

	#[test]
	fn lazy_quota_npos_voters_works_above_quota() {
		ExtBuilder::default()
			.nominate(false)
			.add_staker(
				61,
				60,
				300, // 300 bond has 16 nomination quota.
				StakerStatus::<AccountId>::Nominator(vec![21, 22, 23, 24, 25]),
			)
			.build_and_execute(|| {
				// unbond 78 from stash 60 so that it's bonded balance is 222, which has a lower
				// nomination quota than at nomination time (max 2 targets).
				assert_ok!(Staking::unbond(RuntimeOrigin::signed(61), 78));
				assert_eq!(Staking::api_nominations_quota(300 - 78), 2);

				// even through 61 has nomination quota of 2 at the time of the election, all the
				// nominations (5) will be used.
				assert_eq!(
					Staking::electing_voters(DataProviderBounds::default())
						.unwrap()
						.iter()
						.map(|(stash, _, targets)| (*stash, targets.len()))
						.collect::<Vec<_>>(),
					vec![(11, 1), (21, 1), (31, 1), (61, 5)],
				);
			});
	}

	#[test]
	fn nominations_quota_limits_size_work() {
		ExtBuilder::default()
			.nominate(false)
			.add_staker(
				71,
				70,
				333,
				StakerStatus::<AccountId>::Nominator(vec![16, 15, 14, 13, 12, 11, 10]),
			)
			.build_and_execute(|| {
				// nominations of controller 70 won't be added due to voter size limit exceeded.
				let bounds = ElectionBoundsBuilder::default().voters_size(100.into()).build();
				assert_eq!(
					Staking::electing_voters(bounds.voters)
						.unwrap()
						.iter()
						.map(|(stash, _, targets)| (*stash, targets.len()))
						.collect::<Vec<_>>(),
					vec![(11, 1), (21, 1), (31, 1)],
				);

				assert_eq!(
					*staking_events().last().unwrap(),
					Event::SnapshotVotersSizeExceeded { size: 75 }
				);

				// however, if the election voter size bounds were largers, the snapshot would
				// include the electing voters of 70.
				let bounds = ElectionBoundsBuilder::default().voters_size(1_000.into()).build();
				assert_eq!(
					Staking::electing_voters(bounds.voters)
						.unwrap()
						.iter()
						.map(|(stash, _, targets)| (*stash, targets.len()))
						.collect::<Vec<_>>(),
					vec![(11, 1), (21, 1), (31, 1), (71, 7)],
				);
			});
	}

	#[test]
	fn estimate_next_election_works() {
		ExtBuilder::default().session_per_era(5).period(5).build_and_execute(|| {
			// 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::StakersElected);

			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::StakersElected);
			Staking::force_no_eras(RuntimeOrigin::root()).unwrap();
			assert_eq!(Staking::next_election_prediction(System::block_number()), u64::MAX);
			Staking::force_new_era_always(RuntimeOrigin::root()).unwrap();
			assert_eq!(Staking::next_election_prediction(System::block_number()), 45 + 5);

			Staking::force_new_era(RuntimeOrigin::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);
			// The new era is still forced until a new era is planned.
			assert_eq!(ForceEra::<Test>::get(), Forcing::ForceNew);

			MinimumValidatorCount::<Test>::put(2);
			run_to_block(55);
			assert_eq!(Staking::next_election_prediction(System::block_number()), 55 + 25);
			assert_eq!(staking_events().len(), 10);
			assert_eq!(
				*staking_events().last().unwrap(),
				Event::ForceEra { mode: Forcing::NotForcing }
			);
			assert_eq!(
				*staking_events().get(staking_events().len() - 2).unwrap(),
				Event::StakersElected
			);
			// The new era has been planned, forcing is changed from `ForceNew` to `NotForcing`.
			assert_eq!(ForceEra::<Test>::get(), Forcing::NotForcing);
#[test]
#[should_panic]
fn count_check_works() {
	ExtBuilder::default().build_and_execute(|| {
		// We should never insert into the validators or nominators map directly as this will
		// not keep track of the count. This test should panic as we verify the count is accurate
		// after every test using the `post_checks` in `mock`.
		Validators::<Test>::insert(987654321, ValidatorPrefs::default());
		Nominators::<Test>::insert(
			987654321,
			Nominations {
				targets: Default::default(),
				submitted_in: Default::default(),
				suppressed: false,
			},
		);
	})
}

#[test]
fn min_bond_checks_work() {
	ExtBuilder::default()
		.existential_deposit(100)
		.balance_factor(100)
		.min_nominator_bond(1_000)
		.min_validator_bond(1_500)
		.build_and_execute(|| {
			// 500 is not enough for any role
			assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 500, RewardDestination::Controller));
			assert_noop!(
				Staking::nominate(RuntimeOrigin::signed(3), vec![1]),
				Error::<Test>::InsufficientBond
			);
			assert_noop!(
				Staking::validate(RuntimeOrigin::signed(3), ValidatorPrefs::default()),
				Error::<Test>::InsufficientBond,
			// 1000 is enough for nominator
			assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(3), 500));
			assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![1]));
			assert_noop!(
				Staking::validate(RuntimeOrigin::signed(3), ValidatorPrefs::default()),
				Error::<Test>::InsufficientBond,
			);
			// 1500 is enough for validator
			assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(3), 500));
			assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![1]));
			assert_ok!(Staking::validate(RuntimeOrigin::signed(3), ValidatorPrefs::default()));
			// Can't unbond anything as validator
			assert_noop!(
				Staking::unbond(RuntimeOrigin::signed(3), 500),
				Error::<Test>::InsufficientBond
			);
			// Once they are a nominator, they can unbond 500
			assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![1]));
			assert_ok!(Staking::unbond(RuntimeOrigin::signed(3), 500));
			assert_noop!(
				Staking::unbond(RuntimeOrigin::signed(3), 500),
				Error::<Test>::InsufficientBond
			);
			// Once they are chilled they can unbond everything
			assert_ok!(Staking::chill(RuntimeOrigin::signed(3)));
			assert_ok!(Staking::unbond(RuntimeOrigin::signed(3), 1000));
#[test]
fn chill_other_works() {
	ExtBuilder::default()
		.existential_deposit(100)