difftreelog
refactor(collator-selection) rename revoke to release + update tx + cargo fmt
in: master
13 files changed
pallets/collator-selection/src/lib.rsdiffbeforeafterboth--- a/pallets/collator-selection/src/lib.rs
+++ b/pallets/collator-selection/src/lib.rs
@@ -217,7 +217,7 @@
let bounded_invulnerables =
BoundedVec::<_, T::MaxCollators>::try_from(self.invulnerables.clone())
.expect("genesis invulnerables are more than T::MaxCollators");
-
+
<Invulnerables<T>>::put(bounded_invulnerables);
}
}
@@ -284,6 +284,7 @@
#[pallet::call]
impl<T: Config> Pallet<T> {
/// Add a collator to the list of invulnerable (fixed) collators.
+ #[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::set_invulnerables(1u32))] // todo:collator weight
pub fn add_invulnerable(
origin: OriginFor<T>,
@@ -313,6 +314,7 @@
}
/// Remove a collator from the list of invulnerable (fixed) collators.
+ #[pallet::call_index(1)]
#[pallet::weight(T::WeightInfo::set_invulnerables(1))] // todo:collator weight
pub fn remove_invulnerable(
origin: OriginFor<T>,
@@ -341,6 +343,7 @@
/// (a) already have registered session keys and (b) be able to reserve the `LicenseBond`.
///
/// This call is not available to `Invulnerable` collators.
+ #[pallet::call_index(2)]
#[pallet::weight(T::WeightInfo::register_as_candidate(T::MaxCollators::get()))] // todo:collator weight
pub fn get_license(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
// register_as_candidate
@@ -373,6 +376,7 @@
/// The account must already hold a license, and cannot offboard immediately during a session.
///
/// This call is not available to `Invulnerable` collators.
+ #[pallet::call_index(3)]
#[pallet::weight(T::WeightInfo::register_as_candidate(T::MaxCollators::get()))] // todo:collator weight
pub fn onboard(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
// register_as_candidate
@@ -418,6 +422,7 @@
/// Deregister `origin` as a collator candidate. Note that the collator can only leave on
/// session change. The license to `onboard` later at any other time will remain.
+ #[pallet::call_index(4)]
#[pallet::weight(T::WeightInfo::leave_intent(T::MaxCollators::get()))] // todo:collator weight
pub fn offboard(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
// leave_intent
@@ -430,6 +435,7 @@
/// Forfeit `origin`'s own license. The `LicenseBond` will be unreserved immediately.
///
/// This call is not available to `Invulnerable` collators.
+ #[pallet::call_index(5)]
#[pallet::weight(T::WeightInfo::leave_intent(T::MaxCollators::get()))] // todo:collator weight
pub fn release_license(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
// leave_intent
@@ -445,8 +451,9 @@
/// The `LicenseBond` will be unreserved and returned immediately.
///
/// This call is, of course, not applicable to `Invulnerable` collators.
+ #[pallet::call_index(6)]
#[pallet::weight(T::WeightInfo::leave_intent(T::MaxCollators::get()))] // todo:collator weight
- pub fn force_revoke_license(
+ pub fn force_release_license(
origin: OriginFor<T>,
who: T::AccountId,
) -> DispatchResultWithPostInfo {
pallets/collator-selection/src/mock.rsdiffbeforeafterboth--- a/pallets/collator-selection/src/mock.rs
+++ b/pallets/collator-selection/src/mock.rs
@@ -281,9 +281,7 @@
)
})
.collect::<Vec<_>>();
- let collator_selection = collator_selection::GenesisConfig::<Test> {
- invulnerables,
- };
+ let collator_selection = collator_selection::GenesisConfig::<Test> { invulnerables };
let session = pallet_session::GenesisConfig::<Test> { keys };
pallet_balances::GenesisConfig::<Test> { balances }
.assimilate_storage(&mut t)
pallets/collator-selection/src/tests.rsdiffbeforeafterboth--- a/pallets/collator-selection/src/tests.rs
+++ b/pallets/collator-selection/src/tests.rs
@@ -380,7 +380,7 @@
}
#[test]
-fn force_revoke_license() {
+fn force_release_license() {
new_test_ext().execute_with(|| {
// obtain a license to collate and reserve the bond.
assert_ok!(CollatorSelection::get_license(RuntimeOrigin::signed(3)));
@@ -388,12 +388,12 @@
// cannot execute the operation as non-root
assert_noop!(
- CollatorSelection::force_revoke_license(RuntimeOrigin::signed(3), 3),
+ CollatorSelection::force_release_license(RuntimeOrigin::signed(3), 3),
BadOrigin
);
// release the license and get the bond back.
- assert_ok!(CollatorSelection::force_revoke_license(
+ assert_ok!(CollatorSelection::force_release_license(
RuntimeOrigin::signed(RootAccount::get()),
3
));
@@ -404,7 +404,7 @@
assert_eq!(Balances::free_balance(3), 90);
// can release license even if onboarded.
- assert_ok!(CollatorSelection::force_revoke_license(
+ assert_ok!(CollatorSelection::force_release_license(
RuntimeOrigin::signed(RootAccount::get()),
3
));
@@ -532,9 +532,7 @@
.unwrap();
let invulnerables = vec![1, 1];
- let collator_selection = collator_selection::GenesisConfig::<Test> {
- invulnerables,
- };
+ let collator_selection = collator_selection::GenesisConfig::<Test> { invulnerables };
// collator selection must be initialized before session.
collator_selection.assimilate_storage(&mut t).unwrap();
}
pallets/configuration/src/lib.rsdiffbeforeafterboth--- a/pallets/configuration/src/lib.rs
+++ b/pallets/configuration/src/lib.rs
@@ -201,6 +201,7 @@
Ok(())
}
+ #[pallet::call_index(4)]
#[pallet::weight(T::DbWeight::get().writes(1))]
pub fn set_collator_selection_desired_collators(
origin: OriginFor<T>,
@@ -216,10 +217,13 @@
} else {
<CollatorSelectionDesiredCollatorsOverride<T>>::kill();
}
- Self::deposit_event(Event::NewDesiredCollators { desired_collators: max });
+ Self::deposit_event(Event::NewDesiredCollators {
+ desired_collators: max,
+ });
Ok(())
}
+ #[pallet::call_index(5)]
#[pallet::weight(T::DbWeight::get().writes(1))]
pub fn set_collator_selection_license_bond(
origin: OriginFor<T>,
@@ -235,6 +239,7 @@
Ok(())
}
+ #[pallet::call_index(6)]
#[pallet::weight(T::DbWeight::get().writes(1))]
pub fn set_collator_selection_kick_threshold(
origin: OriginFor<T>,
@@ -246,7 +251,9 @@
} else {
<CollatorSelectionKickThresholdOverride<T>>::kill();
}
- Self::deposit_event(Event::NewCollatorKickThreshold { length_in_blocks: threshold });
+ Self::deposit_event(Event::NewCollatorKickThreshold {
+ length_in_blocks: threshold,
+ });
Ok(())
}
}
runtime/common/data_management.rsdiffbeforeafterboth--- a/runtime/common/data_management.rs
+++ b/runtime/common/data_management.rs
@@ -58,10 +58,10 @@
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> TransactionValidity {
- match call {
- #[cfg(feature = "collator-selection")]
- RuntimeCall::Identity(_) => Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
- _ => Ok(ValidTransaction::default()),
- }
+ match call {
+ #[cfg(feature = "collator-selection")]
+ RuntimeCall::Identity(_) => Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
+ _ => Ok(ValidTransaction::default()),
+ }
}
}
runtime/common/mod.rsdiffbeforeafterboth--- a/runtime/common/mod.rs
+++ b/runtime/common/mod.rs
@@ -16,11 +16,11 @@
pub mod config;
pub mod construct_runtime;
+pub mod data_management;
pub mod dispatch;
pub mod ethereum;
pub mod instance;
pub mod maintenance;
-pub mod data_management;
pub mod runtime_apis;
pub mod xcm;
runtime/common/tests/mod.rsdiffbeforeafterboth--- a/runtime/common/tests/mod.rs
+++ b/runtime/common/tests/mod.rs
@@ -63,9 +63,7 @@
.collect::<Vec<_>>();
let cfg = GenesisConfig {
- collator_selection: CollatorSelectionConfig {
- invulnerables,
- },
+ collator_selection: CollatorSelectionConfig { invulnerables },
session: SessionConfig { keys },
parachain_info: ParachainInfoConfig {
parachain_id: para_id.into(),
tests/src/collatorSelection.seqtest.tsdiffbeforeafterboth1// 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/>.1617import {IKeyringPair} from '@polkadot/types/types';18import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from './util';1920async function resetInvulnerables() {21 await usingPlaygrounds(async (helper, privateKey) => {22 const superuser = await privateKey('//Alice');23 const alice = await privateKey('//Alice');24 const bob = await privateKey('//Bob');25 const invulnerables = await helper.collatorSelection.getInvulnerables();26 if (!invulnerables.includes(alice.address) || !invulnerables.includes(bob.address) || invulnerables.length != 2) {27 console.warn('Alice and Bob are not the invulnerables! Reinstating them back. '28 + 'Current invulnerables\' size: ' + invulnerables.length);2930 let nonce = await helper.chain.getNonce(alice.address);31 // In case there are too many invulnerables already, remove some of them, leaving space for Alice and Bob.32 if (invulnerables.length + 2 >= helper.collatorSelection.maxCollators()) {33 await Promise.all([34 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerables.pop()], true, {nonce: nonce++}),35 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerables.pop()], true, {nonce: nonce++}),36 ]);37 }3839 nonce = await helper.chain.getNonce(alice.address);40 await Promise.all([41 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),42 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),43 ]);4445 nonce = await helper.chain.getNonce(alice.address);46 await Promise.all(invulnerables.map((invulnerable: any) => {47 if (invulnerable == alice.address || invulnerable == bob.address) return new Promise<void>(res => res());48 return helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++});49 }));50 }51 });52}5354// todo:collator Most preferable to launch this test in parallel somehow -- or change the session period (1 hr).55describe('Integration Test: Collator Selection', () => {56 let superuser: IKeyringPair;57 let previousLicenseBond = 0n;58 let licenseBond = 0n;5960 before(async function() {61 await usingPlaygrounds(async (helper, privateKey) => {62 requirePalletsOrSkip(this, helper, [Pallets.CollatorSelection]);63 superuser = await privateKey('//Alice');6465 previousLicenseBond = await helper.collatorSelection.getLicenseBond();66 licenseBond = 10n * helper.balance.getOneTokenNominal();67 await helper.getSudo().collatorSelection.setLicenseBond(superuser, licenseBond);68 });69 });7071 describe('Dynamic shuffling of collators', () => {72 // These two are the default invulnerables, and should return to be invulnerables after this suite.73 let alice: IKeyringPair;74 let bob: IKeyringPair;7576 let charlie: IKeyringPair;77 let dave: IKeyringPair;7879 before(async function() {80 await usingPlaygrounds(async (helper, privateKey) => {81 // todo:collator see again if blocks start to be finalized in dev mode82 // Skip the collator block production in dev mode, since the blocks are sealed automatically.83 if (await helper.arrange.isDevNode()) this.skip();8485 alice = await privateKey('//Alice');86 bob = await privateKey('//Bob');87 charlie = await privateKey('//Charlie');88 dave = await privateKey('//Dave');8990 expect((await helper.session.setOwnKeysFromAddress(charlie))91 .status.toLowerCase()).to.be.equal('success');92 expect((await helper.session.setOwnKeysFromAddress(dave))93 .status.toLowerCase()).to.be.equal('success');9495 const invulnerables = await helper.collatorSelection.getInvulnerables();96 if (!invulnerables.includes(alice.address) || !invulnerables.includes(bob.address) || invulnerables.length != 2) {97 console.warn('Alice and Bob are not the invulnerables! Reinstating them back. '98 + 'Current invulnerables\' size: ' + invulnerables.length);99100 let nonce = await helper.chain.getNonce(superuser.address);101 await Promise.all([102 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),103 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),104 ]);105106 nonce = await helper.chain.getNonce(superuser.address);107 await Promise.all(invulnerables.map((invulnerable: any) => {108 if (invulnerable == alice.address || invulnerable == bob.address) return new Promise((res) => res);109 return helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++});110 }));111 }112 });113 });114115 itSub('Change invulnerables and make sure they start producing blocks', async ({helper}) => {116 let nonce = await helper.chain.getNonce(superuser.address);117 await expect(Promise.all([118 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [charlie.address], true, {nonce: nonce++}),119 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [dave.address], true, {nonce: nonce++}),120 ])).to.be.fulfilled;121122 nonce = await helper.chain.getNonce(superuser.address);123 await expect(Promise.all([124 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alice.address], true, {nonce: nonce++}),125 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [bob.address], true, {nonce: nonce++}),126 ])).to.be.fulfilled;127128 const newInvulnerables = await helper.collatorSelection.getInvulnerables();129 expect(newInvulnerables).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);130131 await helper.wait.newSessions(2);132133 const newValidators = await helper.callRpc('api.query.session.validators');134 expect(newValidators).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);135136 const lastBlockNumber = await helper.chain.getLatestBlockNumber();137 await helper.wait.newBlocks(1);138 const lastCharlieBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [charlie.address])).toNumber();139 const lastDaveBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [dave.address])).toNumber();140 expect(lastCharlieBlock >= lastBlockNumber || lastDaveBlock >= lastBlockNumber).to.be.true;141 });142143 after(async () => {144 await usingPlaygrounds(async (helper) => {145 if (await helper.arrange.isDevNode()) return;146147 let nonce = await helper.chain.getNonce(superuser.address);148 await Promise.all([149 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),150 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),151 ]);152153 nonce = await helper.chain.getNonce(superuser.address);154 await Promise.all([155 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [charlie.address], true, {nonce: nonce++}),156 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [dave.address], true, {nonce: nonce++}),157 ]);158 });159 });160 });161162 describe('Getting and releasing licenses to collate', () => {163 let charlie: IKeyringPair;164 let dave: IKeyringPair;165 let crowd: IKeyringPair[];166167 before(async function() {168 await usingPlaygrounds(async (helper, privateKey) => {169 charlie = await privateKey('//Charlie');170 dave = await privateKey('//Dave');171 crowd = await helper.arrange.createCrowd(20, 100n, superuser);172173 // set session keys for everyone174 expect((await helper.session.setOwnKeysFromAddress(charlie))175 .status.toLowerCase()).to.be.equal('success');176 expect((await helper.session.setOwnKeysFromAddress(dave))177 .status.toLowerCase()).to.be.equal('success');178 await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));179 });180 });181182 describe('Positive', () => {183 itSub('Can lease and release a license', async ({helper}) => {184 const account = crowd.pop()!;185186 // make sure it does not have any reserved funds187 expect((await helper.balance.getSubstrateFull(account.address)).reserved).to.be.equal(0n);188189 // getting a license reserves a license bond cost190 await helper.collatorSelection.obtainLicense(account);191 expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(licenseBond);192 expect((await helper.balance.getSubstrateFull(account.address)).reserved).to.be.equal(licenseBond);193194 // releasing a license un-reserves the license bond cost195 await helper.collatorSelection.releaseLicense(account);196 expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(0n);197198 const balance = await helper.balance.getSubstrateFull(account.address);199 expect(balance.reserved).to.be.equal(0n);200 expect(balance.free > 100n - licenseBond);201 });202203 itSub('Can force revoke a license', async ({helper}) => {204 const account = crowd.pop()!;205206 // getting a license reserves a license bond cost207 const previousBalance = await helper.balance.getSubstrateFull(account.address);208 await helper.collatorSelection.obtainLicense(account);209 expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(licenseBond);210211 // force-releasing a license un-reserves the license bond cost as well212 await helper.getSudo().collatorSelection.forceRevokeLicense(superuser, account.address);213 expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(previousBalance.reserved);214215 const balance = await helper.balance.getSubstrateFull(account.address);216 expect(balance.reserved).to.be.equal(previousBalance.reserved);217 expect(balance.free > previousBalance.free - licenseBond);218 });219 });220221 describe('Negative', () => {222 itSub('Cannot get a license without session keys set', async ({helper}) => {223 const [account] = await helper.arrange.createAccounts([100n], superuser);224 await expect(helper.collatorSelection.obtainLicense(account))225 .to.be.rejectedWith(/collatorSelection.ValidatorNotRegistered/);226 });227228 itSub('Cannot register a license twice', async ({helper}) => {229 const account = crowd.pop()!;230 await helper.collatorSelection.obtainLicense(account);231 await expect(helper.collatorSelection.obtainLicense(account))232 .to.be.rejectedWith(/collatorSelection.AlreadyHoldingLicense/);233 });234235 itSub('Cannot release a license twice', async ({helper}) => {236 const account = crowd.pop()!;237 await helper.collatorSelection.obtainLicense(account);238 await helper.collatorSelection.releaseLicense(account);239 await expect(helper.collatorSelection.releaseLicense(account))240 .to.be.rejectedWith(/collatorSelection.NoLicense/);241 });242243 itSub('Cannot force revoke a license as non-sudo', async ({helper}) => {244 const account = crowd.pop()!;245 await helper.collatorSelection.obtainLicense(account);246 await expect(helper.collatorSelection.forceRevokeLicense(superuser, account.address))247 .to.be.rejectedWith(/BadOrigin/);248 });249 });250 });251252 describe('Onboarding, collating, and offboarding as collator candidates', () => {253 // These two are the default invulnerables, and should return to be invulnerables after this suite.254 let charlie: IKeyringPair;255 let dave: IKeyringPair;256 let crowd: IKeyringPair[];257258 before(async function() {259 await usingPlaygrounds(async (helper, privateKey) => {260 charlie = await privateKey('//Charlie');261 dave = await privateKey('//Dave');262 crowd = await helper.arrange.createCrowd(20, 100n, superuser);263264 // set session keys for everyone265 expect((await helper.session.setOwnKeysFromAddress(charlie))266 .status.toLowerCase()).to.be.equal('success');267 expect((await helper.session.setOwnKeysFromAddress(dave))268 .status.toLowerCase()).to.be.equal('success');269 await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));270 });271 });272273 describe('Positive', () => {274 itSub('Can onboard and offboard repeatedly', async ({helper}) => {275 const account = crowd.pop()!;276 await helper.collatorSelection.obtainLicense(account);277 await helper.collatorSelection.onboard(account);278 expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([account.address]);279280 await helper.collatorSelection.offboard(account);281 expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([]);282283 await helper.collatorSelection.onboard(account);284 expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([account.address]);285286 await helper.collatorSelection.offboard(account);287 expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([]);288 });289290 itSub('Dithmarschen', async ({helper}) => {291 // This one shouldn't even be able to produce blocks.292 const account = crowd.pop()!;293 await helper.collatorSelection.obtainLicense(account);294 await helper.collatorSelection.onboard(account);295 expect(await helper.collatorSelection.getCandidates()).to.contain(account.address);296297 // Wait for 3 new sessions before checking that the collator will be kicked:298 // one to get collator onboarded, and another two for the collator to fail299 await helper.wait.newSessions(3);300301 expect(await helper.collatorSelection.getCandidates()).to.not.contain(account.address);302 expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(0n);303304 // The account's reserved funds get slashed as a penalty305 const balance = await helper.balance.getSubstrateFull(account.address);306 expect(balance.reserved).to.be.equal(0n);307 expect(balance.free < 100n - licenseBond);308 });309 });310311 describe('Negative', () => {312 itSub('Cannot onboard without a license', async ({helper}) => {313 const account = crowd.pop()!;314 await expect(helper.collatorSelection.onboard(account))315 .to.be.rejectedWith(/collatorSelection.NoLicense/);316 });317318 itSub('Cannot offboard without a license', async ({helper}) => {319 const account = crowd.pop()!;320 await expect(helper.collatorSelection.offboard(account))321 .to.be.rejectedWith(/collatorSelection.NotCandidate/);322 });323324 itSub('Cannot offboard while not onboarded', async ({helper}) => {325 const account = crowd.pop()!;326 await helper.collatorSelection.obtainLicense(account);327 await expect(helper.collatorSelection.offboard(account))328 .to.be.rejectedWith(/collatorSelection.NotCandidate/);329 });330331 itSub('Cannot onboard while already onboarded', async ({helper}) => {332 const account = crowd.pop()!;333 await helper.collatorSelection.obtainLicense(account);334 await helper.collatorSelection.onboard(account);335 await expect(helper.collatorSelection.onboard(account))336 .to.be.rejectedWith(/collatorSelection.AlreadyCandidate/);337 });338 });339 });340341 describe('Addition and removal of invulnerables', () => {342 before(async function() {343 await resetInvulnerables();344 });345346 describe('Positive', () => {347 itSub('Adds an invulnerable', async ({helper}) => {348 const [account] = await helper.arrange.createAccounts([10n], superuser);349 const invulnerables = await helper.collatorSelection.getInvulnerables();350351 await helper.session.setOwnKeysFromAddress(account);352 await helper.getSudo().collatorSelection.addInvulnerable(superuser, account.address);353354 const newInvulnerables = await helper.collatorSelection.getInvulnerables();355 expect(invulnerables.concat(account.address)).to.have.all.members(newInvulnerables);356 });357358 itSub('Removes an invulnerable', async ({helper}) => {359 const invulnerables = await helper.collatorSelection.getInvulnerables();360 const lastInvulnerable = invulnerables.pop()!;361362 await helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable);363 const newInvulnerables = await helper.collatorSelection.getInvulnerables();364 // invulnerables had its last element removed, so they should be equal365 expect(newInvulnerables).to.have.all.members(invulnerables);366 });367 });368369 describe('Negative', () => {370 itSub('Does not duplicate an invulnerable', async ({helper}) => {371 const invulnerables = await helper.collatorSelection.getInvulnerables();372 // adding an already invulnerable should not fail, but should not duplicate it either373 await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, invulnerables[0]))374 .to.be.fulfilled;375 const newInvulnerables = await helper.collatorSelection.getInvulnerables();376 expect(newInvulnerables).to.have.all.members(invulnerables);377 });378379 itSub('Cannot remove a non-existent invulnerable', async ({helper}) => {380 const [account] = await helper.arrange.createAccounts([0n], superuser);381 await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, account.address))382 .to.be.rejectedWith(/collatorSelection.NotInvulnerable/);383 });384385 itSub('Cannot allow invulnerables to be empty', async ({helper}) => {386 const invulnerables = await helper.collatorSelection.getInvulnerables();387 const lastInvulnerable = invulnerables.pop()!;388389 let nonce = await helper.chain.getNonce(superuser.address);390 await Promise.all(invulnerables.map((i: any) =>391 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i], true, {nonce: nonce++})));392393 await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable))394 .to.be.rejectedWith(/collatorSelection.TooFewInvulnerables/);395396 const newInvulnerables = await helper.collatorSelection.getInvulnerables();397 expect(newInvulnerables).to.be.deep.equal([lastInvulnerable]);398399 // restore the invulnerables to the previous state400 nonce = await helper.chain.getNonce(superuser.address);401 await Promise.all(invulnerables.map((i: any) =>402 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i], true, {nonce: nonce++})));403 });404405 itSub('Cannot have too many invulnerables', async ({helper}) => {406 // todo:collator make sure that there is enough session time for a set of tests407 // 28 non-functioning collators, teehee.408409 const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;410 const invulnerablesUntilLimit = helper.collatorSelection.maxCollators() - invulnerablesLength;411 const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);412 const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);413414 await Promise.all(newInvulnerables.map((i: IKeyringPair) =>415 helper.session.setOwnKeysFromAddress(i)));416 await helper.session.setOwnKeysFromAddress(lastInvulnerable);417418 let nonce = await helper.chain.getNonce(superuser.address);419 await Promise.all(newInvulnerables.map((i: IKeyringPair) =>420 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i.address], true, {nonce: nonce++})));421422 await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, lastInvulnerable.address))423 .to.be.rejectedWith(/collatorSelection.TooManyInvulnerables/);424425 // restore the invulnerables to the previous state426 nonce = await helper.chain.getNonce(superuser.address);427 await Promise.all(newInvulnerables.map((i: IKeyringPair) =>428 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i.address], true, {nonce: nonce++})));429 });430431 itSub('Forbids a non-sudo to add an invulnerable', async ({helper}) => {432 const [account] = await helper.arrange.createAccounts([10n], superuser);433 const invulnerables = await helper.collatorSelection.getInvulnerables();434435 await helper.session.setOwnKeysFromAddress(account);436 await expect(helper.collatorSelection.addInvulnerable(superuser, account.address))437 .to.be.rejectedWith(/BadOrigin/);438439 const newInvulnerables = await helper.collatorSelection.getInvulnerables();440 expect(newInvulnerables).to.be.members(invulnerables);441 });442443 itSub('Forbids a non-sudo to remove an invulnerable', async ({helper}) => {444 const invulnerables = await helper.collatorSelection.getInvulnerables();445 await expect(helper.collatorSelection.removeInvulnerable(superuser, invulnerables[0]))446 .to.be.rejectedWith(/BadOrigin/);447 expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);448 });449 });450 });451452 after(async () => {453 // eslint-disable-next-line require-await454 await usingPlaygrounds(async (helper) => {455 if (helper.fetchMissingPalletNames([Pallets.CollatorSelection]).length != 0) return;456457 await helper.getSudo().collatorSelection.setLicenseBond(superuser, previousLicenseBond);458459 const candidates = await helper.collatorSelection.getCandidates();460 let nonce = await helper.chain.getNonce(superuser.address);461 await Promise.all(candidates.map(candidate =>462 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.forceRevokeLicense', [candidate], true, {nonce: nonce++})));463 });464 });465});tests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-tx.ts
+++ b/tests/src/interfaces/augment-api-tx.ts
@@ -237,7 +237,7 @@
*
* This call is, of course, not applicable to `Invulnerable` collators.
**/
- forceRevokeLicense: AugmentedSubmittable<(who: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [AccountId32]>;
+ forceReleaseLicense: AugmentedSubmittable<(who: AccountId32 | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [AccountId32]>;
/**
* Purchase a license on block collation for this account.
* It does not make it a collator candidate, use `onboard` afterward. The account must
tests/src/interfaces/default/types.tsdiffbeforeafterboth--- a/tests/src/interfaces/default/types.ts
+++ b/tests/src/interfaces/default/types.ts
@@ -1243,11 +1243,11 @@
readonly isOnboard: boolean;
readonly isOffboard: boolean;
readonly isReleaseLicense: boolean;
- readonly isForceRevokeLicense: boolean;
- readonly asForceRevokeLicense: {
+ readonly isForceReleaseLicense: boolean;
+ readonly asForceReleaseLicense: {
readonly who: AccountId32;
} & Struct;
- readonly type: 'AddInvulnerable' | 'RemoveInvulnerable' | 'GetLicense' | 'Onboard' | 'Offboard' | 'ReleaseLicense' | 'ForceRevokeLicense';
+ readonly type: 'AddInvulnerable' | 'RemoveInvulnerable' | 'GetLicense' | 'Onboard' | 'Offboard' | 'ReleaseLicense' | 'ForceReleaseLicense';
}
/** @name PalletCollatorSelectionError */
tests/src/interfaces/lookup.tsdiffbeforeafterboth--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -1692,7 +1692,7 @@
onboard: 'Null',
offboard: 'Null',
release_license: 'Null',
- force_revoke_license: {
+ force_release_license: {
who: 'AccountId32'
}
}
tests/src/interfaces/types-lookup.tsdiffbeforeafterboth--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -1867,11 +1867,11 @@
readonly isOnboard: boolean;
readonly isOffboard: boolean;
readonly isReleaseLicense: boolean;
- readonly isForceRevokeLicense: boolean;
- readonly asForceRevokeLicense: {
+ readonly isForceReleaseLicense: boolean;
+ readonly asForceReleaseLicense: {
readonly who: AccountId32;
} & Struct;
- readonly type: 'AddInvulnerable' | 'RemoveInvulnerable' | 'GetLicense' | 'Onboard' | 'Offboard' | 'ReleaseLicense' | 'ForceRevokeLicense';
+ readonly type: 'AddInvulnerable' | 'RemoveInvulnerable' | 'GetLicense' | 'Onboard' | 'Offboard' | 'ReleaseLicense' | 'ForceReleaseLicense';
}
/** @name PalletCollatorSelectionError (185) */
tests/src/util/playgrounds/unique.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -2772,8 +2772,8 @@
return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.releaseLicense', []);
}
- forceRevokeLicense(signer: TSigner, released: string) {
- return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.forceRevokeLicense', [released]);
+ forceReleaseLicense(signer: TSigner, released: string) {
+ return this.helper.executeExtrinsic(signer, 'api.tx.collatorSelection.forceReleaseLicense', [released]);
}
async hasLicense(address: string): Promise<bigint> {