Skip to content
tests.rs 138 KiB
Newer Older
		ExtBuilder::default().build_and_execute(|| {
			assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]);
			assert_eq!(
				<Staking as ElectionDataProvider<AccountId, BlockNumber>>::voters(None)
					.unwrap()
					.iter()
					.find(|x| x.0 == 101)
					.unwrap()
					.2,
				vec![11, 21]
			);

			start_active_era(1);
			add_slash(&11);

			// 11 is gone.
			start_active_era(2);
			assert_eq!(
				<Staking as ElectionDataProvider<AccountId, BlockNumber>>::voters(None)
					.unwrap()
					.iter()
					.find(|x| x.0 == 101)
					.unwrap()
					.2,
				vec![21]
			);

			// resubmit and it is back
			assert_ok!(Staking::nominate(Origin::signed(100), vec![11, 21]));
			assert_eq!(
				<Staking as ElectionDataProvider<AccountId, BlockNumber>>::voters(None)
					.unwrap()
	fn respects_snapshot_len_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>::SortedListProvider::count() +
						<Validators<Test>>::iter().count() as u32,
					5
				);

				// if limits is less..
				assert_eq!(Staking::voters(Some(1)).unwrap().len(), 1);

				// if limit is equal..
				assert_eq!(Staking::voters(Some(5)).unwrap().len(), 5);

				// if limit is more.
				assert_eq!(Staking::voters(Some(55)).unwrap().len(), 5);

				// if target limit is more..
				assert_eq!(Staking::targets(Some(6)).unwrap().len(), 4);
				assert_eq!(Staking::targets(Some(4)).unwrap().len(), 4);

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

	#[test]
	fn only_iterates_max_2_times_nominators_quota() {
		ExtBuilder::default()
			.nominate(true) // add nominator 101, who nominates [11, 21]
			// the other nominators only nominate 21
			.add_staker(61, 60, 2_000, StakerStatus::<AccountId>::Nominator(vec![21]))
			.add_staker(71, 70, 2_000, StakerStatus::<AccountId>::Nominator(vec![21]))
			.add_staker(81, 80, 2_000, StakerStatus::<AccountId>::Nominator(vec![21]))
			.build_and_execute(|| {
				// given our nominators ordered by stake,
				assert_eq!(
					<Test as Config>::SortedListProvider::iter().collect::<Vec<_>>(),
					vec![61, 71, 81, 101]
				);

				// and total voters
				assert_eq!(
					<Test as Config>::SortedListProvider::count() +
						<Validators<Test>>::iter().count() as u32,
					7
				);

				// roll to session 5
				run_to_block(25);

				// slash 21, the only validator nominated by our first 3 nominators
				add_slash(&21);

				// we take 4 voters: 2 validators and 2 nominators (so nominators quota = 2)
				assert_eq!(
					Staking::voters(Some(3))
						.unwrap()
						.iter()
						.map(|(stash, _, _)| stash)
						.copied()
						.collect::<Vec<_>>(),
					vec![31, 11], // 2 validators, but no nominators because we hit the quota
				);
			});
	}

	// Even if some of the higher staked nominators are slashed, we still get up to max len voters
	// by adding more lower staked nominators. In other words, we assert that we keep on adding
	// valid nominators until we reach max len voters; which is opposed to simply stopping after we
	// have iterated max len voters, but not adding all of them to voters due to some nominators not
	// having valid targets.
	#[test]
	fn get_max_len_voters_even_if_some_nominators_are_slashed() {
		ExtBuilder::default()
			.nominate(true) // add nominator 101, who nominates [11, 21]
			.add_staker(61, 60, 20, StakerStatus::<AccountId>::Nominator(vec![21]))
			//                                 61 only nominates validator 21 ^^
			.add_staker(71, 70, 10, StakerStatus::<AccountId>::Nominator(vec![11, 21]))
			.build_and_execute(|| {
				// given our nominators ordered by stake,
				assert_eq!(
					<Test as Config>::SortedListProvider::iter().collect::<Vec<_>>(),
					vec![101, 61, 71]
				);

				// and total voters
				assert_eq!(
					<Test as Config>::SortedListProvider::count() +
						<Validators<Test>>::iter().count() as u32,
					6
				);

				// we take 5 voters
				assert_eq!(
					Staking::voters(Some(5))
						.unwrap()
						.iter()
						.map(|(stash, _, _)| stash)
						.copied()
						.collect::<Vec<_>>(),
					// then
					vec![
						31, 21, 11, // 3 nominators
						101, 61 // 2 validators, and 71 is excluded
					],
				);

				// roll to session 5
				run_to_block(25);

				// slash 21, the only validator nominated by 61
				add_slash(&21);

				// we take 4 voters
				assert_eq!(
					Staking::voters(Some(4))
						.unwrap()
						.iter()
						.map(|(stash, _, _)| stash)
						.copied()
						.collect::<Vec<_>>(),
					vec![
						31, 11, // 2 validators (21 was slashed)
						101, 71 // 2 nominators, excluding 61
					],
				);
			});
	#[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(Origin::root()).unwrap();
			assert_eq!(Staking::next_election_prediction(System::block_number()), u64::MAX);

			Staking::force_new_era_always(Origin::root()).unwrap();
			assert_eq!(Staking::next_election_prediction(System::block_number()), 45 + 5);

			Staking::force_new_era(Origin::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(), 6);
			assert_eq!(*staking_events().last().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: vec![], 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(Origin::signed(3), 4, 500, RewardDestination::Controller));
			assert_noop!(
				Staking::nominate(Origin::signed(4), vec![1]),
				Error::<Test>::InsufficientBond
			);
			assert_noop!(
				Staking::validate(Origin::signed(4), ValidatorPrefs::default()),
				Error::<Test>::InsufficientBond,
			// 1000 is enough for nominator
			assert_ok!(Staking::bond_extra(Origin::signed(3), 500));
			assert_ok!(Staking::nominate(Origin::signed(4), vec![1]));
			assert_noop!(
				Staking::validate(Origin::signed(4), ValidatorPrefs::default()),
				Error::<Test>::InsufficientBond,
			);
			// 1500 is enough for validator
			assert_ok!(Staking::bond_extra(Origin::signed(3), 500));
			assert_ok!(Staking::nominate(Origin::signed(4), vec![1]));
			assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default()));
			// Can't unbond anything as validator
			assert_noop!(Staking::unbond(Origin::signed(4), 500), Error::<Test>::InsufficientBond);
			// Once they are a nominator, they can unbond 500
			assert_ok!(Staking::nominate(Origin::signed(4), vec![1]));
			assert_ok!(Staking::unbond(Origin::signed(4), 500));
			assert_noop!(Staking::unbond(Origin::signed(4), 500), Error::<Test>::InsufficientBond);
			// Once they are chilled they can unbond everything
			assert_ok!(Staking::chill(Origin::signed(4)));
			assert_ok!(Staking::unbond(Origin::signed(4), 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 = CounterForValidators::<Test>::get();
			let initial_nominators = CounterForNominators::<Test>::get();
			for i in 0..15 {
				let a = 4 * i;
				let b = 4 * i + 1;
				let c = 4 * i + 2;
				let d = 4 * i + 3;
				Balances::make_free_balance_be(&a, 100_000);
				Balances::make_free_balance_be(&b, 100_000);
				Balances::make_free_balance_be(&c, 100_000);
				Balances::make_free_balance_be(&d, 100_000);

				// Nominator
				assert_ok!(Staking::bond(
					Origin::signed(a),
					b,
					1000,
					RewardDestination::Controller
				));
				assert_ok!(Staking::nominate(Origin::signed(b), vec![1]));

				// Validator
				assert_ok!(Staking::bond(
					Origin::signed(c),
					d,
					1500,
					RewardDestination::Controller
				assert_ok!(Staking::validate(Origin::signed(d), 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(Origin::signed(1337), 1),
				Error::<Test>::CannotChillOther
			);
			assert_noop!(
				Staking::chill_other(Origin::signed(1337), 3),
				Error::<Test>::CannotChillOther
			);
			// Change the minimum bond... but no limits.
			assert_ok!(Staking::set_staking_configs(
				Origin::root(),
				1_500,
				2_000,
				None,
				None,
				None,
				Zero::zero()
			));
			// Still can't chill these users
			assert_noop!(
				Staking::chill_other(Origin::signed(1337), 1),
				Error::<Test>::CannotChillOther
			);
			assert_noop!(
				Staking::chill_other(Origin::signed(1337), 3),
				Error::<Test>::CannotChillOther
			);

			// Add limits, but no threshold
			assert_ok!(Staking::set_staking_configs(
				Origin::root(),
				1_500,
				2_000,
				Some(10),
				Some(10),
			));

			// Still can't chill these users
			assert_noop!(
				Staking::chill_other(Origin::signed(1337), 1),
				Error::<Test>::CannotChillOther
			);
			assert_noop!(
				Staking::chill_other(Origin::signed(1337), 3),
				Error::<Test>::CannotChillOther
			);
			// Add threshold, but no limits
			assert_ok!(Staking::set_staking_configs(
				Some(Percent::from_percent(0)),
				Zero::zero()
			// Still can't chill these users
			assert_noop!(
				Staking::chill_other(Origin::signed(1337), 1),
				Error::<Test>::CannotChillOther
			);
			assert_noop!(
				Staking::chill_other(Origin::signed(1337), 3),
				Error::<Test>::CannotChillOther
			);

			// Add threshold and limits
			assert_ok!(Staking::set_staking_configs(
				Origin::root(),
				1_500,
				2_000,
				Some(10),
				Some(10),
				Some(Percent::from_percent(75)),
				Zero::zero()
			));

			// 16 people total because tests start with 2 active one
			assert_eq!(CounterForNominators::<Test>::get(), 15 + initial_nominators);
			assert_eq!(CounterForValidators::<Test>::get(), 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 {
				let b = 4 * i + 1;
				let d = 4 * i + 3;
				assert_ok!(Staking::chill_other(Origin::signed(1337), b));
				assert_ok!(Staking::chill_other(Origin::signed(1337), d));
			// chill a nominator. Limit is not reached, not chill-able
			assert_eq!(CounterForNominators::<Test>::get(), 7);
			assert_noop!(
				Staking::chill_other(Origin::signed(1337), 1),
				Error::<Test>::CannotChillOther
			);
			// chill a validator. Limit is reached, chill-able.
			assert_eq!(CounterForValidators::<Test>::get(), 9);
			assert_ok!(Staking::chill_other(Origin::signed(1337), 3));
		})
}

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

		// Change the maximums
		let max = 10;
		assert_ok!(Staking::set_staking_configs(
			Origin::root(),
			10,
			10,
			Some(max),
			Some(max),
			Some(Percent::from_percent(0)),
			Zero::zero(),
		));

		// 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,
				100,
				RewardDestination::Controller,
			)
			.unwrap();
			assert_ok!(Staking::validate(Origin::signed(controller), ValidatorPrefs::default()));
			some_existing_validator = controller;
		}
		// but no more
		let (_, last_validator) = testing_utils::create_stash_controller::<Test>(
			1337,
			100,
			RewardDestination::Controller,
		)
		.unwrap();
		assert_noop!(
			Staking::validate(Origin::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,
				100,
				RewardDestination::Controller,
			)
			.unwrap();
			assert_ok!(Staking::nominate(Origin::signed(controller), vec![1]));
			some_existing_nominator = controller;
		}
		// one more is too many
		let (_, last_nominator) = testing_utils::create_stash_controller::<Test>(
			30_000_000,
			100,
			RewardDestination::Controller,
		)
		.unwrap();
		assert_noop!(
			Staking::nominate(Origin::signed(last_nominator), vec![1]),
			Error::<Test>::TooManyNominators
		);
		// Re-nominate works fine
		assert_ok!(Staking::nominate(Origin::signed(some_existing_nominator), vec![1]));
		// Re-validate works fine
		assert_ok!(Staking::validate(
			Origin::signed(some_existing_validator),
			ValidatorPrefs::default()
		));

		// No problem when we set to `None` again
		assert_ok!(Staking::set_staking_configs(
			Origin::root(),
			10,
			10,
			None,
			None,
			None,
			Zero::zero(),
		));
		assert_ok!(Staking::nominate(Origin::signed(last_nominator), vec![1]));
		assert_ok!(Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default()));
	})
#[test]
fn min_commission_works() {
	ExtBuilder::default().build_and_execute(|| {
		assert_ok!(Staking::validate(
			Origin::signed(10),
			ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
		));

		assert_ok!(Staking::set_staking_configs(
			Origin::root(),
			0,
			0,
			None,
			None,
			None,
			Perbill::from_percent(10),
		));

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

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

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

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_nominator_count = Nominators::<Test>::iter().count() as u32;
			assert_eq!(<Test as Config>::SortedListProvider::count(), pre_insert_nominator_count);
			assert!(Nominators::<Test>::contains_key(101));
			assert_eq!(<Test as Config>::SortedListProvider::iter().collect::<Vec<_>>(), vec![101]);

			// when account 101 renominates
			assert_ok!(Staking::nominate(Origin::signed(100), vec![41]));

			// then counts don't change
			assert_eq!(<Test as Config>::SortedListProvider::count(), pre_insert_nominator_count);
			assert_eq!(Nominators::<Test>::iter().count() as u32, pre_insert_nominator_count);
			// and the list is the same
			assert_eq!(<Test as Config>::SortedListProvider::iter().collect::<Vec<_>>(), vec![101]);
		});
	}
}