git.delta.rocks / unique-network / refs/commits / 8f7419bc1620

difftreelog

source

pallets/collator-selection/src/tests.rs13.0 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617// Original license:18// Copyright (C) 2021 Parity Technologies (UK) Ltd.19// SPDX-License-Identifier: Apache-2.02021// Licensed under the Apache License, Version 2.0 (the "License");22// you may not use this file except in compliance with the License.23// You may obtain a copy of the License at24//25// 	http://www.apache.org/licenses/LICENSE-2.026//27// Unless required by applicable law or agreed to in writing, software28// distributed under the License is distributed on an "AS IS" BASIS,29// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.30// See the License for the specific language governing permissions and31// limitations under the License.3233use crate as collator_selection;34use crate::{mock::*, CandidateInfo, Error};35use frame_support::{36	assert_noop, assert_ok,37	traits::{Currency, GenesisBuild, OnInitialize},38};39use pallet_balances::Error as BalancesError;40use sp_runtime::traits::BadOrigin;4142#[test]43fn basic_setup_works() {44	new_test_ext().execute_with(|| {45		assert_eq!(CollatorSelection::desired_candidates(), 2);46		assert_eq!(CollatorSelection::candidacy_bond(), 10);4748		assert!(CollatorSelection::candidates().is_empty());49		assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);50	});51}5253#[test]54fn it_should_set_invulnerables() {55	new_test_ext().execute_with(|| {56		let new_set = vec![1, 2, 3, 4];57		assert_ok!(CollatorSelection::set_invulnerables(58			RuntimeOrigin::signed(RootAccount::get()),59			new_set.clone()60		));61		assert_eq!(CollatorSelection::invulnerables(), new_set);6263		// cannot set with non-root.64		assert_noop!(65			CollatorSelection::set_invulnerables(RuntimeOrigin::signed(1), new_set.clone()),66			BadOrigin67		);6869		// cannot set invulnerables without associated validator keys70		let invulnerables = vec![7];71		assert_noop!(72			CollatorSelection::set_invulnerables(73				RuntimeOrigin::signed(RootAccount::get()),74				invulnerables.clone()75			),76			Error::<Test>::ValidatorNotRegistered77		);78	});79}8081#[test]82fn set_desired_candidates_works() {83	new_test_ext().execute_with(|| {84		// given85		assert_eq!(CollatorSelection::desired_candidates(), 2);8687		// can set88		assert_ok!(CollatorSelection::set_desired_candidates(89			RuntimeOrigin::signed(RootAccount::get()),90			791		));92		assert_eq!(CollatorSelection::desired_candidates(), 7);9394		// rejects bad origin95		assert_noop!(96			CollatorSelection::set_desired_candidates(RuntimeOrigin::signed(1), 8),97			BadOrigin98		);99	});100}101102#[test]103fn set_candidacy_bond() {104	new_test_ext().execute_with(|| {105		// given106		assert_eq!(CollatorSelection::candidacy_bond(), 10);107108		// can set109		assert_ok!(CollatorSelection::set_candidacy_bond(110			RuntimeOrigin::signed(RootAccount::get()),111			7112		));113		assert_eq!(CollatorSelection::candidacy_bond(), 7);114115		// rejects bad origin.116		assert_noop!(CollatorSelection::set_candidacy_bond(RuntimeOrigin::signed(1), 8), BadOrigin);117	});118}119120#[test]121fn cannot_register_candidate_if_too_many() {122	new_test_ext().execute_with(|| {123		// reset desired candidates:124		<crate::DesiredCandidates<Test>>::put(0);125126		// can't accept anyone anymore.127		assert_noop!(128			CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)),129			Error::<Test>::TooManyCandidates,130		);131132		// reset desired candidates:133		<crate::DesiredCandidates<Test>>::put(1);134		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));135136		// but no more137		assert_noop!(138			CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)),139			Error::<Test>::TooManyCandidates,140		);141	})142}143144#[test]145fn cannot_unregister_candidate_if_too_few() {146	new_test_ext().execute_with(|| {147		// reset desired candidates:148		<crate::DesiredCandidates<Test>>::put(1);149		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));150151		// can not remove too few152		assert_noop!(153			CollatorSelection::leave_intent(RuntimeOrigin::signed(4)),154			Error::<Test>::TooFewCandidates,155		);156	})157}158159#[test]160fn cannot_register_as_candidate_if_invulnerable() {161	new_test_ext().execute_with(|| {162		assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);163164		// can't 1 because it is invulnerable.165		assert_noop!(166			CollatorSelection::register_as_candidate(RuntimeOrigin::signed(1)),167			Error::<Test>::AlreadyInvulnerable,168		);169	})170}171172#[test]173fn cannot_register_as_candidate_if_keys_not_registered() {174	new_test_ext().execute_with(|| {175		// can't 7 because keys not registered.176		assert_noop!(177			CollatorSelection::register_as_candidate(RuntimeOrigin::signed(7)),178			Error::<Test>::ValidatorNotRegistered179		);180	})181}182183#[test]184fn cannot_register_dupe_candidate() {185	new_test_ext().execute_with(|| {186		// can add 3 as candidate187		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));188		let addition = CandidateInfo { who: 3, deposit: 10 };189		assert_eq!(CollatorSelection::candidates(), vec![addition]);190		assert_eq!(CollatorSelection::last_authored_block(3), 10);191		assert_eq!(Balances::free_balance(3), 90);192193		// but no more194		assert_noop!(195			CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)),196			Error::<Test>::AlreadyCandidate,197		);198	})199}200201#[test]202fn cannot_register_as_candidate_if_poor() {203	new_test_ext().execute_with(|| {204		assert_eq!(Balances::free_balance(&3), 100);205		assert_eq!(Balances::free_balance(&33), 0);206207		// works208		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));209210		// poor211		assert_noop!(212			CollatorSelection::register_as_candidate(RuntimeOrigin::signed(33)),213			BalancesError::<Test>::InsufficientBalance,214		);215	});216}217218#[test]219fn register_as_candidate_works() {220	new_test_ext().execute_with(|| {221		// given222		assert_eq!(CollatorSelection::desired_candidates(), 2);223		assert_eq!(CollatorSelection::candidacy_bond(), 10);224		assert_eq!(CollatorSelection::candidates(), Vec::new());225		assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);226227		// take two endowed, non-invulnerables accounts.228		assert_eq!(Balances::free_balance(&3), 100);229		assert_eq!(Balances::free_balance(&4), 100);230231		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));232		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));233234		assert_eq!(Balances::free_balance(&3), 90);235		assert_eq!(Balances::free_balance(&4), 90);236237		assert_eq!(CollatorSelection::candidates().len(), 2);238	});239}240241#[test]242fn leave_intent() {243	new_test_ext().execute_with(|| {244		// register a candidate.245		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));246		assert_eq!(Balances::free_balance(3), 90);247248		// register too so can leave above min candidates249		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));250		assert_eq!(Balances::free_balance(5), 90);251252		// cannot leave if not candidate.253		assert_noop!(254			CollatorSelection::leave_intent(RuntimeOrigin::signed(4)),255			Error::<Test>::NotCandidate256		);257258		// bond is returned259		assert_ok!(CollatorSelection::leave_intent(RuntimeOrigin::signed(3)));260		assert_eq!(Balances::free_balance(3), 100);261		assert_eq!(CollatorSelection::last_authored_block(3), 0);262	});263}264265#[test]266fn authorship_event_handler() {267	new_test_ext().execute_with(|| {268		// put 100 in the pot + 5 for ED269		Balances::make_free_balance_be(&CollatorSelection::account_id(), 105);270271		// 4 is the default author.272		assert_eq!(Balances::free_balance(4), 100);273		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));274		// triggers `note_author`275		Authorship::on_initialize(1);276277		let collator = CandidateInfo { who: 4, deposit: 10 };278279		assert_eq!(CollatorSelection::candidates(), vec![collator]);280		assert_eq!(CollatorSelection::last_authored_block(4), 0);281282		// half of the pot goes to the collator who's the author (4 in tests).283		assert_eq!(Balances::free_balance(4), 140);284		// half + ED stays.285		assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 55);286	});287}288289#[test]290fn fees_edgecases() {291	new_test_ext().execute_with(|| {292		// Nothing panics, no reward when no ED in balance293		Authorship::on_initialize(1);294		// put some money into the pot at ED295		Balances::make_free_balance_be(&CollatorSelection::account_id(), 5);296		// 4 is the default author.297		assert_eq!(Balances::free_balance(4), 100);298		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));299		// triggers `note_author`300		Authorship::on_initialize(1);301302		let collator = CandidateInfo { who: 4, deposit: 10 };303304		assert_eq!(CollatorSelection::candidates(), vec![collator]);305		assert_eq!(CollatorSelection::last_authored_block(4), 0);306		// Nothing received307		assert_eq!(Balances::free_balance(4), 90);308		// all fee stays309		assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 5);310	});311}312313#[test]314fn session_management_works() {315	new_test_ext().execute_with(|| {316		initialize_to_block(1);317318		assert_eq!(SessionChangeBlock::get(), 0);319		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);320321		initialize_to_block(4);322323		assert_eq!(SessionChangeBlock::get(), 0);324		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);325326		// add a new collator327		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));328329		// session won't see this.330		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);331		// but we have a new candidate.332		assert_eq!(CollatorSelection::candidates().len(), 1);333334		initialize_to_block(10);335		assert_eq!(SessionChangeBlock::get(), 10);336		// pallet-session has 1 session delay; current validators are the same.337		assert_eq!(Session::validators(), vec![1, 2]);338		// queued ones are changed, and now we have 3.339		assert_eq!(Session::queued_keys().len(), 3);340		// session handlers (aura, et. al.) cannot see this yet.341		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);342343		initialize_to_block(20);344		assert_eq!(SessionChangeBlock::get(), 20);345		// changed are now reflected to session handlers.346		assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3]);347	});348}349350#[test]351fn kick_mechanism() {352	new_test_ext().execute_with(|| {353		// add a new collator354		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));355		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(4)));356		initialize_to_block(10);357		assert_eq!(CollatorSelection::candidates().len(), 2);358		initialize_to_block(20);359		assert_eq!(SessionChangeBlock::get(), 20);360		// 4 authored this block, gets to stay 3 was kicked361		assert_eq!(CollatorSelection::candidates().len(), 1);362		// 3 will be kicked after 1 session delay363		assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3, 4]);364		let collator = CandidateInfo { who: 4, deposit: 10 };365		assert_eq!(CollatorSelection::candidates(), vec![collator]);366		assert_eq!(CollatorSelection::last_authored_block(4), 20);367		initialize_to_block(30);368		// 3 gets kicked after 1 session delay369		assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 4]);370		// kicked collator gets funds back371		assert_eq!(Balances::free_balance(3), 100);372	});373}374375#[test]376fn should_not_kick_mechanism_too_few() {377	new_test_ext().execute_with(|| {378		// add a new collator379		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(3)));380		assert_ok!(CollatorSelection::register_as_candidate(RuntimeOrigin::signed(5)));381		initialize_to_block(10);382		assert_eq!(CollatorSelection::candidates().len(), 2);383		initialize_to_block(20);384		assert_eq!(SessionChangeBlock::get(), 20);385		// 4 authored this block, 5 gets to stay too few 3 was kicked386		assert_eq!(CollatorSelection::candidates().len(), 1);387		// 3 will be kicked after 1 session delay388		assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3, 5]);389		let collator = CandidateInfo { who: 5, deposit: 10 };390		assert_eq!(CollatorSelection::candidates(), vec![collator]);391		assert_eq!(CollatorSelection::last_authored_block(4), 20);392		initialize_to_block(30);393		// 3 gets kicked after 1 session delay394		assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 5]);395		// kicked collator gets funds back396		assert_eq!(Balances::free_balance(3), 100);397	});398}399400#[test]401#[should_panic = "duplicate invulnerables in genesis."]402fn cannot_set_genesis_value_twice() {403	sp_tracing::try_init_simple();404	let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();405	let invulnerables = vec![1, 1];406407	let collator_selection = collator_selection::GenesisConfig::<Test> {408		desired_candidates: 2,409		candidacy_bond: 10,410		invulnerables,411	};412	// collator selection must be initialized before session.413	collator_selection.assimilate_storage(&mut t).unwrap();414}