git.delta.rocks / unique-network / refs/commits / d8a735e3ebdb

difftreelog

refactor! decouple pallet-collator-selection from pallet-configuration (#962)

Pavel Orlov2023-06-30parent: #1ecd8fc.patch.diff
in: master
* feat!: decoupling configuration&collators pallets

BREAKING CHANGE: pallet `collator-selection` no longer has a tight coupling with the `configuration` pallet

* refactor(collator-selection): type bounds, tests

* refactor(collator-selection): tests

* add ci step for banchmark tests

* add opsFee tests

---------

15 files changed

modified.github/workflows/yarn-dev.ymldiffbeforeafterboth
--- a/.github/workflows/yarn-dev.yml
+++ b/.github/workflows/yarn-dev.yml
@@ -87,6 +87,18 @@
         run: |
           echo "url is ${{ steps.test-report.outputs.runHtmlUrl }}"
 
+      - name: Run benchmark mintFee tests
+        working-directory: tests
+        run: |
+          yarn install
+          npx ts-node --esm ./src/benchmarks/mintFee/index.ts
+
+      - name: Run benchmark opsFee tests
+        working-directory: tests
+        run: |
+          yarn install
+          npx ts-node --esm ./src/benchmarks/opsFee/index.ts
+
       - name: Stop running containers
         if: always()                   # run this step always
         run: docker-compose -f ".docker/docker-compose.${{ matrix.network }}.yml" down
modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6371,7 +6371,7 @@
 
 [[package]]
 name = "pallet-collator-selection"
-version = "4.0.0"
+version = "5.0.0"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -6380,7 +6380,6 @@
  "pallet-aura",
  "pallet-authorship",
  "pallet-balances",
- "pallet-configuration",
  "pallet-session",
  "pallet-timestamp",
  "parity-scale-codec",
@@ -6435,7 +6434,7 @@
 
 [[package]]
 name = "pallet-configuration"
-version = "0.1.3"
+version = "0.2.0"
 dependencies = [
  "fp-evm",
  "frame-benchmarking",
modifiedpallets/collator-selection/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/collator-selection/CHANGELOG.md
+++ b/pallets/collator-selection/CHANGELOG.md
@@ -4,22 +4,28 @@
 
 <!-- bureaucracy goes here -->
 
+## [5.0.0] - 2023-06-27
+
+### Major change
+
+- The dependency (tight coupling) this pallet on the configuration pallet has been removed.
+
 ## [4.0.0] - 2022-12-29
 
 ### Added
 
 - Entire functionality moved over from cumulus/pallet-collator-selection (v3.0.0). Refactored business logic:
-   - Added an extra step for candidacy, `get_license`, at which payment happens. The number of license holders is unlimited. 
-      - Only licensed accounts can apply for candidacy with `onboard`. No extra deposits are made.
-      - Active candidates may `offboard`, but they will retain their license.
-      - Deposit is returned, and candidacy possibly removed with `release_license`.
-      - License can be forcibly forfeited and candidacy removed with `force_release_license`.
-   - Failing collators' deposits will now be fully slashed, and funds will be redirected to Treasury.
-   - Unify `MaxInvulnerables` and `MaxCandidates` into `MaxCollators`.
-   - Remove `MinCandidates`.
-   - Minimal amount of invulnerables is now 1.
-   - Both invulnerables and candidates count against the limits together, however invulnerables ignore `DesiredCollators`.
-   - `KickThreshold` is made configurable.
-   - `DesiredCollators`, `LicenseBond`, and `KickThreshold` are moved to and referenced from `pallet-configuration`.
-   - Naming changes to better reflect the new functionality.
-   - More minor changes, tests, benchmarks, etc.
\ No newline at end of file
+  - Added an extra step for candidacy, `get_license`, at which payment happens. The number of license holders is unlimited.
+    - Only licensed accounts can apply for candidacy with `onboard`. No extra deposits are made.
+    - Active candidates may `offboard`, but they will retain their license.
+    - Deposit is returned, and candidacy possibly removed with `release_license`.
+    - License can be forcibly forfeited and candidacy removed with `force_release_license`.
+  - Failing collators' deposits will now be fully slashed, and funds will be redirected to Treasury.
+  - Unify `MaxInvulnerables` and `MaxCandidates` into `MaxCollators`.
+  - Remove `MinCandidates`.
+  - Minimal amount of invulnerables is now 1.
+  - Both invulnerables and candidates count against the limits together, however invulnerables ignore `DesiredCollators`.
+  - `KickThreshold` is made configurable.
+  - `DesiredCollators`, `LicenseBond`, and `KickThreshold` are moved to and referenced from `pallet-configuration`.
+  - Naming changes to better reflect the new functionality.
+  - More minor changes, tests, benchmarks, etc.
modifiedpallets/collator-selection/Cargo.tomldiffbeforeafterboth
--- a/pallets/collator-selection/Cargo.toml
+++ b/pallets/collator-selection/Cargo.toml
@@ -6,7 +6,7 @@
 license = "GPLv3"
 name = "pallet-collator-selection"
 repository = "https://github.com/UniqueNetwork/unique-chain"
-version = "4.0.0"
+version = "5.0.0"
 
 [package.metadata.docs.rs]
 targets = ["x86_64-unknown-linux-gnu"]
@@ -23,7 +23,6 @@
 frame-support = { workspace = true }
 frame-system = { workspace = true }
 pallet-authorship = { workspace = true }
-pallet-configuration = { workspace = true }
 pallet-session = { workspace = true }
 sp-runtime = { workspace = true }
 sp-staking = { workspace = true }
@@ -55,8 +54,6 @@
 	"frame-system/std",
 	"log/std",
 	"pallet-authorship/std",
-	'pallet-aura/std',
-	'pallet-balances/std',
 	"pallet-session/std",
 	"rand/std",
 	"scale-info/std",
@@ -64,6 +61,8 @@
 	"sp-runtime/std",
 	"sp-staking/std",
 	"sp-std/std",
+	'pallet-aura/std',
+	'pallet-balances/std',
 ]
 
 try-runtime = ["frame-support/try-runtime"]
modifiedpallets/collator-selection/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/collator-selection/src/benchmarking.rs
+++ b/pallets/collator-selection/src/benchmarking.rs
@@ -35,7 +35,7 @@
 use super::*;
 
 #[allow(unused)]
-use crate::Pallet as CollatorSelection;
+use crate::{Pallet as CollatorSelection, BalanceOf};
 use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller};
 use frame_support::{
 	assert_ok,
@@ -49,11 +49,6 @@
 use frame_system::{EventRecord, RawOrigin};
 use pallet_authorship::EventHandler;
 use pallet_session::{self as session, SessionManager};
-use pallet_configuration::{
-	self as configuration, BalanceOf,
-	CollatorSelectionDesiredCollatorsOverride as DesiredCollators,
-	CollatorSelectionLicenseBondOverride as LicenseBond,
-};
 use sp_std::prelude::*;
 
 const SEED: u32 = 0;
@@ -117,7 +112,7 @@
 	validators.into_iter().map(|(who, _)| who).collect()
 }
 
-fn register_invulnerables<T: Config + configuration::Config>(count: u32) {
+fn register_invulnerables<T: Config>(count: u32) {
 	let candidates = (0..count)
 		.map(|c| account("candidate", c, SEED))
 		.collect::<Vec<_>>();
@@ -131,33 +126,27 @@
 	}
 }
 
