Skip to content
tests.rs 75.9 KiB
Newer Older
		assert_eq!(Balances::free_balance(&11), recorded_stash_balance);
fn validator_payment_prefs_work() {
	// Test that validator preferences are correctly honored
	// Note: unstake threshold is being directly tested in slashing tests.
	// This test will focus on validator payment.
	with_externalities(&mut ExtBuilder::default()
		.session_length(3)
		.sessions_per_era(3)
		.build(),
	|| {
		let session_reward = 10;
		let validator_cut = 5;
		let validator_initial_balance = Balances::total_balance(&11);
		// Initial config should be correct
		assert_eq!(Staking::era_length(), 9);
		assert_eq!(Staking::sessions_per_era(), 3);
		assert_eq!(Staking::last_era_length_change(), 0);
		assert_eq!(Staking::current_era(), 0);
		assert_eq!(Session::current_index(), 0);

		assert_eq!(Staking::current_session_reward(), session_reward);

		// check the balance of a validator accounts.
		assert_eq!(Balances::total_balance(&10), 1);
		// check the balance of a validator's stash accounts.
		assert_eq!(Balances::total_balance(&11), validator_initial_balance);
		// and the nominator (to-be)
		let _ = Balances::make_free_balance_be(&2, 500);

		// add a dummy nominator.
		// NOTE: this nominator is being added 'manually', use '.nominate()' to do it realistically.
		<Stakers<Test>>::insert(&11, Exposure {
			own: 500, // equal division indicates that the reward will be equally divided among validator and nominator.
			total: 1000,
			others: vec![IndividualExposure {who: 2, value: 500 }]
		<Payee<Test>>::insert(&2, RewardDestination::Stash);
		<Validators<Test>>::insert(&11, ValidatorPrefs {
			unstake_threshold: 3,
			validator_payment: validator_cut
		// ------------ Fast forward
		let mut block = 3;
		// Block 3 => Session 1 => Era 0
		System::set_block_number(block);
		Timestamp::set_timestamp(block*5);	// on time.
		Session::check_rotate_session(System::block_number());
		assert_eq!(Staking::current_era(), 0);
		assert_eq!(Session::current_index(), 1);

		// session triggered: the reward value stashed should be 10 -- defined in ExtBuilder genesis.
		assert_eq!(Staking::current_session_reward(), session_reward);
		assert_eq!(Staking::current_era_reward(), session_reward);
		block = 6; // Block 6 => Session 2 => Era 0
		System::set_block_number(block);
		Timestamp::set_timestamp(block*5);	// a little late.
		Session::check_rotate_session(System::block_number());
		assert_eq!(Staking::current_era(), 0);
		assert_eq!(Session::current_index(), 2);

		assert_eq!(Staking::current_session_reward(), session_reward);
		assert_eq!(Staking::current_era_reward(), 2*session_reward);

		block = 9; // Block 9 => Session 3 => Era 1
		System::set_block_number(block);
		Timestamp::set_timestamp(block*5);
		Session::check_rotate_session(System::block_number());
		assert_eq!(Staking::current_era(), 1);
		assert_eq!(Session::current_index(), 3);

		// whats left to be shared is the sum of 3 rounds minus the validator's cut.
		let shared_cut = 3 * session_reward - validator_cut;
		// Validator's payee is Staked account, 11, reward will be paid here.
		assert_eq!(Balances::total_balance(&11), validator_initial_balance + shared_cut/2 + validator_cut);
		// Controller account will not get any reward.
		assert_eq!(Balances::total_balance(&10), 1);
		// Rest of the reward will be shared and paid to the nominator in stake.
		assert_eq!(Balances::total_balance(&2), 500 + shared_cut/2);
#[test]
fn bond_extra_works() {
	// Tests that extra `free_balance` in the stash can be added to stake
	// NOTE: this tests only verifies `StakingLedger` for correct updates
	// See `bond_extra_and_withdraw_unbonded_works` for more details and updates on `Exposure`.
	with_externalities(&mut ExtBuilder::default().build(),
	|| {
		// Check that account 10 is a validator
		assert!(<Validators<Test>>::exists(11));
		// Check that account 10 is bonded to account 11
		assert_eq!(Staking::bonded(&11), Some(10));
		// Check how much is at stake
		assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![] }));

		// Give account 11 some large free balance greater than total
		let _ = Balances::make_free_balance_be(&11, 1000000);

		// Call the bond_extra function from controller, add only 100
		assert_ok!(Staking::bond_extra(Origin::signed(11), 100));
		// There should be 100 more `total` and `active` in the ledger
		assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 100, active: 1000 + 100, unlocking: vec![] }));

		// Call the bond_extra function with a large number, should handle it
		assert_ok!(Staking::bond_extra(Origin::signed(11), u64::max_value()));
		// The full amount of the funds should now be in the total and active
		assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000000, active: 1000000, unlocking: vec![] }));

	});
}

