use crate as collator_selection;
use crate::{
mock::*, CandidacyBond, CandidateInfo, CandidateList, DesiredCandidates, Error, Invulnerables,
LastAuthoredBlock,
};
use codec::Encode;
use frame_support::{
assert_noop, assert_ok,
traits::{Currency, OnInitialize},
};
use pallet_balances::Error as BalancesError;
use sp_runtime::{testing::UintAuthorityId, traits::BadOrigin, BuildStorage};
#[test]
fn basic_setup_works() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
});
}
#[test]
fn it_should_set_invulnerables() {
new_test_ext().execute_with(|| {
let mut new_set = vec![1, 4, 3, 2];
assert_ok!(CollatorSelection::set_invulnerables(
RuntimeOrigin::signed(RootAccount::get()),
new_set.clone()
));
new_set.sort();
assert_eq!(Invulnerables::<Test>::get(), new_set);
assert_noop!(
CollatorSelection::set_invulnerables(RuntimeOrigin::signed(1), new_set),
BadOrigin
);
});
}
#[test]
fn it_should_set_invulnerables_even_with_some_invalid() {
new_test_ext().execute_with(|| {
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
let new_with_invalid = vec![1, 4, 3, 42, 2];
assert_ok!(CollatorSelection::set_invulnerables(
RuntimeOrigin::signed(RootAccount::get()),
new_with_invalid
));
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2, 3, 4]);
});
}
#[test]
fn add_invulnerable_works() {
new_test_ext().execute_with(|| {
initialize_to_block(1);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
let new = 3;
assert_ok!(CollatorSelection::add_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
new
));
System::assert_last_event(RuntimeEvent::CollatorSelection(
crate::Event::InvulnerableAdded { account_id: new },
));
assert_noop!(
CollatorSelection::add_invulnerable(RuntimeOrigin::signed(RootAccount::get()), new),
Error::<Test>::AlreadyInvulnerable
);
assert!(Invulnerables::<Test>::get().to_vec().contains(&new));
assert_noop!(CollatorSelection::add_invulnerable(RuntimeOrigin::signed(1), new), BadOrigin);
let not_validator = 42;
assert_noop!(
CollatorSelection::add_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
not_validator
),
Error::<Test>::ValidatorNotRegistered
);
});
}
#[test]
fn invulnerable_limit_works() {
new_test_ext().execute_with(|| {
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
for ii in 3..=21 {
if ii > 5 {
Balances::make_free_balance_be(&ii, 100);
let mut key = MockSessionKeys { aura: UintAuthorityId(ii) };
Session::set_keys(
RuntimeOrigin::signed(ii).into(),
key.clone(),
key.create_ownership_proof(&ii.encode()).unwrap().encode(),
)
.unwrap();
}
assert_eq!(Balances::free_balance(ii), 100);
if ii < 21 {
assert_ok!(CollatorSelection::add_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
ii
));
} else {
assert_noop!(
CollatorSelection::add_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
ii
),
Error::<Test>::TooManyInvulnerables
);
}
}
let expected: Vec<u64> = (1..=20).collect();
assert_eq!(Invulnerables::<Test>::get(), expected);
let too_many_invulnerables: Vec<u64> = (1..=21).collect();
assert_noop!(
CollatorSelection::set_invulnerables(
RuntimeOrigin::signed(RootAccount::get()),
too_many_invulnerables
),
Error::<Test>::TooManyInvulnerables
);
assert_eq!(Invulnerables::<Test>::get(), expected);
});
}
#[test]
fn remove_invulnerable_works() {
new_test_ext().execute_with(|| {
initialize_to_block(1);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_ok!(CollatorSelection::add_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
4
));
assert_ok!(CollatorSelection::add_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
3
));
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2, 3, 4]);
assert_ok!(CollatorSelection::remove_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
2
));
System::assert_last_event(RuntimeEvent::CollatorSelection(
crate::Event::InvulnerableRemoved { account_id: 2 },
));
assert_eq!(Invulnerables::<Test>::get(), vec![1, 3, 4]);
assert_noop!(
CollatorSelection::remove_invulnerable(RuntimeOrigin::signed(RootAccount::get()), 2),
Error::<Test>::NotInvulnerable
);
assert_noop!(
CollatorSelection::remove_invulnerable(RuntimeOrigin::signed(1), 3),
BadOrigin
);
});
}
#[test]
fn candidate_to_invulnerable_works() {
new_test_ext().execute_with(|| {
initialize_to_block(1);
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Balances::free_balance(4), 100);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_eq!(Balances::free_balance(3), 90);
assert_eq!(Balances::free_balance(4), 90);
assert_ok!(CollatorSelection::add_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
3
));
System::assert_has_event(RuntimeEvent::CollatorSelection(crate::Event::CandidateRemoved {
account_id: 3,
}));
System::assert_has_event(RuntimeEvent::CollatorSelection(
crate::Event::InvulnerableAdded { account_id: 3 },
));
assert!(Invulnerables::<Test>::get().to_vec().contains(&3));
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(CandidateList::<Test>::get().iter().count(), 1);
assert_ok!(CollatorSelection::add_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
4
));
System::assert_has_event(RuntimeEvent::CollatorSelection(crate::Event::CandidateRemoved {
account_id: 4,
}));
System::assert_has_event(RuntimeEvent::CollatorSelection(
crate::Event::InvulnerableAdded { account_id: 4 },
));
assert!(Invulnerables::<Test>::get().to_vec().contains(&4));
assert_eq!(Balances::free_balance(4), 100);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
});
}
#[test]
fn set_desired_candidates_works() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_ok!(CollatorSelection::set_desired_candidates(
RuntimeOrigin::signed(RootAccount::get()),
7
));
assert_eq!(DesiredCandidates::<Test>::get(), 7);
assert_noop!(
CollatorSelection::set_desired_candidates(RuntimeOrigin::signed(1), 8),
BadOrigin
);
});
}
#[test]
fn set_candidacy_bond_empty_candidate_list() {
new_test_ext().execute_with(|| {
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert!(CandidateList::<Test>::get().is_empty());
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
7
));
assert_eq!(CandidacyBond::<Test>::get(), 7);
assert!(CandidateList::<Test>::get().is_empty());
assert_noop!(CollatorSelection::set_candidacy_bond(RuntimeOrigin::signed(1), 8), BadOrigin);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
20
));
assert!(CandidateList::<Test>::get().is_empty());
assert_eq!(CandidacyBond::<Test>::get(), 20);
});
}
#[test]
fn set_candidacy_bond_with_one_candidate() {
new_test_ext().execute_with(|| {
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert!(CandidateList::<Test>::get().is_empty());
let candidate_3 = CandidateInfo { who: 3, deposit: 10 };
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_eq!(CandidateList::<Test>::get(), vec![candidate_3.clone()]);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
7
));
assert_eq!(CandidacyBond::<Test>::get(), 7);
assert_eq!(CandidateList::<Test>::get(), vec![candidate_3.clone()]);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
10
));
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get(), vec![candidate_3.clone()]);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
20
));
assert!(CandidateList::<Test>::get().is_empty());
});
}
#[test]
fn set_candidacy_bond_with_many_candidates_same_deposit() {
new_test_ext().execute_with(|| {
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert!(CandidateList::<Test>::get().is_empty());
let candidate_3 = CandidateInfo { who: 3, deposit: 10 };
let candidate_4 = CandidateInfo { who: 4, deposit: 10 };
let candidate_5 = CandidateInfo { who: 5, deposit: 10 };
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_eq!(
CandidateList::<Test>::get(),
vec![candidate_5.clone(), candidate_4.clone(), candidate_3.clone()]
);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
7
));
assert_eq!(CandidacyBond::<Test>::get(), 7);
assert_eq!(
CandidateList::<Test>::get(),
vec![candidate_5.clone(), candidate_4.clone(), candidate_3.clone()]
);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
10
));
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(
CandidateList::<Test>::get(),
vec![candidate_5.clone(), candidate_4.clone(), candidate_3.clone()]
);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
20
));
assert!(CandidateList::<Test>::get().is_empty());
});
}
#[test]
fn set_candidacy_bond_with_many_candidates_different_deposits() {
new_test_ext().execute_with(|| {
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert!(CandidateList::<Test>::get().is_empty());
let candidate_3 = CandidateInfo { who: 3, deposit: 10 };
let candidate_4 = CandidateInfo { who: 4, deposit: 20 };
let candidate_5 = CandidateInfo { who: 5, deposit: 30 };
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 30));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 20));
assert_eq!(
CandidateList::<Test>::get(),
vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()]
);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
7
));
assert_eq!(CandidacyBond::<Test>::get(), 7);
assert_eq!(
CandidateList::<Test>::get(),
vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()]
);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
10
));
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(
CandidateList::<Test>::get(),
vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()]
);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
20
));
assert_eq!(CandidacyBond::<Test>::get(), 20);
assert_eq!(CandidateList::<Test>::get(), vec![candidate_4.clone(), candidate_5.clone()]);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
25
));
assert_eq!(CandidacyBond::<Test>::get(), 25);
assert_eq!(CandidateList::<Test>::get(), vec![candidate_5.clone()]);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
5
));
assert_eq!(CandidacyBond::<Test>::get(), 5);
assert_eq!(CandidateList::<Test>::get(), vec![candidate_5.clone()]);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 10));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 20));
assert_eq!(
CandidateList::<Test>::get(),
vec![candidate_3.clone(), candidate_4.clone(), candidate_5.clone()]
);
assert_ok!(CollatorSelection::set_candidacy_bond(
RuntimeOrigin::signed(RootAccount::get()),
40
));
assert_eq!(CandidacyBond::<Test>::get(), 40);
assert!(CandidateList::<Test>::get().is_empty());
});
}
#[test]
fn cannot_register_candidate_if_too_many() {
new_test_ext().execute_with(|| {
<crate::DesiredCandidates<Test>>::put(1);
for i in 6..=23 {
Balances::make_free_balance_be(&i, 100);
let mut key = MockSessionKeys { aura: UintAuthorityId(i) };
Session::set_keys(
RuntimeOrigin::signed(i).into(),
key.clone(),
key.create_ownership_proof(&i.encode()).unwrap().encode(),
)
.unwrap();
}
for c in 3..=22 {
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(c)));
}
assert_noop!(
CollatorSelection::register_as_candidate(RuntimeOrigin::signed(23)),
Error::<Test>::TooManyCandidates,
);
})
}
#[test]
fn cannot_unregister_candidate_if_too_few() {
new_test_ext().execute_with(|| {
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_ok!(CollatorSelection::remove_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
1
));
assert_noop!(
CollatorSelection::remove_invulnerable(RuntimeOrigin::signed(RootAccount::get()), 2),
Error::<Test>::TooFewEligibleCollators,
);
<crate::DesiredCandidates<Test>>::put(1);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::remove_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
2
));
assert_noop!(
CollatorSelection::leave_intent(RuntimeOrigin::signed(4)),
Error::<Test>::TooFewEligibleCollators,
);
})
}
#[test]
fn cannot_register_as_candidate_if_invulnerable() {
new_test_ext().execute_with(|| {
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_noop!(
CollatorSelection::register_as_candidate(RuntimeOrigin::signed(1)),
Error::<Test>::AlreadyInvulnerable,
);
})
}
#[test]
fn cannot_register_as_candidate_if_keys_not_registered() {
new_test_ext().execute_with(|| {
assert_noop!(
CollatorSelection::register_as_candidate(RuntimeOrigin::signed(42)),
Error::<Test>::ValidatorNotRegistered
);
})
}
#[test]
fn cannot_register_dupe_candidate() {
new_test_ext().execute_with(|| {
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
let addition = CandidateInfo { who: 3, deposit: 10 };
assert_eq!(
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>(),
vec![addition]
);
assert_eq!(LastAuthoredBlock::<Test>::get(3), 10);
assert_eq!(Balances::free_balance(3), 90);
assert_noop!(
CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)),
Error::<Test>::AlreadyCandidate,
);
})
}
#[test]
fn cannot_register_as_candidate_if_poor() {
new_test_ext().execute_with(|| {
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Balances::free_balance(33), 0);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_noop!(
CollatorSelection::register_as_candidate(RuntimeOrigin::signed(33)),
BalancesError::<Test>::InsufficientBalance,
);
});
}
#[test]
fn register_as_candidate_works() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Balances::free_balance(4), 100);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_eq!(Balances::free_balance(3), 90);
assert_eq!(Balances::free_balance(4), 90);
assert_eq!(CandidateList::<Test>::get().iter().count(), 2);
});
}
#[test]
fn cannot_take_candidate_slot_if_invulnerable() {
new_test_ext().execute_with(|| {
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_noop!(
CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(1), 50u64.into(), 2),
Error::<Test>::AlreadyInvulnerable,
);
})
}
#[test]
fn cannot_take_candidate_slot_if_keys_not_registered() {
new_test_ext().execute_with(|| {
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_noop!(
CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(42), 50u64.into(), 3),
Error::<Test>::ValidatorNotRegistered
);
})
}
#[test]
fn cannot_take_candidate_slot_if_duplicate() {
new_test_ext().execute_with(|| {
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
let candidate_3 = CandidateInfo { who: 3, deposit: 10 };
let candidate_4 = CandidateInfo { who: 4, deposit: 10 };
let actual_candidates = CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>();
assert_eq!(actual_candidates, vec![candidate_4, candidate_3]);
assert_eq!(LastAuthoredBlock::<Test>::get(3), 10);
assert_eq!(LastAuthoredBlock::<Test>::get(4), 10);
assert_eq!(Balances::free_balance(3), 90);
assert_noop!(
CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(3), 50u64.into(), 4),
Error::<Test>::AlreadyCandidate,
);
})
}
#[test]
fn cannot_take_candidate_slot_if_target_invalid() {
new_test_ext().execute_with(|| {
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
let candidate_3 = CandidateInfo { who: 3, deposit: 10 };
assert_eq!(
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>(),
vec![candidate_3]
);
assert_eq!(LastAuthoredBlock::<Test>::get(3), 10);
assert_eq!(Balances::free_balance(3), 90);
assert_eq!(Balances::free_balance(4), 100);
assert_noop!(
CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(4), 50u64.into(), 5),
Error::<Test>::TargetIsNotCandidate,
);
})
}
#[test]
fn cannot_take_candidate_slot_if_poor() {
new_test_ext().execute_with(|| {
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Balances::free_balance(33), 0);
assert_ok!(CollatorSelection::take_candidate_slot(
RuntimeOrigin::signed(3),
20u64.into(),
4
));
assert_noop!(
CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(33), 30u64.into(), 3),
BalancesError::<Test>::InsufficientBalance,
);
});
}
#[test]
fn cannot_take_candidate_slot_if_insufficient_deposit() {
new_test_ext().execute_with(|| {
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 60u64.into()));
assert_eq!(Balances::free_balance(3), 40);
assert_eq!(Balances::free_balance(4), 100);
assert_noop!(
CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(4), 5u64.into(), 3),
Error::<Test>::InsufficientBond,
);
assert_eq!(Balances::free_balance(3), 40);
assert_eq!(Balances::free_balance(4), 100);
});
}
#[test]
fn cannot_take_candidate_slot_if_deposit_less_than_target() {
new_test_ext().execute_with(|| {
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 60u64.into()));
assert_eq!(Balances::free_balance(3), 40);
assert_eq!(Balances::free_balance(4), 100);
assert_noop!(
CollatorSelection::take_candidate_slot(RuntimeOrigin::signed(4), 20u64.into(), 3),
Error::<Test>::InsufficientBond,
);
assert_eq!(Balances::free_balance(3), 40);
assert_eq!(Balances::free_balance(4), 100);
});
}
#[test]
fn take_candidate_slot_works() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Balances::free_balance(4), 100);
assert_eq!(Balances::free_balance(5), 100);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_eq!(Balances::free_balance(3), 90);
assert_eq!(Balances::free_balance(4), 90);
assert_eq!(Balances::free_balance(5), 90);
assert_eq!(CandidateList::<Test>::get().iter().count(), 3);
Balances::make_free_balance_be(&6, 100);
let mut key = MockSessionKeys { aura: UintAuthorityId(6) };
Session::set_keys(
RuntimeOrigin::signed(6).into(),
key.clone(),
key.create_ownership_proof(&6u64.encode()).unwrap().encode(),
)
.unwrap();
assert_ok!(CollatorSelection::take_candidate_slot(
RuntimeOrigin::signed(6),
50u64.into(),
4
));
assert_eq!(Balances::free_balance(3), 90);
assert_eq!(Balances::free_balance(4), 100);
assert_eq!(Balances::free_balance(5), 90);
assert_eq!(Balances::free_balance(6), 50);
let candidate_3 = CandidateInfo { who: 3, deposit: 10 };
let candidate_6 = CandidateInfo { who: 6, deposit: 50 };
let candidate_5 = CandidateInfo { who: 5, deposit: 10 };
let mut actual_candidates =
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>();
actual_candidates.sort_by(|info_1, info_2| info_1.deposit.cmp(&info_2.deposit));
assert_eq!(
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>(),
vec![candidate_5, candidate_3, candidate_6]
);
});
}
#[test]
fn increase_candidacy_bond_non_candidate_account() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_noop!(
CollatorSelection::update_bond(RuntimeOrigin::signed(5), 20),
Error::<Test>::NotCandidate
);
});
}
#[test]
fn increase_candidacy_bond_insufficient_balance() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Balances::free_balance(4), 100);
assert_eq!(Balances::free_balance(5), 100);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_eq!(Balances::free_balance(3), 90);
assert_eq!(Balances::free_balance(4), 90);
assert_eq!(Balances::free_balance(5), 90);
assert_noop!(
CollatorSelection::update_bond(RuntimeOrigin::signed(3), 110),
BalancesError::<Test>::InsufficientBalance
);
assert_eq!(Balances::free_balance(3), 90);
});
}
#[test]
fn increase_candidacy_bond_works() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Balances::free_balance(4), 100);
assert_eq!(Balances::free_balance(5), 100);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_eq!(Balances::free_balance(3), 90);
assert_eq!(Balances::free_balance(4), 90);
assert_eq!(Balances::free_balance(5), 90);
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 20));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 30));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 40));
assert_eq!(CandidateList::<Test>::get().iter().count(), 3);
assert_eq!(Balances::free_balance(3), 80);
assert_eq!(Balances::free_balance(4), 70);
assert_eq!(Balances::free_balance(5), 60);
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 40));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 60));
assert_eq!(CandidateList::<Test>::get().iter().count(), 3);
assert_eq!(Balances::free_balance(3), 60);
assert_eq!(Balances::free_balance(4), 40);
assert_eq!(Balances::free_balance(5), 60);
});
}
#[test]
fn decrease_candidacy_bond_non_candidate_account() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_eq!(Balances::free_balance(5), 100);
assert_noop!(
CollatorSelection::update_bond(RuntimeOrigin::signed(5), 10),
Error::<Test>::NotCandidate
);
assert_eq!(Balances::free_balance(5), 100);
});
}
#[test]
fn decrease_candidacy_bond_insufficient_funds() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Balances::free_balance(4), 100);
assert_eq!(Balances::free_balance(5), 100);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 60));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 60));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60));
assert_eq!(Balances::free_balance(3), 40);
assert_eq!(Balances::free_balance(4), 40);
assert_eq!(Balances::free_balance(5), 40);
assert_noop!(
CollatorSelection::update_bond(RuntimeOrigin::signed(3), 0),
Error::<Test>::DepositTooLow
);
assert_noop!(
CollatorSelection::update_bond(RuntimeOrigin::signed(4), 5),
Error::<Test>::DepositTooLow
);
assert_noop!(
CollatorSelection::update_bond(RuntimeOrigin::signed(5), 9),
Error::<Test>::DepositTooLow
);
assert_eq!(Balances::free_balance(3), 40);
assert_eq!(Balances::free_balance(4), 40);
assert_eq!(Balances::free_balance(5), 40);
});
}
#[test]
fn decrease_candidacy_bond_occupying_top_slot() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 30u64.into()));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 30u64.into()));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60u64.into()));
let candidate_3 = CandidateInfo { who: 3, deposit: 30 };
let candidate_4 = CandidateInfo { who: 4, deposit: 30 };
let candidate_5 = CandidateInfo { who: 5, deposit: 60 };
assert_eq!(
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>(),
vec![candidate_4, candidate_3, candidate_5]
);
assert_noop!(
CollatorSelection::update_bond(RuntimeOrigin::signed(5), 29),
Error::<Test>::InvalidUnreserve,
);
assert_noop!(
CollatorSelection::update_bond(RuntimeOrigin::signed(3), 29),
Error::<Test>::InvalidUnreserve,
);
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 29u64.into()));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 35u64.into()));
let candidate_3 = CandidateInfo { who: 3, deposit: 30 };
let candidate_4 = CandidateInfo { who: 4, deposit: 35 };
let candidate_5 = CandidateInfo { who: 5, deposit: 60 };
assert_eq!(
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>(),
vec![candidate_3, candidate_4, candidate_5]
);
assert_noop!(
CollatorSelection::update_bond(RuntimeOrigin::signed(5), 34),
Error::<Test>::InvalidUnreserve,
);
assert_noop!(
CollatorSelection::update_bond(RuntimeOrigin::signed(4), 34),
Error::<Test>::InvalidUnreserve,
);
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 10u64.into()));
});
}
#[test]
fn decrease_candidacy_bond_works() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Balances::free_balance(4), 100);
assert_eq!(Balances::free_balance(5), 100);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_eq!(Balances::free_balance(3), 90);
assert_eq!(Balances::free_balance(4), 90);
assert_eq!(Balances::free_balance(5), 90);
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 20));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 30));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 40));
assert_eq!(CandidateList::<Test>::get().iter().count(), 3);
assert_eq!(Balances::free_balance(3), 80);
assert_eq!(Balances::free_balance(4), 70);
assert_eq!(Balances::free_balance(5), 60);
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 10));
assert_eq!(CandidateList::<Test>::get().iter().count(), 3);
assert_eq!(Balances::free_balance(3), 90);
assert_eq!(Balances::free_balance(4), 70);
assert_eq!(Balances::free_balance(5), 60);
});
}
#[test]
fn update_candidacy_bond_with_identical_amount() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Balances::free_balance(4), 100);
assert_eq!(Balances::free_balance(5), 100);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_eq!(Balances::free_balance(3), 90);
assert_eq!(Balances::free_balance(4), 90);
assert_eq!(Balances::free_balance(5), 90);
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 20));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 30));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 40));
assert_eq!(CandidateList::<Test>::get().iter().count(), 3);
assert_eq!(Balances::free_balance(3), 80);
assert_eq!(Balances::free_balance(4), 70);
assert_eq!(Balances::free_balance(5), 60);
assert_noop!(
CollatorSelection::update_bond(RuntimeOrigin::signed(3), 20),
Error::<Test>::IdenticalDeposit
);
assert_eq!(Balances::free_balance(3), 80);
});
}
#[test]
fn candidate_list_works() {
new_test_ext().execute_with(|| {
assert_eq!(DesiredCandidates::<Test>::get(), 2);
assert_eq!(CandidacyBond::<Test>::get(), 10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(Balances::free_balance(4), 100);
assert_eq!(Balances::free_balance(5), 100);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 20));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 30));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 25));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 10));
let candidate_3 = CandidateInfo { who: 3, deposit: 30 };
let candidate_4 = CandidateInfo { who: 4, deposit: 25 };
let candidate_5 = CandidateInfo { who: 5, deposit: 10 };
assert_eq!(
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>(),
vec![candidate_5, candidate_4, candidate_3]
);
});
}
#[test]
fn leave_intent() {
new_test_ext().execute_with(|| {
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_eq!(Balances::free_balance(3), 90);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_eq!(Balances::free_balance(5), 90);
assert_noop!(
CollatorSelection::leave_intent(RuntimeOrigin::signed(4)),
Error::<Test>::NotCandidate
);
assert_ok!(CollatorSelection::leave_intent(RuntimeOrigin::signed(3)));
assert_eq!(Balances::free_balance(3), 100);
assert_eq!(LastAuthoredBlock::<Test>::get(3), 0);
});
}
#[test]
fn authorship_event_handler() {
new_test_ext().execute_with(|| {
Balances::make_free_balance_be(&CollatorSelection::account_id(), 105);
assert_eq!(Balances::free_balance(4), 100);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
Authorship::on_initialize(1);
let collator = CandidateInfo { who: 4, deposit: 10 };
assert_eq!(
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>(),
vec![collator]
);
assert_eq!(LastAuthoredBlock::<Test>::get(4), 0);
assert_eq!(Balances::free_balance(4), 140);
assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 55);
});
}
#[test]
fn fees_edgecases() {
new_test_ext().execute_with(|| {
Authorship::on_initialize(1);
Balances::make_free_balance_be(&CollatorSelection::account_id(), 5);
assert_eq!(Balances::free_balance(4), 100);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
Authorship::on_initialize(1);
let collator = CandidateInfo { who: 4, deposit: 10 };
assert_eq!(
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>(),
vec![collator]
);
assert_eq!(LastAuthoredBlock::<Test>::get(4), 0);
assert_eq!(Balances::free_balance(4), 90);
assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 5);
});
}
#[test]
fn session_management_single_candidate() {
new_test_ext().execute_with(|| {
initialize_to_block(1);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(4);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_eq!(CandidateList::<Test>::get().iter().count(), 1);
initialize_to_block(10);
assert_eq!(SessionChangeBlock::get(), 10);
assert_eq!(Session::validators(), vec![1, 2]);
assert_eq!(Session::queued_keys().len(), 3);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(20);
assert_eq!(SessionChangeBlock::get(), 20);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3]);
});
}
#[test]
fn session_management_max_candidates() {
new_test_ext().execute_with(|| {
initialize_to_block(1);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(4);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_eq!(CandidateList::<Test>::get().iter().count(), 3);
initialize_to_block(10);
assert_eq!(SessionChangeBlock::get(), 10);
assert_eq!(Session::validators(), vec![1, 2]);
assert_eq!(Session::queued_keys().len(), 4);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(20);
assert_eq!(SessionChangeBlock::get(), 20);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3, 4]);
});
}
#[test]
fn session_management_increase_bid_with_list_update() {
new_test_ext().execute_with(|| {
initialize_to_block(1);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(4);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60));
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_eq!(CandidateList::<Test>::get().iter().count(), 3);
initialize_to_block(10);
assert_eq!(SessionChangeBlock::get(), 10);
assert_eq!(Session::validators(), vec![1, 2]);
assert_eq!(Session::queued_keys().len(), 4);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(20);
assert_eq!(SessionChangeBlock::get(), 20);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 5, 3]);
});
}
#[test]
fn session_management_candidate_list_eager_sort() {
new_test_ext().execute_with(|| {
initialize_to_block(1);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(4);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60));
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_eq!(CandidateList::<Test>::get().iter().count(), 3);
initialize_to_block(10);
assert_eq!(SessionChangeBlock::get(), 10);
assert_eq!(Session::validators(), vec![1, 2]);
assert_eq!(Session::queued_keys().len(), 4);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(20);
assert_eq!(SessionChangeBlock::get(), 20);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 5, 3]);
});
}
#[test]
fn session_management_reciprocal_outbidding() {
new_test_ext().execute_with(|| {
initialize_to_block(1);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(4);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60));
initialize_to_block(5);
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 70));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 70));
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_eq!(CandidateList::<Test>::get().iter().count(), 3);
initialize_to_block(10);
assert_eq!(SessionChangeBlock::get(), 10);
assert_eq!(Session::validators(), vec![1, 2]);
assert_eq!(Session::queued_keys().len(), 4);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(20);
assert_eq!(SessionChangeBlock::get(), 20);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 4, 3]);
});
}
#[test]
fn session_management_decrease_bid_after_auction() {
new_test_ext().execute_with(|| {
initialize_to_block(1);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(4);
assert_eq!(SessionChangeBlock::get(), 0);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 60));
initialize_to_block(5);
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(4), 70));
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(3), 70));
initialize_to_block(5);
assert_ok!(CollatorSelection::update_bond(RuntimeOrigin::signed(5), 10));
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
assert_eq!(CandidateList::<Test>::get().iter().count(), 3);
initialize_to_block(10);
assert_eq!(SessionChangeBlock::get(), 10);
assert_eq!(Session::validators(), vec![1, 2]);
assert_eq!(Session::queued_keys().len(), 4);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);
initialize_to_block(20);
assert_eq!(SessionChangeBlock::get(), 20);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 4, 3]);
});
}
#[test]
fn kick_mechanism() {
new_test_ext().execute_with(|| {
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
initialize_to_block(10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 2);
initialize_to_block(20);
assert_eq!(SessionChangeBlock::get(), 20);
assert_eq!(CandidateList::<Test>::get().iter().count(), 1);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3, 4]);
let collator = CandidateInfo { who: 4, deposit: 10 };
assert_eq!(
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>(),
vec![collator]
);
assert_eq!(LastAuthoredBlock::<Test>::get(4), 20);
initialize_to_block(30);
assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 4]);
assert_eq!(Balances::free_balance(3), 100);
});
}
#[test]
fn should_not_kick_mechanism_too_few() {
new_test_ext().execute_with(|| {
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2]);
assert_ok!(CollatorSelection::remove_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
1
));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));
assert_ok!(CollatorSelection::remove_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
2
));
initialize_to_block(10);
assert_eq!(CandidateList::<Test>::get().iter().count(), 2);
initialize_to_block(20);
assert_eq!(SessionChangeBlock::get(), 20);
assert_eq!(CandidateList::<Test>::get().iter().count(), 1);
assert_eq!(SessionHandlerCollators::get(), vec![3, 5]);
let collator = CandidateInfo { who: 3, deposit: 10 };
assert_eq!(
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>(),
vec![collator]
);
assert_eq!(LastAuthoredBlock::<Test>::get(4), 20);
initialize_to_block(30);
assert_eq!(SessionHandlerCollators::get(), vec![3]);
assert_eq!(Balances::free_balance(5), 100);
});
}
#[test]
fn should_kick_invulnerables_from_candidates_on_session_change() {
new_test_ext().execute_with(|| {
assert_eq!(CandidateList::<Test>::get().iter().count(), 0);
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));
assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));
assert_eq!(Balances::free_balance(3), 90);
assert_eq!(Balances::free_balance(4), 90);
assert_ok!(CollatorSelection::set_invulnerables(
RuntimeOrigin::signed(RootAccount::get()),
vec![1, 2, 3]
));
let collator_3 = CandidateInfo { who: 3, deposit: 10 };
let collator_4 = CandidateInfo { who: 4, deposit: 10 };
let actual_candidates = CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>();
assert_eq!(actual_candidates, vec![collator_4.clone(), collator_3]);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2, 3]);
initialize_to_block(10);
assert_eq!(
CandidateList::<Test>::get().iter().cloned().collect::<Vec<_>>(),
vec![collator_4]
);
assert_eq!(Invulnerables::<Test>::get(), vec![1, 2, 3]);
assert_eq!(Balances::free_balance(3), 100);
});
}
#[test]
#[should_panic = "duplicate invulnerables in genesis."]
fn cannot_set_genesis_value_twice() {
sp_tracing::try_init_simple();
let mut t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
let invulnerables = vec![1, 1];
let collator_selection = collator_selection::GenesisConfig::<Test> {
desired_candidates: 2,
candidacy_bond: 10,
invulnerables,
};
collator_selection.assimilate_storage(&mut t).unwrap();
}