difftreelog
tests(collator-selection): further fixes
in: master
2 files changed
pallets/collator-selection/src/tests.rsdiffbeforeafterboth--- a/pallets/collator-selection/src/tests.rs
+++ b/pallets/collator-selection/src/tests.rs
@@ -73,10 +73,7 @@
// cannot set invulnerables without associated validator keys
assert_noop!(
- CollatorSelection::add_invulnerable(
- RuntimeOrigin::signed(RootAccount::get()),
- 7
- ),
+ CollatorSelection::add_invulnerable(RuntimeOrigin::signed(RootAccount::get()), 7),
Error::<Test>::ValidatorNotRegistered
);
});
@@ -108,11 +105,8 @@
// cannot remove an invulnerable if there would be 0 invulnerables.
assert_noop!(
- CollatorSelection::add_invulnerable(
- RuntimeOrigin::signed(RootAccount::get()),
- 1
- ),
- Error::<Test>::NotInvulnerable
+ CollatorSelection::remove_invulnerable(RuntimeOrigin::signed(RootAccount::get()), 1),
+ Error::<Test>::TooFewInvulnerables
);
});
}
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);29 30 let nonce = await helper.chain.getNonce(alice.address);31 await Promise.all([32 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),33 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),34 ]);3536 nonce = await helper.chain.getNonce(alice.address);37 await Promise.all(invulnerables.map((invulnerable: any) => {38 if (invulnerable == alice.address || invulnerable == bob.address) return new Promise<void>(res => res());39 return helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++});40 }));41 }42 });43}4445// todo:collator Most preferable to launch this test in parallel somehow -- or change the session period (1 hr).46// + 18 tests: 5 (1+4) on session change47describe('Integration Test: Collator Selection', () => {48 let superuser: IKeyringPair;4950 before(async function() { 51 await usingPlaygrounds(async (helper, privateKey) => {52 requirePalletsOrSkip(this, helper, [Pallets.CollatorSelection]);53 superuser = await privateKey('//Alice');54 });55 });5657 describe('Dynamic shuffling of collators', () => {58 // These two are the default invulnerables, and should return to be invulnerables after this suite.59 let alice: IKeyringPair;60 let bob: IKeyringPair;6162 let charlie: IKeyringPair;63 let dave: IKeyringPair;64 65 before(async function() { 66 await usingPlaygrounds(async (helper, privateKey) => {67 alice = await privateKey('//Alice');68 bob = await privateKey('//Bob');69 charlie = await privateKey('//Charlie');70 dave = await privateKey('//Dave');7172 expect((await helper.collatorSelection.setOwnKeys(charlie))73 .status.toLowerCase()).to.be.equal('success');74 expect((await helper.collatorSelection.setOwnKeys(dave))75 .status.toLowerCase()).to.be.equal('success');76 77 // todo:collator check necessity + add RPC for invulnerables / just improve in general78 // validators = await helper.callRpc('api.query.session.validators');79 const invulnerables = await helper.collatorSelection.getInvulnerables();80 if (!invulnerables.includes(alice.address) || !invulnerables.includes(bob.address) || invulnerables.length != 2) {81 console.warn('Alice and Bob are not the invulnerables! Reinstating them back. ' 82 + 'Current invulnerables\' size: ' + invulnerables.length);83 84 let nonce = await helper.chain.getNonce(superuser.address);85 await Promise.all([86 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),87 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),88 ]);89 90 nonce = await helper.chain.getNonce(superuser.address);91 await Promise.all(invulnerables.map((invulnerable: any) => {92 if (invulnerable == alice.address || invulnerable == bob.address) return new Promise((res) => res);93 return helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++});94 }));95 }96 });97 });98 99 itSub('Change invulnerables and make sure they start producing blocks', async ({helper}) => {100 let nonce = await helper.chain.getNonce(superuser.address);101 await expect(Promise.all([102 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [charlie.address], true, {nonce: nonce++}),103 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [dave.address], true, {nonce: nonce++}),104 ])).to.be.fulfilled;105 106 nonce = await helper.chain.getNonce(superuser.address);107 await expect(Promise.all([108 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alice.address], true, {nonce: nonce++}),109 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [bob.address], true, {nonce: nonce++}),110 ])).to.be.fulfilled;111 112 const newInvulnerables = await helper.collatorSelection.getInvulnerables();113 expect(newInvulnerables).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);114 115 const expectedSessionIndex = (await helper.callRpc('api.query.session.currentIndex')).toNumber() + 2;116 let currentSessionIndex = -1;117 console.log('Waiting for the session after the next.' 118 + ' This might take a while -- check SessionPeriod in pallet_session::Config for session time.');119 120 while (currentSessionIndex < expectedSessionIndex) {121 // eslint-disable-next-line no-async-promise-executor122 currentSessionIndex = await expect(helper.wait.withTimeout(new Promise(async (resolve) => {123 await helper.wait.newBlocks(1);124 const res = (await helper.callRpc('api.query.session.currentIndex')).toNumber();125 resolve(res);126 }), 24000, 'The chain has stopped producing blocks!')).to.be.fulfilled;127 }128 129 const newValidators = await helper.callRpc('api.query.session.validators');130 expect(newValidators).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);131 132 const lastBlockNumber = await helper.chain.getLatestBlockNumber();133 await helper.wait.newBlocks(1);134 const lastCharlieBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [charlie.address])).toNumber();135 const lastDaveBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [dave.address])).toNumber();136 expect(lastCharlieBlock >= lastBlockNumber || lastDaveBlock >= lastBlockNumber).to.be.true;137 });138 139 // todo:collator keyless invulnerables? will hang, so, a breaking test, eh140 // register candidate without sudos and the like141 142 after(async () => {143 await usingPlaygrounds(async (helper) => {144 if (helper.fetchMissingPalletNames([Pallets.CollatorSelection]).length != 0) return;145146 let nonce = await helper.chain.getNonce(superuser.address);147 await Promise.all([148 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),149 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),150 ]);151 152 nonce = await helper.chain.getNonce(superuser.address);153 await Promise.all([154 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [charlie.address], true, {nonce: nonce++}),155 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [dave.address], true, {nonce: nonce++}),156 ]);157 });158 });159 });160161 // todo:collator make sure that there is enough session time for a set of tests162 // 28 non-functioning collators, teehee.163164 describe.skip('Addition and removal of invulnerables', () => {165 before(async function() {166 await resetInvulnerables();167 });168169 describe('Positive', () => {170 itSub('Adds an invulnerable', async ({helper}) => {171 const [account] = await helper.arrange.createAccounts([10n], superuser);172 const invulnerables = await helper.collatorSelection.getInvulnerables();173174 await helper.collatorSelection.setOwnKeys(account);175 await helper.getSudo().collatorSelection.addInvulnerable(superuser, account.address);176 177 const newInvulnerables = await helper.collatorSelection.getInvulnerables();178 expect(invulnerables.concat(account.address)).to.have.all.members(newInvulnerables);179 });180181 itSub('Removes an invulnerable', async ({helper}) => {182 const invulnerables = await helper.collatorSelection.getInvulnerables();183 const lastInvulnerable = invulnerables.pop();184185 await helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable);186 const newInvulnerables = await helper.collatorSelection.getInvulnerables();187 // invulnerables had its last element removed, so they should be equal188 expect(newInvulnerables).to.have.all.members(invulnerables);189 });190 });191192 describe('Negative', () => {193 itSub('Does not duplicate an invulnerable', async ({helper}) => {194 const invulnerables = await helper.collatorSelection.getInvulnerables();195 // adding an already invulnerable should not fail, but should not duplicate it either196 await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, invulnerables[0]))197 .to.be.fulfilled;198 const newInvulnerables = await helper.collatorSelection.getInvulnerables();199 expect(newInvulnerables).to.have.all.members(invulnerables);200 });201202 itSub('Cannot allow invulnerables to be empty', async ({helper}) => {203 const invulnerables = await helper.collatorSelection.getInvulnerables();204 const lastInvulnerable = invulnerables.pop();205206 let nonce = await helper.chain.getNonce(superuser.address);207 await Promise.all(invulnerables.map((i: any) => 208 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i], true, {nonce: nonce++})));209210 await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable))211 .to.be.rejected;//todo:collator With(/collatorSelection.TooFewInvulnerables/);212213 const newInvulnerables = await helper.collatorSelection.getInvulnerables();214 expect(newInvulnerables).to.be.deep.equal([lastInvulnerable]);215 216 // restore the invulnerables to the previous state217 nonce = await helper.chain.getNonce(superuser.address);218 await Promise.all(invulnerables.map((i: any) => 219 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i], true, {nonce: nonce++})));220 });221222 itSub('Cannot have too many invulnerables', async ({helper}) => {223 const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;224 const invulnerablesUntilLimit = 30 - invulnerablesLength;225 const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);226 const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);227228 await Promise.all(newInvulnerables.map((i: IKeyringPair) => 229 helper.collatorSelection.setOwnKeys(i)));230 await helper.collatorSelection.setOwnKeys(lastInvulnerable);231232 let nonce = await helper.chain.getNonce(superuser.address);233 await Promise.all(newInvulnerables.map((i: IKeyringPair) => 234 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i.address], true, {nonce: nonce++})));235236 await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, lastInvulnerable.address))237 .to.be.rejected; // todo:collator With(/collatorSelection.TooManyInvulnerables/);238 239 // restore the invulnerables to the previous state240 nonce = await helper.chain.getNonce(superuser.address);241 await Promise.all(newInvulnerables.map((i: IKeyringPair) => 242 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i.address], true, {nonce: nonce++})));243 });244245 itSub('Forbids a non-sudo to add an invulnerable', async ({helper}) => {246 const [account] = await helper.arrange.createAccounts([10n], superuser);247 const invulnerables = await helper.collatorSelection.getInvulnerables();248249 await helper.collatorSelection.setOwnKeys(account);250 await expect(helper.collatorSelection.addInvulnerable(superuser, account.address))251 .to.be.rejectedWith(/BadOrigin/);252253 const newInvulnerables = await helper.collatorSelection.getInvulnerables();254 expect(newInvulnerables).to.be.members(invulnerables);255 });256257 itSub('Forbids a non-sudo to remove an invulnerable', async ({helper}) => {258 const invulnerables = await helper.collatorSelection.getInvulnerables();259 await expect(helper.collatorSelection.removeInvulnerable(superuser, invulnerables[0]))260 .to.be.rejectedWith(/BadOrigin/);261 expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);262 });263 });264 265 // todo:collator after266 });267});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/>.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);29 30 let nonce = await helper.chain.getNonce(alice.address);31 await Promise.all([32 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),33 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),34 ]);3536 nonce = await helper.chain.getNonce(alice.address);37 await Promise.all(invulnerables.map((invulnerable: any) => {38 if (invulnerable == alice.address || invulnerable == bob.address) return new Promise<void>(res => res());39 return helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++});40 }));41 }42 });43}4445// todo:collator Most preferable to launch this test in parallel somehow -- or change the session period (1 hr).46// + 18 tests: 5 (1+4) on session change47describe('Integration Test: Collator Selection', () => {48 let superuser: IKeyringPair;4950 before(async function() { 51 await usingPlaygrounds(async (helper, privateKey) => {52 requirePalletsOrSkip(this, helper, [Pallets.CollatorSelection]);53 superuser = await privateKey('//Alice');54 });55 });5657 describe('Dynamic shuffling of collators', () => {58 // These two are the default invulnerables, and should return to be invulnerables after this suite.59 let alice: IKeyringPair;60 let bob: IKeyringPair;6162 let charlie: IKeyringPair;63 let dave: IKeyringPair;64 65 before(async function() { 66 await usingPlaygrounds(async (helper, privateKey) => {67 // todo:collator see again if blocks start to be finalized in dev mode 68 // Skip the collator block production in dev mode, since the blocks are sealed automatically.69 if (await helper.arrange.isDevNode()) this.skip();7071 alice = await privateKey('//Alice');72 bob = await privateKey('//Bob');73 charlie = await privateKey('//Charlie');74 dave = await privateKey('//Dave');7576 expect((await helper.collatorSelection.setOwnKeys(charlie))77 .status.toLowerCase()).to.be.equal('success');78 expect((await helper.collatorSelection.setOwnKeys(dave))79 .status.toLowerCase()).to.be.equal('success');80 81 // todo:collator check necessity + add RPC for invulnerables / just improve in general82 // validators = await helper.callRpc('api.query.session.validators');83 const invulnerables = await helper.collatorSelection.getInvulnerables();84 if (!invulnerables.includes(alice.address) || !invulnerables.includes(bob.address) || invulnerables.length != 2) {85 console.warn('Alice and Bob are not the invulnerables! Reinstating them back. ' 86 + 'Current invulnerables\' size: ' + invulnerables.length);87 88 let nonce = await helper.chain.getNonce(superuser.address);89 await Promise.all([90 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),91 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),92 ]);93 94 nonce = await helper.chain.getNonce(superuser.address);95 await Promise.all(invulnerables.map((invulnerable: any) => {96 if (invulnerable == alice.address || invulnerable == bob.address) return new Promise((res) => res);97 return helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++});98 }));99 }100 });101 });102 103 itSub('Change invulnerables and make sure they start producing blocks', async ({helper}) => {104 let nonce = await helper.chain.getNonce(superuser.address);105 await expect(Promise.all([106 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [charlie.address], true, {nonce: nonce++}),107 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [dave.address], true, {nonce: nonce++}),108 ])).to.be.fulfilled;109 110 nonce = await helper.chain.getNonce(superuser.address);111 await expect(Promise.all([112 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alice.address], true, {nonce: nonce++}),113 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [bob.address], true, {nonce: nonce++}),114 ])).to.be.fulfilled;115 116 const newInvulnerables = await helper.collatorSelection.getInvulnerables();117 expect(newInvulnerables).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);118 119 const expectedSessionIndex = (await helper.callRpc('api.query.session.currentIndex')).toNumber() + 2;120 let currentSessionIndex = -1;121 console.log('Waiting for the session after the next.' 122 + ' This might take a while -- check SessionPeriod in pallet_session::Config for session time.');123 124 while (currentSessionIndex < expectedSessionIndex) {125 // eslint-disable-next-line no-async-promise-executor126 currentSessionIndex = await expect(helper.wait.withTimeout(new Promise(async (resolve) => {127 await helper.wait.newBlocks(1);128 const res = (await helper.callRpc('api.query.session.currentIndex')).toNumber();129 resolve(res);130 }), 24000, 'The chain has stopped producing blocks!')).to.be.fulfilled;131 }132 133 const newValidators = await helper.callRpc('api.query.session.validators');134 expect(newValidators).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);135 136 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 });142 143 // todo:collator keyless invulnerables? will hang, so, a breaking test, eh144 // register candidate without sudos and the like145 146 after(async () => {147 await usingPlaygrounds(async (helper) => {148 if (await helper.arrange.isDevNode()) return;149150 let nonce = await helper.chain.getNonce(superuser.address);151 await Promise.all([152 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),153 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),154 ]);155 156 nonce = await helper.chain.getNonce(superuser.address);157 await Promise.all([158 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [charlie.address], true, {nonce: nonce++}),159 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [dave.address], true, {nonce: nonce++}),160 ]);161 });162 });163 });164165 // todo:collator make sure that there is enough session time for a set of tests166 // 28 non-functioning collators, teehee.167168 describe('Addition and removal of invulnerables', () => {169 before(async function() {170 await resetInvulnerables();171 });172173 describe('Positive', () => {174 itSub('Adds an invulnerable', async ({helper}) => {175 const [account] = await helper.arrange.createAccounts([10n], superuser);176 const invulnerables = await helper.collatorSelection.getInvulnerables();177178 await helper.collatorSelection.setOwnKeys(account);179 await helper.getSudo().collatorSelection.addInvulnerable(superuser, account.address);180 181 const newInvulnerables = await helper.collatorSelection.getInvulnerables();182 expect(invulnerables.concat(account.address)).to.have.all.members(newInvulnerables);183 });184185 itSub('Removes an invulnerable', async ({helper}) => {186 const invulnerables = await helper.collatorSelection.getInvulnerables();187 const lastInvulnerable = invulnerables.pop();188189 await helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable);190 const newInvulnerables = await helper.collatorSelection.getInvulnerables();191 // invulnerables had its last element removed, so they should be equal192 expect(newInvulnerables).to.have.all.members(invulnerables);193 });194 });195196 describe('Negative', () => {197 itSub('Does not duplicate an invulnerable', async ({helper}) => {198 const invulnerables = await helper.collatorSelection.getInvulnerables();199 // adding an already invulnerable should not fail, but should not duplicate it either200 await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, invulnerables[0]))201 .to.be.fulfilled;202 const newInvulnerables = await helper.collatorSelection.getInvulnerables();203 expect(newInvulnerables).to.have.all.members(invulnerables);204 });205206 itSub('Cannot allow invulnerables to be empty', async ({helper}) => {207 const invulnerables = await helper.collatorSelection.getInvulnerables();208 const lastInvulnerable = invulnerables.pop();209210 let nonce = await helper.chain.getNonce(superuser.address);211 await Promise.all(invulnerables.map((i: any) => 212 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i], true, {nonce: nonce++})));213214 await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable))215 .to.be.rejected;//todo:collator With(/collatorSelection.TooFewInvulnerables/);216217 const newInvulnerables = await helper.collatorSelection.getInvulnerables();218 expect(newInvulnerables).to.be.deep.equal([lastInvulnerable]);219 220 // restore the invulnerables to the previous state221 nonce = await helper.chain.getNonce(superuser.address);222 await Promise.all(invulnerables.map((i: any) => 223 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i], true, {nonce: nonce++})));224 });225226 itSub('Cannot have too many invulnerables', async ({helper}) => {227 const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;228 const invulnerablesUntilLimit = 30 - invulnerablesLength;229 const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);230 const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);231232 await Promise.all(newInvulnerables.map((i: IKeyringPair) => 233 helper.collatorSelection.setOwnKeys(i)));234 await helper.collatorSelection.setOwnKeys(lastInvulnerable);235236 let nonce = await helper.chain.getNonce(superuser.address);237 await Promise.all(newInvulnerables.map((i: IKeyringPair) => 238 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i.address], true, {nonce: nonce++})));239240 await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, lastInvulnerable.address))241 .to.be.rejected; // todo:collator With(/collatorSelection.TooManyInvulnerables/);242 243 // restore the invulnerables to the previous state244 nonce = await helper.chain.getNonce(superuser.address);245 await Promise.all(newInvulnerables.map((i: IKeyringPair) => 246 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i.address], true, {nonce: nonce++})));247 });248249 itSub('Forbids a non-sudo to add an invulnerable', async ({helper}) => {250 const [account] = await helper.arrange.createAccounts([10n], superuser);251 const invulnerables = await helper.collatorSelection.getInvulnerables();252253 await helper.collatorSelection.setOwnKeys(account);254 await expect(helper.collatorSelection.addInvulnerable(superuser, account.address))255 .to.be.rejectedWith(/BadOrigin/);256257 const newInvulnerables = await helper.collatorSelection.getInvulnerables();258 expect(newInvulnerables).to.be.members(invulnerables);259 });260261 itSub('Forbids a non-sudo to remove an invulnerable', async ({helper}) => {262 const invulnerables = await helper.collatorSelection.getInvulnerables();263 await expect(helper.collatorSelection.removeInvulnerable(superuser, invulnerables[0]))264 .to.be.rejectedWith(/BadOrigin/);265 expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);266 });267 });268 269 after(async () => {270 // eslint-disable-next-line require-await271 await usingPlaygrounds(async (helper) => {272 if (helper.fetchMissingPalletNames([Pallets.CollatorSelection]).length != 0) return;273 274 // todo:collator after275 });276 });277 });278});