#[test]
fn bond_extra_and_withdraw_unbonded_works() {
	// * Should test
	// * Given an account being bonded [and chosen as a validator](not mandatory)
	// * It can add extra funds to the bonded account.
	// * it can unbond a portion of its funds from the stash account.
	// * Once the unbonding period is done, it can actually take the funds out of the stash.
	with_externalities(&mut ExtBuilder::default()
		.nominate(false)
	|| {
		// Set payee to controller. avoids confusion
		assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller));
		// Set unbonding era (bonding_duration) to 2
		assert_ok!(Staking::set_bonding_duration(2));
		// Give account 11 some large free balance greater than total
		let _ = Balances::make_free_balance_be(&11, 1000000);
		// Initial config should be correct
		assert_eq!(Staking::sessions_per_era(), 1);
		assert_eq!(Staking::current_era(), 0);
		assert_eq!(Session::current_index(), 0);
		assert_eq!(Staking::current_session_reward(), 10);

		// check the balance of a validator accounts.
		assert_eq!(Balances::total_balance(&10), 1);

		// confirm that 10 is a normal validator and gets paid at the end of the era.
		System::set_block_number(1);
		Timestamp::set_timestamp(5);
		Session::check_rotate_session(System::block_number());
		assert_eq!(Staking::current_era(), 1);
		assert_eq!(Session::current_index(), 1);

		// NOTE: despite having .nominate() in extBuilder, 20 doesn't have a share since
		// rewards are paid before election in new_era()
		assert_eq!(Balances::total_balance(&10), 1 + 10);

		// Initial state of 10
		assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![] }));
		assert_eq!(Staking::stakers(&11), Exposure { total: 1000, own: 1000, others: vec![] });
		// deposit the extra 100 units
		Staking::bond_extra(Origin::signed(11), 100).unwrap();

		assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 100, active: 1000 + 100, unlocking: vec![] }));
		// Exposure is a snapshot! only updated after the next era update.
		assert_ne!(Staking::stakers(&11), Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] });

		// trigger next era.
		System::set_block_number(2);Timestamp::set_timestamp(10);Session::check_rotate_session(System::block_number());
		assert_eq!(Staking::current_era(), 2);
		assert_eq!(Session::current_index(), 2);

		// ledger should be the same.
		assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000 + 100, active: 1000 + 100, unlocking: vec![] }));
		// Exposure is now updated.
		assert_eq!(Staking::stakers(&11), Exposure { total: 1000 + 100, own: 1000 + 100, others: vec![] });
		// Note that by this point 10 also have received more rewards, but we don't care now.
		// assert_eq!(Balances::total_balance(&10), 1 + 10 + MORE_REWARD);

		// Unbond almost all of the funds in stash.
		Staking::unbond(Origin::signed(10), 1000).unwrap();
		assert_eq!(Staking::ledger(&10), Some(StakingLedger {
			stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 2}] }));

		// Attempting to free the balances now will fail. 2 eras need to pass.
		Staking::withdraw_unbonded(Origin::signed(10)).unwrap();
		assert_eq!(Staking::ledger(&10), Some(StakingLedger {
			stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 2}] }));

		// trigger next era.
		System::set_block_number(3);Timestamp::set_timestamp(15);Session::check_rotate_session(System::block_number());
		assert_eq!(Staking::current_era(), 3);
		assert_eq!(Session::current_index(), 3);

		// nothing yet
		Staking::withdraw_unbonded(Origin::signed(10)).unwrap();
		assert_eq!(Staking::ledger(&10), Some(StakingLedger {
			stash: 11, total: 1000 + 100, active: 100, unlocking: vec![UnlockChunk{ value: 1000, era: 2 + 2}] }));

		// trigger next era.
		System::set_block_number(4);Timestamp::set_timestamp(20);Session::check_rotate_session(System::block_number());
		assert_eq!(Staking::current_era(), 4);
		assert_eq!(Session::current_index(), 4);
		Staking::withdraw_unbonded(Origin::signed(10)).unwrap();
		// Now the value is free and the staking ledger is updated.
		assert_eq!(Staking::ledger(&10), Some(StakingLedger {
			stash: 11, total: 100, active: 100, unlocking: vec![] }));
	})
}