-fn register_candidates<T: Config + configuration::Config>(count: u32) {
+fn register_candidates<T: Config>(count: u32) {
 	let candidates = (0..count)
 		.map(|c| account("candidate", c, SEED))
 		.collect::<Vec<_>>();
-	assert!(
-		<LicenseBond<T>>::get() > 0u32.into(),
-		"Bond cannot be zero!"
-	);
+	assert!(T::LicenseBond::get() > 0u32.into(), "Bond cannot be zero!");
 
 	for who in candidates {
-		T::Currency::set_balance(&who, <LicenseBond<T>>::get() * 2u32.into());
+		T::Currency::set_balance(&who, T::LicenseBond::get() * 2u32.into());
 		<CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();
 		<CollatorSelection<T>>::onboard(RawOrigin::Signed(who).into()).unwrap();
 	}
 }
 
-fn get_licenses<T: Config + configuration::Config>(count: u32) {
+fn get_licenses<T: Config>(count: u32) {
 	let candidates = (0..count)
 		.map(|c| account("candidate", c, SEED))
 		.collect::<Vec<_>>();
-	assert!(
-		<LicenseBond<T>>::get() > 0u32.into(),
-		"Bond cannot be zero!"
-	);
+	assert!(T::LicenseBond::get() > 0u32.into(), "Bond cannot be zero!");
 
 	for who in candidates {
-		T::Currency::set_balance(&who, <LicenseBond<T>>::get() * 2u32.into());
+		T::Currency::set_balance(&who, T::LicenseBond::get() * 2u32.into());
 		<CollatorSelection<T>>::get_license(RawOrigin::Signed(who.clone()).into()).unwrap();
 	}
 }
@@ -165,7 +154,7 @@
 /// `Currency::minimum_balance` was used originally, but in unique-chain, we have
 /// zero existential deposit, thus triggering zero bond assertion.
 fn balance_unit<T: Config>() -> BalanceOf<T> {
-	200u32.into()
+	T::LicenseBond::get()
 }
 
 /// Our benchmarking environment already has invulnerables registered.
@@ -173,7 +162,7 @@
 
 benchmarks! {
 	where_clause { where
-		T: pallet_authorship::Config + session::Config + configuration::Config
+		T: Config + pallet_authorship::Config + session::Config
 	}
 
 	// todo:collator this and all the following do not work for some reason, going all the way up to 10 in length
@@ -188,7 +177,7 @@
 
 		let new_invulnerable: T::AccountId = whitelisted_caller();
 		let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();
-		T::Currency::set_balance(&new_invulnerable, bond.clone());
+		<T as Config>::Currency::set_balance(&new_invulnerable, bond);
 
 		<session::Pallet<T>>::set_keys(
 			RawOrigin::Signed(new_invulnerable.clone()).into(),
@@ -225,15 +214,13 @@
 
 	get_license {
 		let c in 1 .. T::MaxCollators::get() - 1;
-
-		<LicenseBond<T>>::put(balance_unit::<T>());
 
 		register_validators::<T>(c);
 		get_licenses::<T>(c);
 
 		let caller: T::AccountId = whitelisted_caller();
 		let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();
-		T::Currency::set_balance(&caller, bond.clone());
+		T::Currency::set_balance(&caller, bond);
 
 		<session::Pallet<T>>::set_keys(
 			RawOrigin::Signed(caller.clone()).into(),
@@ -251,15 +238,12 @@
 	onboard {
 		let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES - 1;
 
-		<LicenseBond<T>>::put(balance_unit::<T>());
-		<DesiredCollators<T>>::put(c + INITIAL_INVULNERABLES + 1);
-
 		register_validators::<T>(c);
 		register_candidates::<T>(c);
 
 		let caller: T::AccountId = whitelisted_caller();
 		let bond: BalanceOf<T> = balance_unit::<T>() * 2u32.into();
-		T::Currency::set_balance(&caller, bond.clone());
+		T::Currency::set_balance(&caller, bond);
 
 		let origin = RawOrigin::Signed(caller.clone());
 
@@ -279,9 +263,7 @@
 
 	// worst case is the last candidate leaving.
 	offboard {
-		let c in 1 .. T::MaxCollators::get();
-		<LicenseBond<T>>::put(balance_unit::<T>());
-		<DesiredCollators<T>>::put(c + INITIAL_INVULNERABLES);
+		let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;
 
 		register_validators::<T>(c);
 		register_candidates::<T>(c);
@@ -295,10 +277,8 @@
 
 	// worst case is the last candidate leaving.
 	release_license {
-		let c in 1 .. T::MaxCollators::get();
+		let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;
 		let bond = balance_unit::<T>();
-		<LicenseBond<T>>::put(bond);
-		<DesiredCollators<T>>::put(c + INITIAL_INVULNERABLES);
 
 		register_validators::<T>(c);
 		register_candidates::<T>(c);
@@ -312,10 +292,8 @@
 
 	// worst case is the last candidate leaving.
 	force_release_license {
-		let c in 1 .. T::MaxCollators::get();
+		let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;
 		let bond = balance_unit::<T>();
-		<LicenseBond<T>>::put(bond);
-		<DesiredCollators<T>>::put(c + INITIAL_INVULNERABLES);
 
 		register_validators::<T>(c);
 		register_candidates::<T>(c);
@@ -334,7 +312,6 @@
 
 	// worst case is paying a non-existing candidate account.
 	note_author {
-		<LicenseBond<T>>::put(balance_unit::<T>());
 		T::Currency::set_balance(
 			&<CollatorSelection<T>>::account_id(),
 			balance_unit::<T>() * 4u32.into(),
@@ -353,11 +330,9 @@
 
 	// worst case for new session.
 	new_session {
-		let r in 1 .. T::MaxCollators::get();
-		let c in 1 .. T::MaxCollators::get();
+		let r in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;
+		let c in 1 .. T::MaxCollators::get() - INITIAL_INVULNERABLES;
 
-		<LicenseBond<T>>::put(balance_unit::<T>());
-		<DesiredCollators<T>>::put(c + INITIAL_INVULNERABLES);
 		frame_system::Pallet::<T>::set_block_number(0u32.into());
 
 		register_validators::<T>(c);
modifiedpallets/collator-selection/src/lib.rsdiffbeforeafterboth
--- a/pallets/collator-selection/src/lib.rs
+++ b/pallets/collator-selection/src/lib.rs
@@ -90,6 +90,10 @@
 mod benchmarking;
 pub mod weights;
 
+use frame_support::traits::fungible::Inspect;
+
+type BalanceOf<T> =
+	<<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
@@ -111,11 +115,6 @@
 	use frame_system::pallet_prelude::*;
 	use pallet_session::SessionManager;
 	use sp_runtime::{Perbill, traits::Convert};
-	use pallet_configuration::{
-		CollatorSelectionDesiredCollatorsOverride as DesiredCollators,
-		CollatorSelectionLicenseBondOverride as LicenseBond,
-		CollatorSelectionKickThresholdOverride as KickThreshold, BalanceOf,
-	};
 	use sp_staking::SessionIndex;
 
 	/// A convertor from collators id. Since this pallet does not have stash/controller, this is
@@ -129,9 +128,12 @@
 
 	/// Configure the pallet by specifying the parameters and types on which it depends.
 	#[pallet::config]
-	pub trait Config: frame_system::Config + pallet_configuration::Config {
+	pub trait Config: frame_system::Config {
 		/// Overarching event type.
 		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
+		type Currency: Mutate<Self::AccountId>
+			+ MutateHold<Self::AccountId>
+			+ BalancedHold<Self::AccountId>;
 
 		/// Origin that can dictate updating parameters of this pallet.
 		type UpdateOrigin: EnsureOrigin<Self::RuntimeOrigin>;
@@ -163,7 +165,13 @@
 		type WeightInfo: WeightInfo;
 
 		#[pallet::constant]
-		type LicenceBondIdentifier: Get<<<Self as pallet_configuration::Config>::Currency as InspectHold<Self::AccountId>>::Reason>;
+		type LicenceBondIdentifier: Get<<Self::Currency as InspectHold<Self::AccountId>>::Reason>;
+
+		type DesiredCollators: Get<u32>;
+
+		type LicenseBond: Get<BalanceOf<Self>>;
+
+		type KickThreshold: Get<Self::BlockNumber>;
 	}
 
 	#[pallet::pallet]
@@ -365,7 +373,7 @@
 				Error::<T>::ValidatorNotRegistered
 			);
 
-			let deposit = <LicenseBond<T>>::get();
+			let deposit = T::LicenseBond::get();
 
 			T::Currency::hold(&T::LicenceBondIdentifier::get(), &who, deposit)?;
 			LicenseDepositOf::<T>::insert(who.clone(), deposit);
@@ -396,7 +404,7 @@
 			let length = <Candidates<T>>::decode_len().unwrap_or_default()
 				+ <Invulnerables<T>>::decode_len().unwrap_or_default();
 			ensure!(
-				(length as u32) < <DesiredCollators<T>>::get(),
+				(length as u32) < T::DesiredCollators::get(),
 				Error::<T>::TooManyCandidates
 			);
 			ensure!(
@@ -415,7 +423,7 @@
 						// First authored block is current block plus kick threshold to handle session delay
 						<LastAuthoredBlock<T>>::insert(
 							who.clone(),
-							frame_system::Pallet::<T>::block_number() + <KickThreshold<T>>::get(),
+							frame_system::Pallet::<T>::block_number() + T::KickThreshold::get(),
 						);
 						Ok(candidates.len())
 					}
@@ -574,7 +582,7 @@
 			candidates: BoundedVec<T::AccountId, T::MaxCollators>,
 		) -> BoundedVec<T::AccountId, T::MaxCollators> {
 			let now = frame_system::Pallet::<T>::block_number();
-			let kick_threshold = <KickThreshold<T>>::get();
+			let kick_threshold = T::KickThreshold::get();
 			candidates
 				.into_iter()
 				.filter_map(|c| {
modifiedpallets/collator-selection/src/mock.rsdiffbeforeafterboth
--- a/pallets/collator-selection/src/mock.rs
+++ b/pallets/collator-selection/src/mock.rs
@@ -63,7 +63,6 @@
 		Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
 		CollatorSelection: collator_selection::{Pallet, Call, Storage, Event<T>},
 		Authorship: pallet_authorship::{Pallet, Storage},
-		Configuration: pallet_configuration::{Pallet, Call, Storage, Event<T>},
 	}
 );
 
@@ -216,21 +215,6 @@
 	pub AppPromotionDailyRate: Perbill = Perbill::from_rational(5u32, 10_000);
 	pub const DayRelayBlocks: u32 = 1;
 	pub const LicenceBondIdentifier: [u8; 16] = *b"licenceidentifie";
-}
-
-impl pallet_configuration::Config for Test {
-	type RuntimeEvent = RuntimeEvent;
-	type Currency = Balances;
-	type DefaultCollatorSelectionMaxCollators = MaxCollators;
-	type DefaultCollatorSelectionKickThreshold = KickThreshold;
-	type DefaultCollatorSelectionLicenseBond = LicenseBond;
-	// the following constants we don't care about
-	type DefaultWeightToFeeCoefficient = DefaultWeightToFeeCoefficient;
-	type DefaultMinGasPrice = DefaultMinGasPrice;
-	type MaxXcmAllowedLocations = MaxXcmAllowedLocations;
-	type AppPromotionDailyRate = AppPromotionDailyRate;
-	type DayRelayBlocks = DayRelayBlocks;
-	type WeightInfo = pallet_configuration::weights::SubstrateWeight<Self>;
 }
 
 ord_parameter_types! {
@@ -246,11 +230,7 @@
 pub struct IsRegistered;
 impl ValidatorRegistration<u64> for IsRegistered {
 	fn is_registered(id: &u64) -> bool {
-		if *id == 7u64 {
-			false
-		} else {
-			true
-		}
+		*id != 7u64
 	}
 }
 
@@ -265,6 +245,10 @@
 	type ValidatorIdOf = IdentityCollator;
 	type ValidatorRegistration = IsRegistered;
 	type LicenceBondIdentifier = LicenceBondIdentifier;
+	type Currency = Balances;
+	type DesiredCollators = MaxCollators;
+	type LicenseBond = LicenseBond;
+	type KickThreshold = KickThreshold;
 	type WeightInfo = ();
 }
 
@@ -277,7 +261,11 @@
 
 	let ed = <Test as pallet_balances::Config>::ExistentialDeposit::get();
 
-	let balances = vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100), (33, ed)];
+	let balances: Vec<(u64, u64)> = (1..=<Test as Config>::DesiredCollators::get() as u64 + 1)
+		.map(|i| (i, 100))
+		.chain(core::iter::once((33, ed)))
+		.collect();
+
 	let keys = balances
 		.iter()
 		.map(|&(i, _)| {
modifiedpallets/collator-selection/src/tests.rsdiffbeforeafterboth
before · pallets/collator-selection/src/tests.rs
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::*, Error};35use frame_support::{36	assert_noop, assert_ok,37	traits::{fungible, GenesisBuild, OnInitialize},38};39use frame_system::RawOrigin;40use sp_runtime::{traits::BadOrigin, TokenError};41use pallet_configuration::{42	CollatorSelectionDesiredCollatorsOverride as DesiredCollators,43	CollatorSelectionKickThresholdOverride as KickThreshold,44	CollatorSelectionLicenseBondOverride as LicenseBond,45};46use scale_info::prelude::*;4748fn get_license_and_onboard(account_id: <Test as frame_system::Config>::AccountId) {49	assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(50		account_id51	)));52	assert_ok!(CollatorSelection::onboard(RuntimeOrigin::signed(53		account_id54	)));55}5657#[test]58fn basic_setup_works() {59	new_test_ext().execute_with(|| {60		assert_eq!(<DesiredCollators<Test>>::get(), 5);61		assert_eq!(<LicenseBond<Test>>::get(), 10);6263		assert!(CollatorSelection::candidates().is_empty());64		assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);65	});66}6768#[test]69fn it_should_add_invulnerables() {70	new_test_ext().execute_with(|| {71		assert_ok!(CollatorSelection::add_invulnerable(72			RuntimeOrigin::signed(RootAccount::get()),73			174		));75		assert_ok!(CollatorSelection::add_invulnerable(76			RuntimeOrigin::signed(RootAccount::get()),77			278		));79		assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);8081		// cannot set with non-root.82		assert_noop!(83			CollatorSelection::add_invulnerable(RuntimeOrigin::signed(1), 3),84			BadOrigin85		);8687		// cannot set invulnerables without associated validator keys88		assert_noop!(89			CollatorSelection::add_invulnerable(RuntimeOrigin::signed(RootAccount::get()), 7),90			Error::<Test>::ValidatorNotRegistered91		);92	});93}9495#[test]96fn it_should_remove_invulnerables() {97	new_test_ext().execute_with(|| {98		assert_ok!(CollatorSelection::add_invulnerable(99			RuntimeOrigin::signed(RootAccount::get()),100			1101		));102		assert_ok!(CollatorSelection::add_invulnerable(103			RuntimeOrigin::signed(RootAccount::get()),104			2105		));106107		// cannot remove with non-root.108		assert_noop!(109			CollatorSelection::remove_invulnerable(RuntimeOrigin::signed(1), 3),110			BadOrigin111		);112113		assert_ok!(CollatorSelection::remove_invulnerable(114			RuntimeOrigin::signed(RootAccount::get()),115			2116		));117		assert_eq!(CollatorSelection::invulnerables(), vec![1]);118119		// cannot remove an invulnerable if there would be 0 invulnerables.120		assert_noop!(121			CollatorSelection::remove_invulnerable(RuntimeOrigin::signed(RootAccount::get()), 1),122			Error::<Test>::TooFewInvulnerables123		);124	});125}126127#[test]128fn set_desired_collators_works() {129	new_test_ext().execute_with(|| {130		// given131		assert_eq!(<DesiredCollators<Test>>::get(), 5);132133		// can set134		assert_ok!(Configuration::set_collator_selection_desired_collators(135			RawOrigin::Root.into(),136			Some(7)137		));138		assert_eq!(<DesiredCollators<Test>>::get(), 7);139140		// rejects bad origin141		assert_noop!(142			Configuration::set_collator_selection_desired_collators(143				RuntimeOrigin::signed(1),144				Some(8)145			),146			BadOrigin147		);148	});149}150151#[test]152fn set_license_bond() {153	new_test_ext().execute_with(|| {154		// given155		assert_eq!(<LicenseBond<Test>>::get(), 10);156157		// can set158		assert_ok!(Configuration::set_collator_selection_license_bond(159			RawOrigin::Root.into(),160			Some(7)161		));162		assert_eq!(<LicenseBond<Test>>::get(), 7);163164		// rejects bad origin.165		assert_noop!(166			Configuration::set_collator_selection_license_bond(RuntimeOrigin::signed(1), Some(8)),167			BadOrigin168		);169	});170}171172#[test]173fn cannot_onboard_candidate_with_no_license() {174	new_test_ext().execute_with(|| {175		// can't onboard a candidate who did not get a license.176		assert_noop!(177			CollatorSelection::onboard(RuntimeOrigin::signed(3)),178			Error::<Test>::NoLicense,179		);180181		// but give it a license and welcome aboard.182		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));183		assert_ok!(CollatorSelection::onboard(RuntimeOrigin::signed(3)));184	})185}186187#[test]188fn cannot_onboard_candidate_if_too_many() {189	new_test_ext().execute_with(|| {190		// reset desired candidates191		<pallet_configuration::CollatorSelectionDesiredCollatorsOverride<Test>>::put(0);192193		// can still get a license.194		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(4)));195196		// can't accept anyone anymore.197		assert_noop!(198			CollatorSelection::onboard(RuntimeOrigin::signed(4)),199			Error::<Test>::TooManyCandidates,200		);201202		// reset desired candidates to invulnerables + 1203		<pallet_configuration::CollatorSelectionDesiredCollatorsOverride<Test>>::put(3);204		assert_ok!(CollatorSelection::onboard(RuntimeOrigin::signed(4)));205206		// but no more.207		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(5)));208		assert_noop!(209			CollatorSelection::onboard(RuntimeOrigin::signed(5)),210			Error::<Test>::TooManyCandidates,211		);212	})213}214215#[test]216fn cannot_obtain_license_if_keys_not_registered() {217	new_test_ext().execute_with(|| {218		// can't 7 because keys not registered.219		assert_noop!(220			CollatorSelection::get_license(RuntimeOrigin::signed(7)),221			Error::<Test>::ValidatorNotRegistered222		);223	})224}225226#[test]227fn cannot_obtain_license_if_poor() {228	new_test_ext().execute_with(|| {229		let ed = <Test as pallet_balances::Config>::ExistentialDeposit::get();230		assert_eq!(Balances::free_balance(&3), 100);231		assert_eq!(Balances::free_balance(&33), ed);232233		// works234		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));235236		// poor237		assert_noop!(238			CollatorSelection::get_license(RuntimeOrigin::signed(33)),239			TokenError::FundsUnavailable,240		);241	});242}243244#[test]245fn cannot_onboard_dupe_candidate() {246	new_test_ext().execute_with(|| {247		// can add 3 as candidate248		get_license_and_onboard(3);249		assert_eq!(CollatorSelection::license_deposit_of(3), 10);250		assert_eq!(CollatorSelection::candidates(), vec![3]);251		assert_eq!(CollatorSelection::last_authored_block(3), 10);252		assert_eq!(Balances::free_balance(3), 90);253254		// but no more255		assert_noop!(256			CollatorSelection::get_license(RuntimeOrigin::signed(3)),257			Error::<Test>::AlreadyHoldingLicense,258		);259		assert_noop!(260			CollatorSelection::onboard(RuntimeOrigin::signed(3)),261			Error::<Test>::AlreadyCandidate,262		);263	})264}265266#[test]267fn becoming_candidate_works() {268	new_test_ext().execute_with(|| {269		// given270		assert_eq!(<DesiredCollators<Test>>::get(), 5);271		assert_eq!(<LicenseBond<Test>>::get(), 10);272		assert_eq!(CollatorSelection::candidates(), Vec::new());273		assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);274275		// take two endowed, non-invulnerables accounts.276		assert_eq!(Balances::free_balance(&3), 100);277		assert_eq!(Balances::free_balance(&4), 100);278279		get_license_and_onboard(3);280		get_license_and_onboard(4);281282		assert_eq!(Balances::free_balance(&3), 90);283		assert_eq!(Balances::free_balance(&4), 90);284285		assert_eq!(CollatorSelection::candidates().len(), 2);286	});287}288289#[test]290fn cannot_become_candidate_if_invulnerable() {291	new_test_ext().execute_with(|| {292		assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);293294		// can obtain a license even if is invulnerable.295		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(1)));296		// but cannot onboard297		assert_noop!(298			CollatorSelection::onboard(RuntimeOrigin::signed(1)),299			Error::<Test>::AlreadyInvulnerable,300		);301302		// get a license and then become invulnerable.303		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));304		assert_ok!(CollatorSelection::add_invulnerable(305			RuntimeOrigin::signed(RootAccount::get()),306			3307		));308		assert_noop!(309			CollatorSelection::onboard(RuntimeOrigin::signed(3)),310			Error::<Test>::AlreadyInvulnerable,311		);312	})313}314315#[test]316fn can_become_invulnerable_if_candidate() {317	new_test_ext().execute_with(|| {318		// become a candidate and then become invulnerable.319		get_license_and_onboard(3);320		assert_eq!(CollatorSelection::candidates(), vec![3]);321322		assert_ok!(CollatorSelection::add_invulnerable(323			RuntimeOrigin::signed(RootAccount::get()),324			3325		));326		// should exclude from candidates, but not revoke the license327		assert_eq!(CollatorSelection::candidates(), vec![]);328		assert_eq!(CollatorSelection::license_deposit_of(3), 10);329		assert_eq!(Balances::free_balance(3), 90);330	});331}332333#[test]334fn offboard() {335	new_test_ext().execute_with(|| {336		// register a candidate.337		get_license_and_onboard(3);338		assert_eq!(Balances::free_balance(3), 90);339340		// cannot leave if holds license but not yet candidate.341		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(4)));342		assert_noop!(343			CollatorSelection::offboard(RuntimeOrigin::signed(4)),344			Error::<Test>::NotCandidate345		);346		// cannot leave if does not hold license.347		assert_noop!(348			CollatorSelection::offboard(RuntimeOrigin::signed(5)),349			Error::<Test>::NotCandidate350		);351352		// bond is returned - only after releasing the license353		assert_ok!(CollatorSelection::offboard(RuntimeOrigin::signed(3)));354		assert_eq!(Balances::free_balance(3), 90);355		assert_eq!(CollatorSelection::last_authored_block(3), 0);356		assert_ok!(CollatorSelection::release_license(RuntimeOrigin::signed(3)));357		assert_eq!(Balances::free_balance(3), 100);358	});359}360361#[test]362fn release_license() {363	new_test_ext().execute_with(|| {364		// obtain a license to collate and reserve the bond.365		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));366		assert_eq!(Balances::free_balance(3), 90);367368		// release the license and get the bond back.369		assert_ok!(CollatorSelection::release_license(RuntimeOrigin::signed(3)));370		assert_eq!(Balances::free_balance(3), 100);371372		// register a candidate.373		get_license_and_onboard(3);374		assert_eq!(Balances::free_balance(3), 90);375376		// can release license even if onboarded.377		assert_ok!(CollatorSelection::release_license(RuntimeOrigin::signed(3)));378		assert_eq!(Balances::free_balance(3), 100);379		assert_eq!(CollatorSelection::candidates(), vec![]);380	});381}382383#[test]384fn force_release_license() {385	new_test_ext().execute_with(|| {386		// obtain a license to collate and reserve the bond.387		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));388		assert_eq!(Balances::free_balance(3), 90);389390		// cannot execute the operation as non-root391		assert_noop!(392			CollatorSelection::force_release_license(RuntimeOrigin::signed(3), 3),393			BadOrigin394		);395396		// release the license and get the bond back.397		assert_ok!(CollatorSelection::force_release_license(398			RuntimeOrigin::signed(RootAccount::get()),399			3400		));401		assert_eq!(Balances::free_balance(3), 100);402403		// register a candidate.404		get_license_and_onboard(3);405		assert_eq!(Balances::free_balance(3), 90);406407		// can release license even if onboarded.408		assert_ok!(CollatorSelection::force_release_license(409			RuntimeOrigin::signed(RootAccount::get()),410			3411		));412		assert_eq!(Balances::free_balance(3), 100);413		assert_eq!(CollatorSelection::candidates(), vec![]);414	});415}416417#[test]418fn authorship_event_handler() {419	new_test_ext().execute_with(|| {420		// put 100 in the pot + 5 for ED421		<Balances as fungible::Mutate<_>>::set_balance(&CollatorSelection::account_id(), 105);422423		// 4 is the default author.424		assert_eq!(Balances::free_balance(4), 100);425		get_license_and_onboard(4);426		// triggers `note_author`427		Authorship::on_initialize(1);428429		assert_eq!(CollatorSelection::candidates(), vec![4]);430		assert_eq!(CollatorSelection::last_authored_block(4), 0);431432		// half of the pot goes to the collator who's the author (4 in tests).433		assert_eq!(Balances::free_balance(4), 140);434		// half + ED stays.435		assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 55);436	});437}438439#[test]440fn fees_edgecases() {441	new_test_ext().execute_with(|| {442		// Nothing panics, no reward when no ED in balance443		Authorship::on_initialize(1);444		// put some money into the pot at ED445		<Balances as fungible::Mutate<_>>::set_balance(&CollatorSelection::account_id(), 5);446		// 4 is the default author.447		assert_eq!(Balances::free_balance(4), 100);448		get_license_and_onboard(4);449		// triggers `note_author`450		Authorship::on_initialize(1);451452		assert_eq!(CollatorSelection::candidates(), vec![4]);453		assert_eq!(CollatorSelection::last_authored_block(4), 0);454		// Nothing received455		assert_eq!(Balances::free_balance(4), 90);456		// all fee stays457		assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 5);458	});459}460461#[test]462fn session_management_works() {463	new_test_ext().execute_with(|| {464		initialize_to_block(1);465466		assert_eq!(SessionChangeBlock::get(), 0);467		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);468469		initialize_to_block(4);470471		assert_eq!(SessionChangeBlock::get(), 0);472		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);473474		// add a new collator475		get_license_and_onboard(5);476477		// session won't see this.478		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);479		// but we have a new candidate.480		assert_eq!(CollatorSelection::candidates().len(), 1);481482		initialize_to_block(10);483		assert_eq!(SessionChangeBlock::get(), 10);484		// pallet-session has 1 session delay; current validators are the same.485		assert_eq!(Session::validators(), vec![1, 2]);486		// queued ones are changed, and now we have 3.487		assert_eq!(Session::queued_keys().len(), 3);488		// session handlers (aura, et. al.) cannot see this yet.489		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);490491		initialize_to_block(20);492		assert_eq!(SessionChangeBlock::get(), 20);493		// changed are now reflected to session handlers.494		assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 5]);495	});496}497498#[test]499fn kick_mechanism() {500	new_test_ext().execute_with(|| {501		// add a new collator502		get_license_and_onboard(3);503		get_license_and_onboard(4);504505		initialize_to_block(10);506		assert_eq!(CollatorSelection::candidates().len(), 2);507508		initialize_to_block(20);509		assert_eq!(SessionChangeBlock::get(), 20);510		// 4 authored this block, gets to stay 3 was kicked511		assert_eq!(CollatorSelection::candidates().len(), 1);512		// 3 will be kicked after 1 session delay513		assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3, 4]);514515		assert_eq!(CollatorSelection::candidates(), vec![4]);516		assert_eq!(<KickThreshold<Test>>::get(), 10);517		assert_eq!(CollatorSelection::last_authored_block(4), 20);518519		initialize_to_block(30);520		// 3 gets kicked after 1 session delay521		assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 4]);522		// kicked collator gets their funds slashed, the deposit going to treasury523		assert_eq!(Balances::free_balance(3), 90);524	});525}526527#[test]528#[should_panic = "duplicate invulnerables in genesis."]529fn cannot_set_genesis_value_twice() {530	sp_tracing::try_init_simple();531	let mut t = frame_system::GenesisConfig::default()532		.build_storage::<Test>()533		.unwrap();534	let invulnerables = vec![1, 1];535536	let collator_selection = collator_selection::GenesisConfig::<Test> { invulnerables };537	// collator selection must be initialized before session.538	collator_selection.assimilate_storage(&mut t).unwrap();539}
after · pallets/collator-selection/src/tests.rs
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::{self as collator_selection, Config};34use crate::{mock::*, Error};35use frame_support::{36	assert_noop, assert_ok,37	traits::{fungible, GenesisBuild, OnInitialize},38};39use sp_runtime::{traits::BadOrigin, TokenError};40use scale_info::prelude::*;4142fn get_license_and_onboard(account_id: <Test as frame_system::Config>::AccountId) {43	assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(44		account_id45	)));46	assert_ok!(CollatorSelection::onboard(RuntimeOrigin::signed(47		account_id48	)));49}5051#[test]52fn basic_setup_works() {53	new_test_ext().execute_with(|| {54		assert!(CollatorSelection::candidates().is_empty());55		assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);56	});57}5859#[test]60fn it_should_add_invulnerables() {61	new_test_ext().execute_with(|| {62		assert_ok!(CollatorSelection::add_invulnerable(63			RuntimeOrigin::signed(RootAccount::get()),64			165		));66		assert_ok!(CollatorSelection::add_invulnerable(67			RuntimeOrigin::signed(RootAccount::get()),68			269		));70		assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);7172		// cannot set with non-root.73		assert_noop!(74			CollatorSelection::add_invulnerable(RuntimeOrigin::signed(1), 3),75			BadOrigin76		);7778		// cannot set invulnerables without associated validator keys79		assert_noop!(80			CollatorSelection::add_invulnerable(RuntimeOrigin::signed(RootAccount::get()), 7),81			Error::<Test>::ValidatorNotRegistered82		);83	});84}8586#[test]87fn it_should_remove_invulnerables() {88	new_test_ext().execute_with(|| {89		assert_ok!(CollatorSelection::add_invulnerable(90			RuntimeOrigin::signed(RootAccount::get()),91			192		));93		assert_ok!(CollatorSelection::add_invulnerable(94			RuntimeOrigin::signed(RootAccount::get()),95			296		));9798		// cannot remove with non-root.99		assert_noop!(100			CollatorSelection::remove_invulnerable(RuntimeOrigin::signed(1), 3),101			BadOrigin102		);103104		assert_ok!(CollatorSelection::remove_invulnerable(105			RuntimeOrigin::signed(RootAccount::get()),106			2107		));108		assert_eq!(CollatorSelection::invulnerables(), vec![1]);109110		// cannot remove an invulnerable if there would be 0 invulnerables.111		assert_noop!(112			CollatorSelection::remove_invulnerable(RuntimeOrigin::signed(RootAccount::get()), 1),113			Error::<Test>::TooFewInvulnerables114		);115	});116}117118#[test]119fn cannot_onboard_candidate_with_no_license() {120	new_test_ext().execute_with(|| {121		// can't onboard a candidate who did not get a license.122		assert_noop!(123			CollatorSelection::onboard(RuntimeOrigin::signed(3)),124			Error::<Test>::NoLicense,125		);126127		// but give it a license and welcome aboard.128		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));129		assert_ok!(CollatorSelection::onboard(RuntimeOrigin::signed(3)));130	})131}132133#[test]134fn cannot_onboard_candidate_if_too_many() {135	new_test_ext().execute_with(|| {136		// can accept desired value of collators.137		for c in 3u64..=(<Test as Config>::DesiredCollators::get()).into() {138			assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(c)));139			assert_ok!(CollatorSelection::onboard(RuntimeOrigin::signed(c)));140		}141142		// but no more.143		let undesired_collator = (<Test as Config>::DesiredCollators::get() + 1) as u64;144		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(145			undesired_collator146		)));147		assert_noop!(148			CollatorSelection::onboard(RuntimeOrigin::signed(undesired_collator)),149			Error::<Test>::TooManyCandidates,150		);151	})152}153154#[test]155fn cannot_obtain_license_if_keys_not_registered() {156	new_test_ext().execute_with(|| {157		// can't 7 because keys not registered.158		assert_noop!(159			CollatorSelection::get_license(RuntimeOrigin::signed(7)),160			Error::<Test>::ValidatorNotRegistered161		);162	})163}164165#[test]166fn cannot_obtain_license_if_poor() {167	new_test_ext().execute_with(|| {168		let ed = <Test as pallet_balances::Config>::ExistentialDeposit::get();169		assert_eq!(Balances::free_balance(3), 100);170		assert_eq!(Balances::free_balance(33), ed);171172		// works173		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));174175		// poor176		assert_noop!(177			CollatorSelection::get_license(RuntimeOrigin::signed(33)),178			TokenError::FundsUnavailable,179		);180	});181}182183#[test]184fn cannot_onboard_dupe_candidate() {185	new_test_ext().execute_with(|| {186		// can add 3 as candidate187		get_license_and_onboard(3);188		assert_eq!(CollatorSelection::license_deposit_of(3), 10);189		assert_eq!(CollatorSelection::candidates(), vec![3]);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::get_license(RuntimeOrigin::signed(3)),196			Error::<Test>::AlreadyHoldingLicense,197		);198		assert_noop!(199			CollatorSelection::onboard(RuntimeOrigin::signed(3)),200			Error::<Test>::AlreadyCandidate,201		);202	})203}204205#[test]206fn becoming_candidate_works() {207	new_test_ext().execute_with(|| {208		assert_eq!(CollatorSelection::candidates(), Vec::new());209		assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);210211		// take two endowed, non-invulnerables accounts.212		assert_eq!(Balances::free_balance(3), 100);213		assert_eq!(Balances::free_balance(4), 100);214215		get_license_and_onboard(3);216		get_license_and_onboard(4);217218		assert_eq!(Balances::free_balance(3), 90);219		assert_eq!(Balances::free_balance(4), 90);220221		assert_eq!(CollatorSelection::candidates().len(), 2);222	});223}224225#[test]226fn cannot_become_candidate_if_invulnerable() {227	new_test_ext().execute_with(|| {228		assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);229230		// can obtain a license even if is invulnerable.231		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(1)));232		// but cannot onboard233		assert_noop!(234			CollatorSelection::onboard(RuntimeOrigin::signed(1)),235			Error::<Test>::AlreadyInvulnerable,236		);237238		// get a license and then become invulnerable.239		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));240		assert_ok!(CollatorSelection::add_invulnerable(241			RuntimeOrigin::signed(RootAccount::get()),242			3243		));244		assert_noop!(245			CollatorSelection::onboard(RuntimeOrigin::signed(3)),246			Error::<Test>::AlreadyInvulnerable,247		);248	})249}250251#[test]252fn can_become_invulnerable_if_candidate() {253	new_test_ext().execute_with(|| {254		// become a candidate and then become invulnerable.255		get_license_and_onboard(3);256		assert_eq!(CollatorSelection::candidates(), vec![3]);257258		assert_ok!(CollatorSelection::add_invulnerable(259			RuntimeOrigin::signed(RootAccount::get()),260			3261		));262		// should exclude from candidates, but not revoke the license263		assert_eq!(CollatorSelection::candidates(), vec![]);264		assert_eq!(CollatorSelection::license_deposit_of(3), 10);265		assert_eq!(Balances::free_balance(3), 90);266	});267}268269#[test]270fn offboard() {271	new_test_ext().execute_with(|| {272		// register a candidate.273		get_license_and_onboard(3);274		assert_eq!(Balances::free_balance(3), 90);275276		// cannot leave if holds license but not yet candidate.277		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(4)));278		assert_noop!(279			CollatorSelection::offboard(RuntimeOrigin::signed(4)),280			Error::<Test>::NotCandidate281		);282		// cannot leave if does not hold license.283		assert_noop!(284			CollatorSelection::offboard(RuntimeOrigin::signed(5)),285			Error::<Test>::NotCandidate286		);287288		// bond is returned - only after releasing the license289		assert_ok!(CollatorSelection::offboard(RuntimeOrigin::signed(3)));290		assert_eq!(Balances::free_balance(3), 90);291		assert_eq!(CollatorSelection::last_authored_block(3), 0);292		assert_ok!(CollatorSelection::release_license(RuntimeOrigin::signed(3)));293		assert_eq!(Balances::free_balance(3), 100);294	});295}296297#[test]298fn release_license() {299	new_test_ext().execute_with(|| {300		// obtain a license to collate and reserve the bond.301		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));302		assert_eq!(Balances::free_balance(3), 90);303304		// release the license and get the bond back.305		assert_ok!(CollatorSelection::release_license(RuntimeOrigin::signed(3)));306		assert_eq!(Balances::free_balance(3), 100);307308		// register a candidate.309		get_license_and_onboard(3);310		assert_eq!(Balances::free_balance(3), 90);311312		// can release license even if onboarded.313		assert_ok!(CollatorSelection::release_license(RuntimeOrigin::signed(3)));314		assert_eq!(Balances::free_balance(3), 100);315		assert_eq!(CollatorSelection::candidates(), vec![]);316	});317}318319#[test]320fn force_release_license() {321	new_test_ext().execute_with(|| {322		// obtain a license to collate and reserve the bond.323		assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));324		assert_eq!(Balances::free_balance(3), 90);325326		// cannot execute the operation as non-root327		assert_noop!(328			CollatorSelection::force_release_license(RuntimeOrigin::signed(3), 3),329			BadOrigin330		);331332		// release the license and get the bond back.333		assert_ok!(CollatorSelection::force_release_license(334			RuntimeOrigin::signed(RootAccount::get()),335			3336		));337		assert_eq!(Balances::free_balance(3), 100);338339		// register a candidate.340		get_license_and_onboard(3);341		assert_eq!(Balances::free_balance(3), 90);342343		// can release license even if onboarded.344		assert_ok!(CollatorSelection::force_release_license(345			RuntimeOrigin::signed(RootAccount::get()),346			3347		));348		assert_eq!(Balances::free_balance(3), 100);349		assert_eq!(CollatorSelection::candidates(), vec![]);350	});351}352353#[test]354fn authorship_event_handler() {355	new_test_ext().execute_with(|| {356		// put 100 in the pot + 5 for ED357		<Balances as fungible::Mutate<_>>::set_balance(&CollatorSelection::account_id(), 105);358359		// 4 is the default author.360		assert_eq!(Balances::free_balance(4), 100);361		get_license_and_onboard(4);362		// triggers `note_author`363		Authorship::on_initialize(1);364365		assert_eq!(CollatorSelection::candidates(), vec![4]);366		assert_eq!(CollatorSelection::last_authored_block(4), 0);367368		// half of the pot goes to the collator who's the author (4 in tests).369		assert_eq!(Balances::free_balance(4), 140);370		// half + ED stays.371		assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 55);372	});373}374375#[test]376fn fees_edgecases() {377	new_test_ext().execute_with(|| {378		// Nothing panics, no reward when no ED in balance379		Authorship::on_initialize(1);380		// put some money into the pot at ED381		<Balances as fungible::Mutate<_>>::set_balance(&CollatorSelection::account_id(), 5);382		// 4 is the default author.383		assert_eq!(Balances::free_balance(4), 100);384		get_license_and_onboard(4);385		// triggers `note_author`386		Authorship::on_initialize(1);387388		assert_eq!(CollatorSelection::candidates(), vec![4]);389		assert_eq!(CollatorSelection::last_authored_block(4), 0);390		// Nothing received391		assert_eq!(Balances::free_balance(4), 90);392		// all fee stays393		assert_eq!(Balances::free_balance(CollatorSelection::account_id()), 5);394	});395}396397#[test]398fn session_management_works() {399	new_test_ext().execute_with(|| {400		initialize_to_block(1);401402		assert_eq!(SessionChangeBlock::get(), 0);403		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);404405		initialize_to_block(4);406407		assert_eq!(SessionChangeBlock::get(), 0);408		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);409410		// add a new collator411		get_license_and_onboard(5);412413		// session won't see this.414		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);415		// but we have a new candidate.416		assert_eq!(CollatorSelection::candidates().len(), 1);417418		initialize_to_block(10);419		assert_eq!(SessionChangeBlock::get(), 10);420		// pallet-session has 1 session delay; current validators are the same.421		assert_eq!(Session::validators(), vec![1, 2]);422		// queued ones are changed, and now we have 3.423		assert_eq!(Session::queued_keys().len(), 3);424		// session handlers (aura, et. al.) cannot see this yet.425		assert_eq!(SessionHandlerCollators::get(), vec![1, 2]);426427		initialize_to_block(20);428		assert_eq!(SessionChangeBlock::get(), 20);429		// changed are now reflected to session handlers.430		assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 5]);431	});432}433434#[test]435fn kick_mechanism() {436	new_test_ext().execute_with(|| {437		// add a new collator438		get_license_and_onboard(3);439		get_license_and_onboard(4);440441		initialize_to_block(10);442		assert_eq!(CollatorSelection::candidates().len(), 2);443444		initialize_to_block(20);445		assert_eq!(SessionChangeBlock::get(), 20);446		// 4 authored this block, gets to stay 3 was kicked447		assert_eq!(CollatorSelection::candidates().len(), 1);448		// 3 will be kicked after 1 session delay449		assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3, 4]);450451		assert_eq!(CollatorSelection::candidates(), vec![4]);452		// assert_eq!(<KickThreshold<Test>>::get(), 10);453		assert_eq!(CollatorSelection::last_authored_block(4), 20);454455		initialize_to_block(30);456		// 3 gets kicked after 1 session delay457		assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 4]);458		// kicked collator gets their funds slashed, the deposit going to treasury459		assert_eq!(Balances::free_balance(3), 90);460	});461}462463#[test]464#[should_panic = "duplicate invulnerables in genesis."]465fn cannot_set_genesis_value_twice() {466	sp_tracing::try_init_simple();467	let mut t = frame_system::GenesisConfig::default()468		.build_storage::<Test>()469		.unwrap();470	let invulnerables = vec![1, 1];471472	let collator_selection = collator_selection::GenesisConfig::<Test> { invulnerables };473	// collator selection must be initialized before session.474	collator_selection.assimilate_storage(&mut t).unwrap();475}
modifiedpallets/configuration/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/configuration/CHANGELOG.md
+++ b/pallets/configuration/CHANGELOG.md
@@ -3,7 +3,12 @@
 All notable changes to this project will be documented in this file.
 
 <!-- bureaucrate goes here -->
+## [0.2.0] - 2023-06-27
+
+### Major change
 
+- Architecture fixed: in the configuration of this pallet, bounds on the associated type were determined not by the functional requirements for this pallet itself, but by the pallet that had tight coupling with it.
+
 ## [0.1.3] - 2022-12-29
 
 ### Added
@@ -20,4 +25,4 @@
 
 ### Other changes
 
-- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
\ No newline at end of file
+- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a
modifiedpallets/configuration/Cargo.tomldiffbeforeafterboth
--- a/pallets/configuration/Cargo.toml
+++ b/pallets/configuration/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 edition = "2021"
 name = "pallet-configuration"
-version = "0.1.3"
+version = "0.2.0"
 
 [dependencies]
 # Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it.
@@ -22,11 +22,11 @@
 default = ["std"]
 runtime-benchmarks = ["frame-benchmarking"]
 std = [
+	"codec/std",
 	"fp-evm/std",
 	"frame-benchmarking/std",
 	"frame-support/std",
 	"frame-system/std",
-	"codec/std",
 	"sp-arithmetic/std",
 	"sp-core/std",
 	"sp-std/std",
modifiedpallets/configuration/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/configuration/src/benchmarking.rs
+++ b/pallets/configuration/src/benchmarking.rs
@@ -19,7 +19,7 @@
 use super::*;
 use frame_benchmarking::benchmarks;
 use frame_system::{EventRecord, RawOrigin};
-use frame_support::{assert_ok, traits::fungible::Inspect};
+use frame_support::assert_ok;
 
 fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
 	let events = frame_system::Pallet::<T>::events();
@@ -30,7 +30,10 @@
 }
 
 benchmarks! {
-	where_clause { where T: Config }
+	where_clause { where
+		T: Config,
+		T::Balance: From<u32>
+	}
 
 	set_weight_to_fee_coefficient_override {
 		let coeff: u64 = 999;
@@ -60,7 +63,7 @@
 		let max: u32 = 999;
 	}: {
 		assert_ok!(
-			<Pallet<T>>::set_collator_selection_desired_collators(RawOrigin::Root.into(), Some(max.clone()))
+			<Pallet<T>>::set_collator_selection_desired_collators(RawOrigin::Root.into(), Some(max))
 		);
 	}
 	verify {
@@ -68,10 +71,10 @@
 	}
 
 	set_collator_selection_license_bond {
-		let bond_cost: Option<BalanceOf<T>> = Some(T::Currency::minimum_balance() * 10u32.into());
+		let bond_cost: Option<T::Balance> = Some(1000u32.into());
 	}: {
 		assert_ok!(
-			<Pallet<T>>::set_collator_selection_license_bond(RawOrigin::Root.into(), bond_cost.clone())
+			<Pallet<T>>::set_collator_selection_license_bond(RawOrigin::Root.into(), bond_cost)
 		);
 	}
 	verify {
@@ -82,7 +85,7 @@
 		let threshold: Option<T::BlockNumber> = Some(900u32.into());
 	}: {
 		assert_ok!(
-			<Pallet<T>>::set_collator_selection_kick_threshold(RawOrigin::Root.into(), threshold.clone())
+			<Pallet<T>>::set_collator_selection_kick_threshold(RawOrigin::Root.into(), threshold)
 		);
 	}
 	verify {
modifiedpallets/configuration/src/lib.rsdiffbeforeafterboth
--- a/pallets/configuration/src/lib.rs
+++ b/pallets/configuration/src/lib.rs
@@ -22,6 +22,7 @@
 	pallet,
 	weights::{WeightToFeePolynomial, WeightToFeeCoefficients, WeightToFeeCoefficient, Weight},
 	traits::Get,
+	Parameter,
 };
 use codec::{Decode, Encode, MaxEncodedLen};
 use scale_info::TypeInfo;
@@ -42,27 +43,33 @@
 mod pallet {
 	use super::*;
 	use frame_support::{
-		traits::{fungible, Get},
-		pallet_prelude::{StorageValue, ValueQuery, DispatchResult, IsType},
+		traits::{Get},
+		pallet_prelude::{
+			StorageValue, ValueQuery, DispatchResult, IsType, Member, MaybeSerializeDeserialize,
+		},
 		log,
+		dispatch::{Codec, fmt::Debug},
 	};
-	use frame_system::{pallet_prelude::OriginFor, ensure_root, Config as SystemConfig};
-
+	use frame_system::{pallet_prelude::OriginFor, ensure_root};
+	use sp_arithmetic::{FixedPointOperand, traits::AtLeast32BitUnsigned};
 	pub use crate::weights::WeightInfo;
-	pub type BalanceOf<T> =
-		<<T as Config>::Currency as fungible::Inspect<<T as SystemConfig>::AccountId>>::Balance;
 
 	#[pallet::config]
 	pub trait Config: frame_system::Config {
 		/// Overarching event type.
 		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
 
-		type Currency: fungible::Inspect<Self::AccountId>
-			+ fungible::Mutate<Self::AccountId>
-			+ fungible::MutateFreeze<Self::AccountId>
-			+ fungible::InspectHold<Self::AccountId>
-			+ fungible::MutateHold<Self::AccountId>
-			+ fungible::BalancedHold<Self::AccountId>;
+		type Balance: Parameter
+			+ Member
+			+ AtLeast32BitUnsigned
+			+ Codec
+			+ Default
+			+ Copy
+			+ MaybeSerializeDeserialize
+			+ Debug
+			+ MaxEncodedLen
+			+ TypeInfo
+			+ FixedPointOperand;
 
 		#[pallet::constant]
 		type DefaultWeightToFeeCoefficient: Get<u64>;
@@ -79,7 +86,7 @@
 		#[pallet::constant]
 		type DefaultCollatorSelectionMaxCollators: Get<u32>;
 		#[pallet::constant]
-		type DefaultCollatorSelectionLicenseBond: Get<BalanceOf<Self>>;
+		type DefaultCollatorSelectionLicenseBond: Get<Self::Balance>;
 		#[pallet::constant]
 		type DefaultCollatorSelectionKickThreshold: Get<Self::BlockNumber>;
 
@@ -94,7 +101,7 @@
 			desired_collators: Option<u32>,
 		},
 		NewCollatorLicenseBond {
-			bond_cost: Option<BalanceOf<T>>,
+			bond_cost: Option<T::Balance>,
 		},
 		NewCollatorKickThreshold {
 			length_in_blocks: Option<T::BlockNumber>,
@@ -130,7 +137,7 @@
 
 	#[pallet::storage]
 	pub type CollatorSelectionLicenseBondOverride<T: Config> = StorageValue<
-		Value = BalanceOf<T>,
+		Value = T::Balance,
 		QueryKind = ValueQuery,
 		OnEmpty = T::DefaultCollatorSelectionLicenseBond,
 	>;
@@ -221,7 +228,7 @@
 		#[pallet::weight(T::WeightInfo::set_collator_selection_license_bond())]
 		pub fn set_collator_selection_license_bond(
 			origin: OriginFor<T>,
-			amount: Option<BalanceOf<T>>,
+			amount: Option<<T as Config>::Balance>,
 		) -> DispatchResult {
 			ensure_root(origin)?;
 			if let Some(amount) = amount {
modifiedruntime/common/config/pallets/collator_selection.rsdiffbeforeafterboth
--- a/runtime/common/config/pallets/collator_selection.rs
+++ b/runtime/common/config/pallets/collator_selection.rs
@@ -23,7 +23,10 @@
 };
 use sp_runtime::Perbill;
 use up_common::constants::{UNIQUE, MILLIUNIQUE};
-
+use pallet_configuration::{
+	CollatorSelectionKickThresholdOverride, CollatorSelectionLicenseBondOverride,
+	CollatorSelectionDesiredCollatorsOverride,
+};
 parameter_types! {
 	pub const SessionOffset: BlockNumber = 0;
 }
@@ -60,6 +63,9 @@
 	pub const MaxAdditionalFields: u32 = 100;
 	pub const MaxRegistrars: u32 = 20;
 	pub const LicenceBondIdentifier: [u8; 16] = *b"licenceidentifie";
+	pub LicenseBond: Balance =  CollatorSelectionLicenseBondOverride::<Runtime>::get();
+	pub DesiredCollators: u32 = CollatorSelectionDesiredCollatorsOverride::<Runtime>::get();
+	pub KickThreshold: BlockNumber = CollatorSelectionKickThresholdOverride::<Runtime>::get();
 }
 
 impl pallet_identity::Config for Runtime {
@@ -84,6 +90,7 @@
 
 impl pallet_collator_selection::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
+	type Currency = Balances;
 	// We allow root only to execute privileged collator selection operations.
 	type UpdateOrigin = EnsureRoot<AccountId>;
 	type TreasuryAccountId = TreasuryAccountId;
@@ -95,4 +102,7 @@
 	type ValidatorRegistration = Session;
 	type WeightInfo = pallet_collator_selection::weights::SubstrateWeight<Runtime>;
 	type LicenceBondIdentifier = LicenceBondIdentifier;
+	type DesiredCollators = DesiredCollators;
+	type LicenseBond = LicenseBond;
+	type KickThreshold = KickThreshold;
 }
modifiedruntime/common/config/pallets/mod.rsdiffbeforeafterboth
--- a/runtime/common/config/pallets/mod.rs
+++ b/runtime/common/config/pallets/mod.rs
@@ -129,7 +129,7 @@
 
 impl pallet_configuration::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
-	type Currency = Balances;
+	type Balance = Balance;
 	type DefaultWeightToFeeCoefficient = ConstU64<{ up_common::constants::WEIGHT_TO_FEE_COEFF }>;
 	type DefaultMinGasPrice = ConstU64<{ up_common::constants::MIN_GAS_PRICE }>;
 	type DefaultCollatorSelectionMaxCollators = MaxCollators;
modifiedtests/src/benchmarks/mintFee/index.tsdiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/index.ts
+++ b/tests/src/benchmarks/mintFee/index.ts
@@ -360,7 +360,7 @@
           susbstrateReceiver.addressRaw,
           PROPERTIES.slice(0, setup.propertiesNumber),
         )
-        .send({from: ethSigner, gas: 25_000_000});
+        .send({from: ethSigner});
     },
   );