Skip to content
tests.rs 218 KiB
Newer Older
	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, RewardDestination::Staked,));
			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]
#[should_panic = "called `Result::unwrap()` on an `Err` value: Other(\"number of entries in payee storage items does not match the number of bonded ledgers\")"]
fn check_payee_invariant1_works() {
	// A bonded ledger should always have an assigned `Payee` This test should panic as we verify
	// that a bad state will panic due to the `try_state` checks in the `post_checks` in `mock`.
	ExtBuilder::default().build_and_execute(|| {
		let rogue_ledger = StakingLedger::<Test>::new(123456, 20);
		Ledger::<Test>::insert(123456, rogue_ledger);
	})
}

#[test]
#[should_panic = "called `Result::unwrap()` on an `Err` value: Other(\"number of entries in payee storage items does not match the number of bonded ledgers\")"]
fn check_payee_invariant2_works() {
	// The number of entries in both `Payee` and of bonded staking ledgers should match. This test
	// should panic as we verify that a bad state will panic due to the `try_state` checks in the
	// `post_checks` in `mock`.
	ExtBuilder::default().build_and_execute(|| {
		Payee::<Test>::insert(1111, RewardDestination::Staked);
	})
}

#[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::Stash));
			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)
		.balance_factor(100)
		.min_nominator_bond(1_000)
		.min_validator_bond(1_500)
		.build_and_execute(|| {
			let initial_validators = Validators::<Test>::count();
			let initial_nominators = Nominators::<Test>::count();
			for i in 0..15 {
				let a = 4 * i;
				Balances::make_free_balance_be(&a, 100_000);
				Balances::make_free_balance_be(&b, 100_000);
				Balances::make_free_balance_be(&c, 100_000);

				// Nominator
				assert_ok!(Staking::bond(RuntimeOrigin::signed(a), 1000, RewardDestination::Stash));
				assert_ok!(Staking::nominate(RuntimeOrigin::signed(a), vec![1]));
				assert_ok!(Staking::bond(RuntimeOrigin::signed(b), 1500, RewardDestination::Stash));
				assert_ok!(Staking::validate(RuntimeOrigin::signed(b), ValidatorPrefs::default()));
			// To chill other users, we need to:
			// * Set a minimum bond amount
			// * Set a limit
			// * Set a threshold
			//
			// If any of these are missing, we do not have enough information to allow the
			// `chill_other` to succeed from one user to another.
			// Can't chill these users
			assert_noop!(
				Staking::chill_other(RuntimeOrigin::signed(1337), 0),
				Error::<Test>::CannotChillOther
			);
			assert_noop!(
				Staking::chill_other(RuntimeOrigin::signed(1337), 2),
				Error::<Test>::CannotChillOther
			);
			// Change the minimum bond... but no limits.
			assert_ok!(Staking::set_staking_configs(
				RuntimeOrigin::root(),
				ConfigOp::Set(1_500),
				ConfigOp::Set(2_000),
				ConfigOp::Remove,
				ConfigOp::Remove,
				ConfigOp::Remove,
				ConfigOp::Remove
			// Still can't chill these users
			assert_noop!(
				Staking::chill_other(RuntimeOrigin::signed(1337), 0),
				Error::<Test>::CannotChillOther
			);
			assert_noop!(
				Staking::chill_other(RuntimeOrigin::signed(1337), 2),
				Error::<Test>::CannotChillOther
			);

			// Add limits, but no threshold
			assert_ok!(Staking::set_staking_configs(
				RuntimeOrigin::root(),
				ConfigOp::Noop,
				ConfigOp::Noop,
				ConfigOp::Set(10),
				ConfigOp::Set(10),
				ConfigOp::Noop,
				ConfigOp::Noop
			));

			// Still can't chill these users
			assert_noop!(
				Staking::chill_other(RuntimeOrigin::signed(1337), 0),
				Error::<Test>::CannotChillOther
			);
			assert_noop!(
				Staking::chill_other(RuntimeOrigin::signed(1337), 2),
				Error::<Test>::CannotChillOther
			);
			// Add threshold, but no limits
			assert_ok!(Staking::set_staking_configs(
				RuntimeOrigin::root(),
				ConfigOp::Noop,
				ConfigOp::Noop,
				ConfigOp::Remove,
				ConfigOp::Remove,
				ConfigOp::Noop,
				ConfigOp::Noop
			// Still can't chill these users
			assert_noop!(
				Staking::chill_other(RuntimeOrigin::signed(1337), 0),
				Error::<Test>::CannotChillOther
			);
			assert_noop!(
				Staking::chill_other(RuntimeOrigin::signed(1337), 2),
				Error::<Test>::CannotChillOther
			);

			// Add threshold and limits
			assert_ok!(Staking::set_staking_configs(
				RuntimeOrigin::root(),
				ConfigOp::Noop,
				ConfigOp::Noop,
				ConfigOp::Set(10),
				ConfigOp::Set(10),
				ConfigOp::Set(Percent::from_percent(75)),
				ConfigOp::Noop
			));

			// 16 people total because tests start with 2 active one
			assert_eq!(Nominators::<Test>::count(), 15 + initial_nominators);
			assert_eq!(Validators::<Test>::count(), 15 + initial_validators);
			// Users can now be chilled down to 7 people, so we try to remove 9 of them (starting
			// with 16)
			for i in 6..15 {
				assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), b));
				assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), d));
			// chill a nominator. Limit is not reached, not chill-able
			assert_eq!(Nominators::<Test>::count(), 7);
			assert_noop!(
				Staking::chill_other(RuntimeOrigin::signed(1337), 0),
				Error::<Test>::CannotChillOther
			);
			// chill a validator. Limit is reached, chill-able.
			assert_eq!(Validators::<Test>::count(), 9);
			assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), 2));
		})
}