#[test]
fn slot_stake_is_least_staked_validator_and_limits_maximum_punishment() {
	// Test that slot_stake is determined by the least staked validator
	// Test that slot_stake is the maximum punishment that can happen to a validator
	// Note that rewardDestination is the stash account by default
	// Note that unlike reward slash will affect free_balance, not the stash account.
	with_externalities(&mut ExtBuilder::default()
		.nominate(false)
		.fare(false)
		.build(),
	|| {
		// Give the man some money.
		// Confirm validator count is 2
		assert_eq!(Staking::validator_count(), 2);
		// Confirm account 10 and 20 are validators
		assert!(<Validators<Test>>::exists(&11) && <Validators<Test>>::exists(&21));
		assert_eq!(Staking::stakers(&11).total, 1000);
		assert_eq!(Staking::stakers(&21).total, 2000);
		// Give the man some money.
		let _ = Balances::make_free_balance_be(&10, 1000);
		let _ = Balances::make_free_balance_be(&20, 1000);

		// We confirm initialized slot_stake is this value
		assert_eq!(Staking::slot_stake(), Staking::stakers(&11).total);

		// Now lets lower account 20 stake
		<Stakers<Test>>::insert(&21, Exposure { total: 69, own: 69, others: vec![] });
		assert_eq!(Staking::stakers(&21).total, 69);
		<Ledger<Test>>::insert(&20, StakingLedger { stash: 22, total: 69, active: 69, unlocking: vec![] });

		// New era --> rewards are paid --> stakes are changed
		System::set_block_number(1);
		Timestamp::set_timestamp(5);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Staking::current_era(), 1);
		// -- new balances + reward
		assert_eq!(Staking::stakers(&11).total, 1000 + 10);
		assert_eq!(Staking::stakers(&21).total, 69 + 10);
		// -- Note that rewards are going directly to stash, not as free balance.
		assert_eq!(Balances::free_balance(&10), 1000);
		assert_eq!(Balances::free_balance(&20), 1000);

		// -- slot stake should also be updated.
		assert_eq!(Staking::slot_stake(), 79);

		// // If 10 gets slashed now, despite having +1000 in stash, it will be slashed byt 79, which is the slot stake
		Staking::on_offline_validator(10, 4);
		// // Confirm user has been reported
		assert_eq!(Staking::slash_count(&11), 4);
		// // check the balance of 10 (slash will be deducted from free balance.)
		assert_eq!(Balances::free_balance(&11), 1000 + 10 - 50 /*5% of 1000*/ * 8 /*2**3*/);

#[test]
fn on_free_balance_zero_stash_removes_validator() {
	// Tests that validator storage items are cleaned up when stash is empty
	// Tests that storage items are untouched when controller is empty
	with_externalities(&mut ExtBuilder::default()
		.existential_deposit(10)
		.build(),
	|| {
		// Check that account 10 is a validator
		assert!(<Validators<Test>>::exists(11));
		// Check the balance of the validator account
		assert_eq!(Balances::free_balance(&10), 256);
		// Check the balance of the stash account
		assert_eq!(Balances::free_balance(&11), 256000);
		// Check these two accounts are bonded
		assert_eq!(Staking::bonded(&11), Some(10));

		// Set some storage items which we expect to be cleaned up
		// Initiate slash count storage item
		Staking::on_offline_validator(10, 1);
		// Set payee information
		assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash));

		// Check storage items that should be cleaned up
		assert!(<Ledger<Test>>::exists(&10));
		assert!(<Bonded<Test>>::exists(&11));
		assert!(<Validators<Test>>::exists(&11));
		assert!(<SlashCount<Test>>::exists(&11));
		assert!(<Payee<Test>>::exists(&11));

		// Reduce free_balance of controller to 0
		Balances::slash(&10, u64::max_value());

		// Check the balance of the stash account has not been touched
		assert_eq!(Balances::free_balance(&11), 256000);
		// Check these two accounts are still bonded
		assert_eq!(Staking::bonded(&11), Some(10));

		// Check storage items have not changed
		assert!(<Ledger<Test>>::exists(&10));
		assert!(<Bonded<Test>>::exists(&11));
		assert!(<Validators<Test>>::exists(&11));
		assert!(<SlashCount<Test>>::exists(&11));
		assert!(<Payee<Test>>::exists(&11));

		// Reduce free_balance of stash to 0
		Balances::slash(&11, u64::max_value());
		// Check total balance of stash
		assert_eq!(Balances::total_balance(&11), 0);

		// Check storage items do not exist
		assert!(!<Ledger<Test>>::exists(&10));
		assert!(!<Bonded<Test>>::exists(&11));
		assert!(!<Validators<Test>>::exists(&11));
		assert!(!<Nominators<Test>>::exists(&11));
		assert!(!<SlashCount<Test>>::exists(&11));
		assert!(!<Payee<Test>>::exists(&11));
	});
}

