difftreelog
refactor! decouple pallet-collator-selection from pallet-configuration (#962)
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
.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
Cargo.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",
pallets/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.
pallets/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"]
pallets/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);
pallets/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| {
pallets/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, _)| {
pallets/collator-selection/src/tests.rsdiffbeforeafterboth--- a/pallets/collator-selection/src/tests.rs
+++ b/pallets/collator-selection/src/tests.rs
@@ -30,19 +30,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use crate as collator_selection;
+use crate::{self as collator_selection, Config};
use crate::{mock::*, Error};
use frame_support::{
assert_noop, assert_ok,
traits::{fungible, GenesisBuild, OnInitialize},
};
-use frame_system::RawOrigin;
use sp_runtime::{traits::BadOrigin, TokenError};
-use pallet_configuration::{
- CollatorSelectionDesiredCollatorsOverride as DesiredCollators,
- CollatorSelectionKickThresholdOverride as KickThreshold,
- CollatorSelectionLicenseBondOverride as LicenseBond,
-};
use scale_info::prelude::*;
fn get_license_and_onboard(account_id: <Test as frame_system::Config>::AccountId) {
@@ -57,9 +51,6 @@
#[test]
fn basic_setup_works() {
new_test_ext().execute_with(|| {
- assert_eq!(<DesiredCollators<Test>>::get(), 5);
- assert_eq!(<LicenseBond<Test>>::get(), 10);
-
assert!(CollatorSelection::candidates().is_empty());
assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);
});
@@ -120,51 +111,6 @@
assert_noop!(
CollatorSelection::remove_invulnerable(RuntimeOrigin::signed(RootAccount::get()), 1),
Error::<Test>::TooFewInvulnerables
- );
- });
-}
-
-#[test]
-fn set_desired_collators_works() {
- new_test_ext().execute_with(|| {
- // given
- assert_eq!(<DesiredCollators<Test>>::get(), 5);
-
- // can set
- assert_ok!(Configuration::set_collator_selection_desired_collators(
- RawOrigin::Root.into(),
- Some(7)
- ));
- assert_eq!(<DesiredCollators<Test>>::get(), 7);
-
- // rejects bad origin
- assert_noop!(
- Configuration::set_collator_selection_desired_collators(
- RuntimeOrigin::signed(1),
- Some(8)
- ),
- BadOrigin
- );
- });
-}
-
-#[test]
-fn set_license_bond() {
- new_test_ext().execute_with(|| {
- // given
- assert_eq!(<LicenseBond<Test>>::get(), 10);
-
- // can set
- assert_ok!(Configuration::set_collator_selection_license_bond(
- RawOrigin::Root.into(),
- Some(7)
- ));
- assert_eq!(<LicenseBond<Test>>::get(), 7);
-
- // rejects bad origin.
- assert_noop!(
- Configuration::set_collator_selection_license_bond(RuntimeOrigin::signed(1), Some(8)),
- BadOrigin
);
});
}
@@ -187,26 +133,19 @@
#[test]
fn cannot_onboard_candidate_if_too_many() {
new_test_ext().execute_with(|| {
- // reset desired candidates
- <pallet_configuration::CollatorSelectionDesiredCollatorsOverride<Test>>::put(0);
-
- // can still get a license.
- assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(4)));
-
- // can't accept anyone anymore.
- assert_noop!(
- CollatorSelection::onboard(RuntimeOrigin::signed(4)),
- Error::<Test>::TooManyCandidates,
- );
-
- // reset desired candidates to invulnerables + 1
- <pallet_configuration::CollatorSelectionDesiredCollatorsOverride<Test>>::put(3);
- assert_ok!(CollatorSelection::onboard(RuntimeOrigin::signed(4)));
+ // can accept desired value of collators.
+ for c in 3u64..=(<Test as Config>::DesiredCollators::get()).into() {
+ assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(c)));
+ assert_ok!(CollatorSelection::onboard(RuntimeOrigin::signed(c)));
+ }
// but no more.
- assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(5)));
+ let undesired_collator = (<Test as Config>::DesiredCollators::get() + 1) as u64;
+ assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(
+ undesired_collator
+ )));
assert_noop!(
- CollatorSelection::onboard(RuntimeOrigin::signed(5)),
+ CollatorSelection::onboard(RuntimeOrigin::signed(undesired_collator)),
Error::<Test>::TooManyCandidates,
);
})
@@ -227,8 +166,8 @@
fn cannot_obtain_license_if_poor() {
new_test_ext().execute_with(|| {
let ed = <Test as pallet_balances::Config>::ExistentialDeposit::get();
- assert_eq!(Balances::free_balance(&3), 100);
- assert_eq!(Balances::free_balance(&33), ed);
+ assert_eq!(Balances::free_balance(3), 100);
+ assert_eq!(Balances::free_balance(33), ed);
// works
assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));
@@ -266,21 +205,18 @@
#[test]
fn becoming_candidate_works() {
new_test_ext().execute_with(|| {
- // given
- assert_eq!(<DesiredCollators<Test>>::get(), 5);
- assert_eq!(<LicenseBond<Test>>::get(), 10);
assert_eq!(CollatorSelection::candidates(), Vec::new());
assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);
// take two endowed, non-invulnerables accounts.
- assert_eq!(Balances::free_balance(&3), 100);
- assert_eq!(Balances::free_balance(&4), 100);
+ assert_eq!(Balances::free_balance(3), 100);
+ assert_eq!(Balances::free_balance(4), 100);
get_license_and_onboard(3);
get_license_and_onboard(4);
- assert_eq!(Balances::free_balance(&3), 90);
- assert_eq!(Balances::free_balance(&4), 90);
+ assert_eq!(Balances::free_balance(3), 90);
+ assert_eq!(Balances::free_balance(4), 90);
assert_eq!(CollatorSelection::candidates().len(), 2);
});
@@ -513,7 +449,7 @@
assert_eq!(SessionHandlerCollators::get(), vec![1, 2, 3, 4]);
assert_eq!(CollatorSelection::candidates(), vec![4]);
- assert_eq!(<KickThreshold<Test>>::get(), 10);
+ // assert_eq!(<KickThreshold<Test>>::get(), 10);
assert_eq!(CollatorSelection::last_authored_block(4), 20);
initialize_to_block(30);
pallets/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
pallets/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",
pallets/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 {
pallets/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 {
runtime/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;
}
runtime/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;
tests/src/benchmarks/mintFee/index.tsdiffbeforeafterboth1import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';2import {readFile} from 'fs/promises';3import {4 ICrossAccountId,5} from '../../util/playgrounds/types';6import {IKeyringPair} from '@polkadot/types/types';7import {UniqueNFTCollection} from '../../util/playgrounds/unique';8import {Contract} from 'web3-eth-contract';9import {createObjectCsvWriter} from 'csv-writer';10import {convertToTokens, createCollectionForBenchmarks, PERMISSIONS, PROPERTIES} from '../utils/common';11import {makeNames} from '../../util';12import {ContractImports} from '../../eth/util/playgrounds/types';1314const {dirname} = makeNames(import.meta.url);1516export const CONTRACT_IMPORT: ContractImports[] = [17 {18 fsPath: `${dirname}/../../eth/api/CollectionHelpers.sol`,19 solPath: 'eth/api/CollectionHelpers.sol',20 },21 {22 fsPath: `${dirname}/../../eth/api/ContractHelpers.sol`,23 solPath: 'eth/api/ContractHelpers.sol',24 },25 {26 fsPath: `${dirname}/../../eth/api/UniqueRefungibleToken.sol`,27 solPath: 'eth/api/UniqueRefungibleToken.sol',28 },29 {30 fsPath: `${dirname}/../../eth/api/UniqueRefungible.sol`,31 solPath: 'eth/api/UniqueRefungible.sol',32 },33 {34 fsPath: `${dirname}/../../eth/api/UniqueNFT.sol`,35 solPath: 'eth/api/UniqueNFT.sol',36 },37];3839interface IBenchmarkResultForProp {40 propertiesNumber: number;41 substrateFee: number;42 ethFee: number;43 ethBulkFee: number;44 ethMintCrossFee: number;45 evmProxyContractFee: number;46 evmProxyContractBulkFee: number;47}4849const main = async () => {50 const benchmarks = [51 'substrateFee',52 'ethFee',53 'ethBulkFee',54 'ethMintCrossFee',55 'evmProxyContractFee',56 'evmProxyContractBulkFee',57 ];58 const headers = [59 'propertiesNumber',60 ...benchmarks,61 ];626364 const csvWriter = createObjectCsvWriter({65 path: 'properties.csv',66 header: headers,67 });6869 await usingEthPlaygrounds(async (helper, privateKey) => {70 const CONTRACT_SOURCE = (71 await readFile(`${dirname}/proxyContract.sol`)72 ).toString();7374 const donor = await privateKey('//Alice'); // Seed from account with balance on this network75 const ethSigner = await helper.eth.createAccountWithBalance(donor);7677 const contract = await helper.ethContract.deployByCode(78 ethSigner,79 'ProxyMint',80 CONTRACT_SOURCE,81 CONTRACT_IMPORT,82 );8384 const fees = await benchMintFee(helper, privateKey, contract);85 console.log('Minting without properties');86 console.table(fees);8788 const result: IBenchmarkResultForProp[] = [];89 const csvResult: IBenchmarkResultForProp[] = [];9091 for(let i = 1; i <= 20; i++) {92 const benchResult = await benchMintWithProperties(helper, privateKey, contract, {93 propertiesNumber: i,94 }) as any;9596 csvResult.push(benchResult);9798 const minFee = Math.min(...(benchmarks.map(x => benchResult[x])));99 for(const key of benchmarks) {100 const keyPercent = Math.round((benchResult[key] / minFee) * 100);101 benchResult[key] = `${benchResult[key]} (${keyPercent}%)`;102 }103104 result.push(benchResult);105 }106107 await csvWriter.writeRecords(csvResult);108109 console.log('Minting with properties');110 console.table(result, headers);111 });112};113114main()115 .then(() => process.exit(0))116 .catch((e) => {117 console.log(e);118 process.exit(1);119 });120121122123async function benchMintFee(124 helper: EthUniqueHelper,125 privateKey: (seed: string) => Promise<IKeyringPair>,126 proxyContract: Contract,127): Promise<{128 substrateFee: number;129 ethFee: number;130 evmProxyContractFee: number;131}> {132 const donor = await privateKey('//Alice');133 const substrateReceiver = await privateKey('//Bob');134 const ethSigner = await helper.eth.createAccountWithBalance(donor);135136 const nominal = helper.balance.getOneTokenNominal();137138 await helper.eth.transferBalanceFromSubstrate(139 donor,140 proxyContract.options.address,141 100n,142 );143144 const collection = (await createCollectionForBenchmarks(145 'nft',146 helper,147 privateKey,148 ethSigner,149 proxyContract.options.address,150 PERMISSIONS,151 )) as UniqueNFTCollection;152153 const substrateFee = await helper.arrange.calculcateFee(154 {Substrate: donor.address},155 () => collection.mintToken(donor, {Substrate: substrateReceiver.address}),156 );157158 const collectionEthAddress = helper.ethAddress.fromCollectionId(collection.collectionId);159 const collectionContract = await helper.ethNativeContract.collection(160 collectionEthAddress,161 'nft',162 );163164 const receiverEthAddress = helper.address.substrateToEth(substrateReceiver.address);165166 const encodedCall = collectionContract.methods167 .mint(receiverEthAddress)168 .encodeABI();169170 const ethFee = await helper.arrange.calculcateFee(171 {Substrate: donor.address},172 async () => {173 await helper.eth.sendEVM(174 donor,175 collectionContract.options.address,176 encodedCall,177 '0',178 );179 },180 );181182 const evmProxyContractFee = await helper.arrange.calculcateFee(183 {Ethereum: ethSigner},184 async () => {185 await proxyContract.methods186 .mintToSubstrate(187 helper.ethAddress.fromCollectionId(collection.collectionId),188 substrateReceiver.addressRaw,189 )190 .send({from: ethSigner});191 },192 );193194 return {195 substrateFee: convertToTokens(substrateFee, nominal),196 ethFee: convertToTokens(ethFee, nominal),197 evmProxyContractFee: convertToTokens(evmProxyContractFee, nominal),198 };199}200201async function benchMintWithProperties(202 helper: EthUniqueHelper,203 privateKey: (seed: string) => Promise<IKeyringPair>,204 proxyContract: Contract,205 setup: { propertiesNumber: number },206): Promise<IBenchmarkResultForProp> {207 const donor = await privateKey('//Alice'); // Seed from account with balance on this network208 const ethSigner = await helper.eth.createAccountWithBalance(donor);209210 const susbstrateReceiver = await privateKey('//Bob');211 const receiverEthAddress = helper.address.substrateToEth(susbstrateReceiver.address);212213 const nominal = helper.balance.getOneTokenNominal();214215 const substrateFee = await calculateFeeNftMintWithProperties(216 helper,217 privateKey,218 {Substrate: donor.address},219 ethSigner,220 proxyContract.options.address,221 async (collection) => {222 await collection.mintToken(223 donor,224 {Substrate: susbstrateReceiver.address},225 PROPERTIES.slice(0, setup.propertiesNumber).map((p) => ({key: p.key, value: Buffer.from(p.value).toString()})),226 );227 },228 );229230 const ethFee = await calculateFeeNftMintWithProperties(231 helper,232 privateKey,233 {Substrate: donor.address},234 ethSigner,235 proxyContract.options.address,236 async (collection) => {237 const evmContract = await helper.ethNativeContract.collection(238 helper.ethAddress.fromCollectionId(collection.collectionId),239 'nft',240 undefined,241 true,242 );243244 const subTokenId = await evmContract.methods.nextTokenId().call();245246 let encodedCall = evmContract.methods247 .mint(receiverEthAddress)248 .encodeABI();249250 await helper.eth.sendEVM(251 donor,252 evmContract.options.address,253 encodedCall,254 '0',255 );256257 for(const val of PROPERTIES.slice(0, setup.propertiesNumber)) {258 encodedCall = await evmContract.methods259 .setProperty(subTokenId, val.key, Buffer.from(val.value))260 .encodeABI();261262 await helper.eth.sendEVM(263 donor,264 evmContract.options.address,265 encodedCall,266 '0',267 );268 }269 },270 );271272 const ethBulkFee = await calculateFeeNftMintWithProperties(273 helper,274 privateKey,275 {Substrate: donor.address},276 ethSigner,277 proxyContract.options.address,278 async (collection) => {279 const evmContract = await helper.ethNativeContract.collection(280 helper.ethAddress.fromCollectionId(collection.collectionId),281 'nft',282 );283284 const subTokenId = await evmContract.methods.nextTokenId().call();285286 let encodedCall = evmContract.methods287 .mint(receiverEthAddress)288 .encodeABI();289290 await helper.eth.sendEVM(291 donor,292 evmContract.options.address,293 encodedCall,294 '0',295 );296297 encodedCall = await evmContract.methods298 .setProperties(299 subTokenId,300 PROPERTIES.slice(0, setup.propertiesNumber),301 )302 .encodeABI();303304 await helper.eth.sendEVM(305 donor,306 evmContract.options.address,307 encodedCall,308 '0',309 );310 },311 );312313 const ethMintCrossFee = await calculateFeeNftMintWithProperties(314 helper,315 privateKey,316 {Ethereum: ethSigner},317 ethSigner,318 proxyContract.options.address,319 async (collection) => {320 const evmContract = await helper.ethNativeContract.collection(321 helper.ethAddress.fromCollectionId(collection.collectionId),322 'nft',323 );324325 await evmContract.methods.mintCross(326 helper.ethCrossAccount.fromAddress(receiverEthAddress),327 PROPERTIES.slice(0, setup.propertiesNumber),328 )329 .send({from: ethSigner});330 },331 );332333 const proxyContractFee = await calculateFeeNftMintWithProperties(334 helper,335 privateKey,336 {Ethereum: ethSigner},337 ethSigner,338 proxyContract.options.address,339 async (collection) => {340 await proxyContract.methods341 .mintToSubstrateWithProperty(342 helper.ethAddress.fromCollectionId(collection.collectionId),343 susbstrateReceiver.addressRaw,344 PROPERTIES.slice(0, setup.propertiesNumber),345 )346 .send({from: ethSigner});347 },348 );349350 const proxyContractBulkFee = await calculateFeeNftMintWithProperties(351 helper,352 privateKey,353 {Ethereum: ethSigner},354 ethSigner,355 proxyContract.options.address,356 async (collection) => {357 await proxyContract.methods358 .mintToSubstrateBulkProperty(359 helper.ethAddress.fromCollectionId(collection.collectionId),360 susbstrateReceiver.addressRaw,361 PROPERTIES.slice(0, setup.propertiesNumber),362 )363 .send({from: ethSigner});364 },365 );366367 return {368 propertiesNumber: setup.propertiesNumber,369 substrateFee: convertToTokens(substrateFee, nominal),370 ethFee: convertToTokens(ethFee, nominal),371 ethBulkFee: convertToTokens(ethBulkFee, nominal),372 ethMintCrossFee: convertToTokens(ethMintCrossFee, nominal),373 evmProxyContractFee: convertToTokens(proxyContractFee, nominal),374 evmProxyContractBulkFee: convertToTokens(proxyContractBulkFee, nominal),375 };376}377378async function calculateFeeNftMintWithProperties(379 helper: EthUniqueHelper,380 privateKey: (seed: string) => Promise<IKeyringPair>,381 payer: ICrossAccountId,382 ethSigner: string,383 proxyContractAddress: string,384 calculatedCall: (collection: UniqueNFTCollection) => Promise<any>,385): Promise<bigint> {386 const collection = (await createCollectionForBenchmarks(387 'nft',388 helper,389 privateKey,390 ethSigner,391 proxyContractAddress,392 PERMISSIONS,393 )) as UniqueNFTCollection;394 return helper.arrange.calculcateFee(payer, async () => {395 await calculatedCall(collection);396 });397}398399400