#[test]
fn capped_stakers_works() {
	ExtBuilder::default().build_and_execute(|| {
		let validator_count = Validators::<Test>::count();
		assert_eq!(validator_count, 3);
		let nominator_count = Nominators::<Test>::count();
		assert_eq!(nominator_count, 1);

		// Change the maximums
		let max = 10;
		assert_ok!(Staking::set_staking_configs(
			RuntimeOrigin::root(),
			ConfigOp::Set(10),
			ConfigOp::Set(10),
			ConfigOp::Set(max),
			ConfigOp::Set(max),
			ConfigOp::Remove,
			ConfigOp::Remove,
		));

		// can create `max - validator_count` validators
		let mut some_existing_validator = AccountId::default();
		for i in 0..max - validator_count {
			let (_, controller) = testing_utils::create_stash_controller::<Test>(
				i + 10_000_000,
				RewardDestination::Stash,
			assert_ok!(Staking::validate(
				RuntimeOrigin::signed(controller),
				ValidatorPrefs::default()
			));
			some_existing_validator = controller;
		}
		// but no more
		let (_, last_validator) =
			testing_utils::create_stash_controller::<Test>(1337, 100, RewardDestination::Stash)
				.unwrap();
		assert_noop!(
			Staking::validate(RuntimeOrigin::signed(last_validator), ValidatorPrefs::default()),
			Error::<Test>::TooManyValidators,
		);
		// same with nominators
		let mut some_existing_nominator = AccountId::default();
		for i in 0..max - nominator_count {
			let (_, controller) = testing_utils::create_stash_controller::<Test>(
				i + 20_000_000,
				RewardDestination::Stash,
			assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![1]));
			some_existing_nominator = controller;
		}
		let (_, last_nominator) = testing_utils::create_stash_controller::<Test>(
			30_000_000,
			100,
			RewardDestination::Stash,
		)
		.unwrap();
		assert_noop!(
			Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![1]),
			Error::<Test>::TooManyNominators
		);
		// Re-nominate works fine
		assert_ok!(Staking::nominate(RuntimeOrigin::signed(some_existing_nominator), vec![1]));
		// Re-validate works fine
		assert_ok!(Staking::validate(
			RuntimeOrigin::signed(some_existing_validator),
			ValidatorPrefs::default()
		));

		// No problem when we set to `None` again
		assert_ok!(Staking::set_staking_configs(
			RuntimeOrigin::root(),
			ConfigOp::Noop,
			ConfigOp::Noop,
			ConfigOp::Remove,
			ConfigOp::Remove,
			ConfigOp::Noop,
			ConfigOp::Noop,
		assert_ok!(Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![1]));
		assert_ok!(Staking::validate(
			RuntimeOrigin::signed(last_validator),
			ValidatorPrefs::default()
		));
#[test]
fn min_commission_works() {
	ExtBuilder::default().build_and_execute(|| {
		// account 11 controls the stash of itself.
		assert_ok!(Staking::validate(
			ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
		));

		// event emitted should be correct
		assert_eq!(
			*staking_events().last().unwrap(),
			Event::ValidatorPrefsSet {
				stash: 11,
				prefs: ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
			}
		assert_ok!(Staking::set_staking_configs(
			RuntimeOrigin::root(),
			ConfigOp::Remove,
			ConfigOp::Remove,
			ConfigOp::Remove,
			ConfigOp::Remove,
			ConfigOp::Remove,
			ConfigOp::Set(Perbill::from_percent(10)),
		));

		// can't make it less than 10 now
		assert_noop!(
			Staking::validate(
				ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
			),
			Error::<Test>::CommissionTooLow
		);

		// can only change to higher.
		assert_ok!(Staking::validate(
			ValidatorPrefs { commission: Perbill::from_percent(10), blocked: false }
		));

		assert_ok!(Staking::validate(
			ValidatorPrefs { commission: Perbill::from_percent(15), blocked: false }
		));
	})
}

#[should_panic]
fn change_of_absolute_max_nominations() {
	use frame_election_provider_support::ElectionDataProvider;
	ExtBuilder::default()
		.add_staker(61, 61, 10, StakerStatus::Nominator(vec![1]))
		.add_staker(71, 71, 10, StakerStatus::Nominator(vec![1, 2, 3]))
		.balance_factor(10)
		.build_and_execute(|| {
			// pre-condition
			assert_eq!(AbsoluteMaxNominations::get(), 16);

			assert_eq!(
				Nominators::<Test>::iter()
					.map(|(k, n)| (k, n.targets.len()))
					.collect::<Vec<_>>(),

			// default bounds are unbounded.
			let bounds = DataProviderBounds::default();

			// 3 validators and 3 nominators
			assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 3);

			// abrupt change from 16 to 4, everyone should be fine.
			AbsoluteMaxNominations::set(4);

			assert_eq!(
				Nominators::<Test>::iter()
					.map(|(k, n)| (k, n.targets.len()))
					.collect::<Vec<_>>(),
			assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 3);

			// abrupt change from 4 to 3, everyone should be fine.
			AbsoluteMaxNominations::set(3);

			assert_eq!(
				Nominators::<Test>::iter()
					.map(|(k, n)| (k, n.targets.len()))
					.collect::<Vec<_>>(),
			assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 3);

			// abrupt change from 3 to 2, this should cause some nominators to be non-decodable, and
			// thus non-existent unless if they update.
			AbsoluteMaxNominations::set(2);

			assert_eq!(
				Nominators::<Test>::iter()
					.map(|(k, n)| (k, n.targets.len()))
					.collect::<Vec<_>>(),
			);
			// 70 is still in storage..
			assert!(Nominators::<Test>::contains_key(71));
			// but its value cannot be decoded and default is returned.
			assert!(Nominators::<Test>::get(71).is_none());
			assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 2);
			assert!(Nominators::<Test>::contains_key(101));

			// abrupt change from 2 to 1, this should cause some nominators to be non-decodable, and
			// thus non-existent unless if they update.
			AbsoluteMaxNominations::set(1);

			assert_eq!(
				Nominators::<Test>::iter()
					.map(|(k, n)| (k, n.targets.len()))
					.collect::<Vec<_>>(),
			assert!(Nominators::<Test>::contains_key(71));
			assert!(Nominators::<Test>::contains_key(61));
			assert!(Nominators::<Test>::get(71).is_none());
			assert!(Nominators::<Test>::get(61).is_some());
			assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 1);

			// now one of them can revive themselves by re-nominating to a proper value.
			assert_ok!(Staking::nominate(RuntimeOrigin::signed(71), vec![1]));
			assert_eq!(
				Nominators::<Test>::iter()
					.map(|(k, n)| (k, n.targets.len()))
					.collect::<Vec<_>>(),
			);

			// or they can be chilled by any account.
			assert!(Nominators::<Test>::contains_key(101));
			assert!(Nominators::<Test>::get(101).is_none());
			assert_ok!(Staking::chill_other(RuntimeOrigin::signed(71), 101));
			assert!(!Nominators::<Test>::contains_key(101));
			assert!(Nominators::<Test>::get(101).is_none());
		})
}

#[test]
fn nomination_quota_max_changes_decoding() {
	use frame_election_provider_support::ElectionDataProvider;
	ExtBuilder::default()
		.add_staker(60, 61, 10, StakerStatus::Nominator(vec![1]))
		.add_staker(70, 71, 10, StakerStatus::Nominator(vec![1, 2, 3]))
		.add_staker(30, 330, 10, StakerStatus::Nominator(vec![1, 2, 3, 4]))
		.add_staker(50, 550, 10, StakerStatus::Nominator(vec![1, 2, 3, 4]))
		.balance_factor(10)
		.build_and_execute(|| {
			// pre-condition.
			assert_eq!(MaxNominationsOf::<Test>::get(), 16);

			let unbonded_election = DataProviderBounds::default();

			assert_eq!(
				Nominators::<Test>::iter()
					.map(|(k, n)| (k, n.targets.len()))
					.collect::<Vec<_>>(),
				vec![(70, 3), (101, 2), (50, 4), (30, 4), (60, 1)]
			);
			// 4 validators and 4 nominators
			assert_eq!(Staking::electing_voters(unbonded_election).unwrap().len(), 4 + 4);
		});
}

#[test]
fn api_nominations_quota_works() {
	ExtBuilder::default().build_and_execute(|| {
		assert_eq!(Staking::api_nominations_quota(10), MaxNominationsOf::<Test>::get());
		assert_eq!(Staking::api_nominations_quota(333), MaxNominationsOf::<Test>::get());
		assert_eq!(Staking::api_nominations_quota(222), 2);
		assert_eq!(Staking::api_nominations_quota(111), 1);
	})
}

mod sorted_list_provider {
	use super::*;
	use frame_election_provider_support::SortedListProvider;

	#[test]
	fn re_nominate_does_not_change_counters_or_list() {
		ExtBuilder::default().nominate(true).build_and_execute(|| {
			// given
			let pre_insert_voter_count =
				(Nominators::<Test>::count() + Validators::<Test>::count()) as u32;
			assert_eq!(<Test as Config>::VoterList::count(), pre_insert_voter_count);

			assert_eq!(
				<Test as Config>::VoterList::iter().collect::<Vec<_>>(),
				vec![11, 21, 31, 101]
			);
			assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![41]));
			assert_eq!(<Test as Config>::VoterList::count(), pre_insert_voter_count);
			// and the list is the same
			assert_eq!(
				<Test as Config>::VoterList::iter().collect::<Vec<_>>(),
				vec![11, 21, 31, 101]
			);
		});
	}

	#[test]
	fn re_validate_does_not_change_counters_or_list() {
		ExtBuilder::default().nominate(false).build_and_execute(|| {
			// given
			let pre_insert_voter_count =
				(Nominators::<Test>::count() + Validators::<Test>::count()) as u32;
			assert_eq!(<Test as Config>::VoterList::count(), pre_insert_voter_count);

			assert_eq!(<Test as Config>::VoterList::iter().collect::<Vec<_>>(), vec![11, 21, 31]);

			// when account 11 re-validates
			assert_ok!(Staking::validate(RuntimeOrigin::signed(11), Default::default()));

			// then counts don't change
			assert_eq!(<Test as Config>::VoterList::count(), pre_insert_voter_count);
			assert_eq!(<Test as Config>::VoterList::iter().collect::<Vec<_>>(), vec![11, 21, 31]);

#[test]
fn force_apply_min_commission_works() {
	let prefs = |c| ValidatorPrefs { commission: Perbill::from_percent(c), blocked: false };
	let validators = || Validators::<Test>::iter().collect::<Vec<_>>();
	ExtBuilder::default().build_and_execute(|| {
		assert_ok!(Staking::validate(RuntimeOrigin::signed(31), prefs(10)));
		assert_ok!(Staking::validate(RuntimeOrigin::signed(21), prefs(5)));

		// Given
		assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]);
		MinCommission::<Test>::set(Perbill::from_percent(5));

		// When applying to a commission greater than min
		assert_ok!(Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 31));
		// Then the commission is not changed
		assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]);

		// When applying to a commission that is equal to min
		assert_ok!(Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 21));
		// Then the commission is not changed
		assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]);

		// When applying to a commission that is less than the min
		assert_ok!(Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 11));
		// Then the commission is bumped to the min
		assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(5))]);

		// When applying commission to a validator that doesn't exist then storage is not altered
		assert_noop!(
			Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 420),