#[test]
fn on_free_balance_zero_stash_removes_nominator() {
	// Tests that nominator storage items are cleaned up when stash is empty
	// Tests that storage items are untouched when controller is empty
	with_externalities(&mut ExtBuilder::default()
		.existential_deposit(10)
		.build(),
	|| {
		// Make 10 a nominator
		assert_ok!(Staking::nominate(Origin::signed(10), vec![20]));
		// Check that account 10 is a nominator
		assert!(<Nominators<Test>>::exists(11));
		// Check the balance of the nominator account
		assert_eq!(Balances::free_balance(&10), 256);
		// Check the balance of the stash account
		assert_eq!(Balances::free_balance(&11), 256000);
		// Check these two accounts are bonded
		assert_eq!(Staking::bonded(&11), Some(10));

		// Set payee information
		assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Stash));


		// Check storage items that should be cleaned up
		assert!(<Ledger<Test>>::exists(&10));
		assert!(<Bonded<Test>>::exists(&11));
		assert!(<Nominators<Test>>::exists(&11));
		assert!(<Payee<Test>>::exists(&11));

		// Reduce free_balance of controller to 0
		Balances::slash(&10, u64::max_value());
		// Check total balance of account 10
		assert_eq!(Balances::total_balance(&10), 0);

		// Check the balance of the stash account has not been touched
		assert_eq!(Balances::free_balance(&11), 256000);
		// Check these two accounts are still bonded
		assert_eq!(Staking::bonded(&11), Some(10));

		// Check storage items have not changed
		assert!(<Ledger<Test>>::exists(&10));
		assert!(<Bonded<Test>>::exists(&11));
		assert!(<Nominators<Test>>::exists(&11));
		assert!(<Payee<Test>>::exists(&11));

		// Reduce free_balance of stash to 0
		Balances::slash(&11, u64::max_value());
		// Check total balance of stash
		assert_eq!(Balances::total_balance(&11), 0);

		// Check storage items do not exist
		assert!(!<Ledger<Test>>::exists(&10));
		assert!(!<Bonded<Test>>::exists(&11));
		assert!(!<Validators<Test>>::exists(&11));
		assert!(!<Nominators<Test>>::exists(&11));
		assert!(!<SlashCount<Test>>::exists(&11));
		assert!(!<Payee<Test>>::exists(&11));
}

#[test]
fn phragmen_poc_works() {
	// Tests the POC test of the phragmen, mentioned in the paper and reference implementation.
	// Initial votes:
	// Votes  [
	// ('2', 500, ['10', '20', '30']),
	// ('4', 500, ['10', '20', '40']),
	// ('10', 1000, ['10']),
	// ('20', 1000, ['20']),
	// ('30', 1000, ['30']),
	// ('40', 1000, ['40'])]
	//
	// Sequential Phragmén gives
	// 10  is elected with stake  1666.6666666666665 and score  0.0005
	// 20  is elected with stake  1333.3333333333333 and score  0.00075

	// 2  has load  0.00075 and supported
	// 10  with stake  333.3333333333333 20  with stake  166.66666666666666 30  with stake  0.0
	// 4  has load  0.00075 and supported
	// 10  with stake  333.3333333333333 20  with stake  166.66666666666666 40  with stake  0.0
	// 10  has load  0.0005 and supported
	// 10  with stake  1000.0
	// 20  has load  0.00075 and supported
	// 20  with stake  1000.0
	// 30  has load  0 and supported
	// 30  with stake  0
	// 40  has load  0 and supported
	// 40  with stake  0

	// 	Sequential Phragmén with post processing gives
	// 10  is elected with stake  1500.0 and score  0.0005
	// 20  is elected with stake  1500.0 and score  0.00075
	// 10  has load  0.0005 and supported
	// 10  with stake  1000.0
	// 20  has load  0.00075 and supported
	// 20  with stake  1000.0
	// 30  has load  0 and supported
	// 30  with stake  0
	// 40  has load  0 and supported
	// 40  with stake  0
	// 2  has load  0.00075 and supported
	// 10  with stake  166.66666666666674 20  with stake  333.33333333333326 30  with stake  0
	// 4  has load  0.00075 and supported
	// 10  with stake  333.3333333333333 20  with stake  166.66666666666666 40  with stake  0.0


	with_externalities(&mut ExtBuilder::default()
		.nominate(false)
		.validator_pool(true)
		// We don't really care about this. At this point everything is even.
		// assert_eq!(Session::validators(), vec![40, 30]);

		assert_eq!(Staking::ledger(&10), Some(StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: vec![] }));
		assert_eq!(Staking::ledger(&20), Some(StakingLedger { stash: 21, total: 1000, active: 1000, unlocking: vec![] }));
		assert_eq!(Staking::ledger(&30), Some(StakingLedger { stash: 31, total: 1000, active: 1000, unlocking: vec![] }));
		assert_eq!(Staking::ledger(&40), Some(StakingLedger { stash: 41, total: 1000, active: 1000, unlocking: vec![] }));
		assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller));
		assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller));
		assert_ok!(Staking::set_payee(Origin::signed(30), RewardDestination::Controller));
		assert_ok!(Staking::set_payee(Origin::signed(40), RewardDestination::Controller));

		// no one is a nominator
		assert_eq!(<Nominators<Test>>::enumerate().count(), 0 as usize);

		// bond [2,1] / [4,3] a nominator
		let _ = Balances::deposit_creating(&1, 1000);
		let _ = Balances::deposit_creating(&3, 1000);
		assert_ok!(Staking::bond(Origin::signed(1), 2, 500, RewardDestination::default()));
		assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21, 31]));
		assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::default()));
		assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 21, 41]));

		// New era => election algorithm will trigger
		System::set_block_number(1);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Session::validators(), vec![20, 10]);

		// with stake 1666 and 1333 respectively
		assert_eq!(Staking::stakers(11).own, 1000);
		assert_eq!(Staking::stakers(11).total, 1000 + 332);
		assert_eq!(Staking::stakers(21).own, 1000);
		assert_eq!(Staking::stakers(21).total, 1000 + 666);

		// Nominator's stake distribution.
		assert_eq!(Staking::stakers(11).others.iter().map(|e| e.value).collect::<Vec<BalanceOf<Test>>>(), vec![166, 166]);
		assert_eq!(Staking::stakers(11).others.iter().map(|e| e.value).sum::<BalanceOf<Test>>(), 332);
		assert_eq!(Staking::stakers(11).others.iter().map(|e| e.who).collect::<Vec<BalanceOf<Test>>>(), vec![3, 1]);

		assert_eq!(Staking::stakers(21).others.iter().map(|e| e.value).collect::<Vec<BalanceOf<Test>>>(), vec![333, 333]);
		assert_eq!(Staking::stakers(21).others.iter().map(|e| e.value).sum::<BalanceOf<Test>>(), 666);
		assert_eq!(Staking::stakers(21).others.iter().map(|e| e.who).collect::<Vec<BalanceOf<Test>>>(), vec![3, 1]);
fn phragmen_election_works_example_2() {
	// tests the encapsulated phragmen::elect function.
	with_externalities(&mut ExtBuilder::default().nominate(false).build(), || {
		// initial setup of 10 and 20, both validators
		assert_eq!(Session::validators(), vec![20, 10]);

		// no one is a nominator
		assert_eq!(<Nominators<Test>>::enumerate().count(), 0 as usize);

		// Bond [30, 31] as the third validator
		assert_ok!(Staking::bond(Origin::signed(31), 30, 1000, RewardDestination::default()));
		assert_ok!(Staking::validate(Origin::signed(30), ValidatorPrefs::default()));

		// bond [2,1](A), [4,3](B), as 2 nominators
		// Give all of them some balance to be able to bond properly.
		for i in &[1, 3] { let _ = Balances::deposit_creating(i, 2000); }
		assert_ok!(Staking::bond(Origin::signed(1), 2, 50, RewardDestination::default()));
		assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21]));
		assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::default()));
		assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 31]));

		let rounds =     || 2 as usize;
		let validators = || <Validators<Test>>::enumerate();
		let nominators = || <Nominators<Test>>::enumerate();
		let min_validator_count = Staking::minimum_validator_count() as usize;

		let winners = phragmen::elect::<Test, _, _, _, _>(
			rounds,
			validators,
			nominators,
			Staking::slashable_balance_of,
			min_validator_count,
			ElectionConfig::<BalanceOf<Test>> {
				equalize: true,
				tolerance: <BalanceOf<Test>>::sa(10 as u64),
				iterations: 10,
			}
		let winners = winners.unwrap();

		// 10 and 30 must be the winners
		assert_eq!(winners.iter().map(|w| w.who).collect::<Vec<BalanceOf<Test>>>(), vec![11, 31]);
		let winner_10 = winners.iter().filter(|w| w.who == 11).nth(0).unwrap();
		let winner_30 = winners.iter().filter(|w| w.who == 31).nth(0).unwrap();

		// python implementation output:
		/*
		Votes  [
			('10', 1000, ['10']),
			('20', 1000, ['20']),
			('30', 1000, ['30']),
			('2', 50, ['10', '20']),
			('4', 1000, ['10', '30'])
		]
		Sequential Phragmén gives
		10  is elected with stake  1705.7377049180327 and score  0.0004878048780487805
		30  is elected with stake  1344.2622950819673 and score  0.0007439024390243903

		10  has load  0.0004878048780487805 and supported
		10  with stake  1000.0
		20  has load  0 and supported
		20  with stake  0
		30  has load  0.0007439024390243903 and supported
		30  with stake  1000.0
		2  has load  0.0004878048780487805 and supported
		10  with stake  50.0 20  with stake  0.0
		4  has load  0.0007439024390243903 and supported
		10  with stake  655.7377049180328 30  with stake  344.26229508196724

		Sequential Phragmén with post processing gives
		10  is elected with stake  1525.0 and score  0.0004878048780487805
		30  is elected with stake  1525.0 and score  0.0007439024390243903

		10  has load  0.0004878048780487805 and supported
		10  with stake  1000.0
		20  has load  0 and supported
		20  with stake  0
		30  has load  0.0007439024390243903 and supported
		30  with stake  1000.0
		2  has load  0.0004878048780487805 and supported
		10  with stake  50.0 20  with stake  0.0
		4  has load  0.0007439024390243903 and supported
		10  with stake  475.0 30  with stake  525.0

		assert_eq!(winner_10.exposure.total, 1000 + 525);
		assert_eq!(winner_10.score, Perquintill::from_quintillionths(487804878048780));
		assert_eq!(winner_10.exposure.others[0].value, 475);
		assert_eq!(winner_10.exposure.others[1].value, 50);
		assert_eq!(winner_30.exposure.total, 1000 + 525);
		assert_eq!(winner_30.score, Perquintill::from_quintillionths(743902439024390));
		assert_eq!(winner_30.exposure.others[0].value, 525);
	})
}

#[test]
fn switching_roles() {
	// Show: It should be possible to switch between roles (nominator, validator, idle) with minimal overhead.
	with_externalities(&mut ExtBuilder::default()
		.nominate(false)
		.sessions_per_era(3)
		.build(),
	|| {
		// Reset reward destination
		for i in &[10, 20] { assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); }

		assert_eq!(Session::validators(), vec![20, 10]);

		// put some money in account that we'll use.
		for i in 1..7 { let _ = Balances::deposit_creating(&i, 5000); }

		// add 2 nominators
		assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::Controller));
		assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 5]));

		assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller));
		assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 1]));

		// add a new validator candidate
		assert_ok!(Staking::bond(Origin::signed(5), 6, 1000, RewardDestination::Controller));
		assert_ok!(Staking::validate(Origin::signed(6), ValidatorPrefs::default()));

		System::set_block_number(1);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Session::validators(), vec![20, 10]);

		System::set_block_number(2);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Session::validators(), vec![20, 10]);

		// new block --> ne era --> new validators
		System::set_block_number(3);
		Session::check_rotate_session(System::block_number());

		// with current nominators 10 and 5 have the most stake
		assert_eq!(Session::validators(), vec![6, 10]);

		// 2 decides to be a validator. Consequences:
		// new stakes:
		// 10: 1000 self vote
		// 6: 1000 self vote
		// 20: 1000 self vote + 500 vote
		// 2: 2000 self  vote + 500 vote.
		assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default()));

		System::set_block_number(4);
		Session::check_rotate_session(System::block_number());
		assert_eq!(Session::validators(), vec![6, 10]);

		System::set_block_number(5);
		Session::check_rotate_session(System::block_number());
		assert_eq!(Session::validators(), vec![6, 10]);

		System::set_block_number(6);
		Session::check_rotate_session(System::block_number());
		assert_eq!(Session::validators(), vec![2, 20]);
	});
}

#[test]
fn wrong_vote_is_null() {
	with_externalities(&mut ExtBuilder::default()
		.nominate(false)
		.validator_pool(true)
	.build(),
	|| {
		assert_eq!(Session::validators(), vec![40, 30]);

		// put some money in account that we'll use.
		for i in 1..3 { let _ = Balances::deposit_creating(&i, 5000); }

		// add 1 nominators
		assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::default()));
		assert_ok!(Staking::nominate(Origin::signed(2), vec![
			11, 21, 			// good votes
			1, 2, 15, 1000, 25  // crap votes. No effect.
		]));

		// new block
		System::set_block_number(1);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Session::validators(), vec![20, 10]);
	});
}

#[test]
fn bond_with_no_staked_value() {
	// Behavior when someone bonds with no staked value.
	// Particularly when she votes and the candidate is elected.
	with_externalities(&mut ExtBuilder::default()
	.validator_count(3)
	.nominate(false)
	.minimum_validator_count(1)
	.build(), || {
		// setup
		assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller));
		assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller));
		let _ = Balances::deposit_creating(&3, 1000);
		let initial_balance_2 = Balances::free_balance(&2);
		let initial_balance_4 = Balances::free_balance(&4);

		// initial validators
		assert_eq!(Session::validators(), vec![20, 10]);

		// Stingy validator.
		assert_ok!(Staking::bond(Origin::signed(1), 2, 0, RewardDestination::Controller));
		assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default()));

		System::set_block_number(1);
		Session::check_rotate_session(System::block_number());

		// Not elected even though we want 3.
		assert_eq!(Session::validators(), vec![20, 10]);

		// min of 10 and 20.
		assert_eq!(Staking::slot_stake(), 1000);

		// let's make the stingy one elected.
		assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller));
		assert_ok!(Staking::nominate(Origin::signed(4), vec![1]));

		assert_eq!(Staking::ledger(4), Some(StakingLedger { stash: 3, active: 500, total: 500, unlocking: vec![]}));

		assert_eq!(Balances::free_balance(&2), initial_balance_2);
		assert_eq!(Balances::free_balance(&4), initial_balance_4);

		System::set_block_number(2);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Session::validators(), vec![20, 10, 2]);
		assert_eq!(Staking::stakers(1), Exposure { own: 0, total: 500, others: vec![IndividualExposure { who: 3, value: 500}]});

		assert_eq!(Staking::slot_stake(), 500);

		// no rewards paid to 2 and 4 yet
		assert_eq!(Balances::free_balance(&2), initial_balance_2);
		assert_eq!(Balances::free_balance(&4), initial_balance_4);

		System::set_block_number(3);
		Session::check_rotate_session(System::block_number());

		let reward = Staking::current_session_reward();
		// 2 will not get any reward
		// 4 will get all the reward share
		assert_eq!(Balances::free_balance(&2), initial_balance_2);
		// assert_eq!(Balances::free_balance(&4), initial_balance_4 + reward);
		assert_eq!(Balances::free_balance(&4), initial_balance_4 + reward);
	});
}

#[test]
fn bond_with_little_staked_value() {
	// Behavior when someone bonds with little staked value.
	// Particularly when she votes and the candidate is elected.
	with_externalities(&mut ExtBuilder::default()
		.validator_count(3)
		.nominate(false)
		.minimum_validator_count(1)
		.build(),
	|| {
		// setup
		assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller));
		assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller));
		let initial_balance_2 = Balances::free_balance(&2);

		// initial validators
		assert_eq!(Session::validators(), vec![20, 10]);

		// Stingy validator.
		assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller));
		assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default()));

		System::set_block_number(1);
		Session::check_rotate_session(System::block_number());

		// 2 is elected.
		// and fucks up the slot stake.
		assert_eq!(Session::validators(), vec![20, 10, 2]);
		assert_eq!(Staking::slot_stake(), 1);

		// Old ones are rewarded.
		assert_eq!(Balances::free_balance(&10), 1 + 10);
		assert_eq!(Balances::free_balance(&20), 1 + 10);
		// no rewards paid to 2. This was initial election.
		assert_eq!(Balances::free_balance(&2), initial_balance_2);

		System::set_block_number(2);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Session::validators(), vec![20, 10, 2]);
		assert_eq!(Staking::slot_stake(), 1);

		let reward = Staking::current_session_reward();
		// 2 will not get the full reward, practically 1
		assert_eq!(Balances::free_balance(&2), initial_balance_2 + reward.max(1));


#[test]
#[ignore] // Enable this once post-processing is on.
fn phragmen_linear_worse_case_equalize() {
	with_externalities(&mut ExtBuilder::default()
		.nominate(false)
		.validator_pool(true)
		.fare(true)
		.build(),
	|| {
		let bond_validator = |a, b| {
			let _ = Balances::deposit_creating(&(a-1), b);
			assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller));
			assert_ok!(Staking::validate(Origin::signed(a), ValidatorPrefs::default()));
		};
		let bond_nominator = |a, b, v| {
			let _ = Balances::deposit_creating(&(a-1), b);
			assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller));
			assert_ok!(Staking::nominate(Origin::signed(a), v));
		};

		for i in &[10, 20, 30, 40] { assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); }

		bond_validator(50, 1000);
		bond_validator(60, 1000);
		bond_validator(70, 1000);

		bond_nominator(2, 2000, vec![11]);
		bond_nominator(4, 1000, vec![11, 21]);
		bond_nominator(6, 1000, vec![21, 31]);
		bond_nominator(8, 1000, vec![31, 41]);
		bond_nominator(110, 1000, vec![41, 51]);
		bond_nominator(112, 1000, vec![51, 61]);
		bond_nominator(114, 1000, vec![61, 71]);

		assert_eq!(Session::validators(), vec![40, 30]);
		assert_ok!(Staking::set_validator_count(7));

		System::set_block_number(1);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Session::validators(), vec![10, 60, 40, 20, 50, 30, 70]);

		// Sequential Phragmén with post processing gives
		// 10  is elected with stake  3000.0 and score  0.00025
		// 30  is elected with stake  2008.8712884829595 and score  0.0003333333333333333
		// 50  is elected with stake  2000.0001049958742 and score  0.0003333333333333333
		// 60  is elected with stake  1991.128921508789 and score  0.0004444444444444444
		// 20  is elected with stake  2017.7421569824219 and score  0.0005277777777777777
		// 40  is elected with stake  2000.0001049958742 and score  0.0005555555555555556
		// 70  is elected with stake  1982.2574230340813 and score  0.0007222222222222222

		assert_eq!(Staking::stakers(11).total, 3000);
		assert_eq!(Staking::stakers(31).total, 2035);
		assert_eq!(Staking::stakers(51).total, 2000);
		assert_eq!(Staking::stakers(61).total, 1968);
		assert_eq!(Staking::stakers(21).total, 2035);
		assert_eq!(Staking::stakers(41).total, 2024);
		assert_eq!(Staking::stakers(71).total, 1936);
	})
}

#[test]
fn phragmen_chooses_correct_validators() {
	with_externalities(&mut ExtBuilder::default()
		.nominate(true)
		.validator_pool(true)
		.fare(true)
		.validator_count(1)
		.build(),
	|| {
		// 4 validator candidates
		// self vote + default account 100 is nominator.
		assert_eq!(Staking::validator_count(), 1);
		assert_eq!(Session::validators().len(), 1);

		System::set_block_number(1);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Session::validators().len(), 1);
	})
}

#[test]
fn phragmen_should_not_overflow_validators() {
	with_externalities(&mut ExtBuilder::default()
	.nominate(false)
	.build()
	, || {
		let bond_validator = |a, b| {
			assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller));
			assert_ok!(Staking::validate(Origin::signed(a), ValidatorPrefs::default()));
		};
		let bond_nominator = |a, b, v| {
			assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller));
			assert_ok!(Staking::nominate(Origin::signed(a), v));
		};

		for i in 1..=8 {
			let _ = Balances::make_free_balance_be(&i, u64::max_value());
		}

		let _ = Staking::chill(Origin::signed(10));
		let _ = Staking::chill(Origin::signed(20));

		bond_validator(2, u64::max_value());
		bond_validator(4, u64::max_value());

		bond_nominator(6, u64::max_value()/2, vec![1, 3]);
		bond_nominator(8, u64::max_value()/2, vec![1, 3]);

		System::set_block_number(2);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Session::validators(), vec![4, 2]);
	})
}

#[test]
fn phragmen_should_not_overflow_nominators() {
	with_externalities(&mut ExtBuilder::default()
	.nominate(false)
	.build()
	, || {
		let bond_validator = |a, b| {
			assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller));
			assert_ok!(Staking::validate(Origin::signed(a), ValidatorPrefs::default()));
		};
		let bond_nominator = |a, b, v| {
			assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller));
			assert_ok!(Staking::nominate(Origin::signed(a), v));
		};

		let _ = Staking::chill(Origin::signed(10));
		let _ = Staking::chill(Origin::signed(20));

		for i in 1..=8 {
			let _ = Balances::make_free_balance_be(&i, u64::max_value());
		}

		bond_validator(2, u64::max_value()/2);
		bond_validator(4, u64::max_value()/2);

		bond_nominator(6, u64::max_value(), vec![1, 3]);
		bond_nominator(8, u64::max_value(), vec![1, 3]);

		System::set_block_number(2);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Session::validators(), vec![4, 2]);
	})
}

#[test]
fn phragmen_should_not_overflow_ultimate() {
	with_externalities(&mut ExtBuilder::default()
	.nominate(false)
	.build()
	, || {
		let bond_validator = |a, b| {
			assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller));
			assert_ok!(Staking::validate(Origin::signed(a), ValidatorPrefs::default()));
		};
		let bond_nominator = |a, b, v| {
			assert_ok!(Staking::bond(Origin::signed(a-1), a, b, RewardDestination::Controller));
			assert_ok!(Staking::nominate(Origin::signed(a), v));
		};

		for i in 1..=8 {
			let _ = Balances::make_free_balance_be(&i, u64::max_value());
		}

		bond_validator(2, u64::max_value());
		bond_validator(4, u64::max_value());

		bond_nominator(6, u64::max_value(), vec![1, 3]);
		bond_nominator(8, u64::max_value(), vec![1, 3]);

		System::set_block_number(2);
		Session::check_rotate_session(System::block_number());

		assert_eq!(Session::validators(), vec![4, 2]);
	})
}