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

difftreelog

Merge pull request #988 from UniqueNetwork/fix/collector-selection-tests-release-60

Yaroslav Bolyukin2023-09-08parents: #e6eb884 #095843d.patch.diff
in: master

9 files changed

modified.baedeker/collator-selection.jsonnetdiffbeforeafterboth
--- a/.baedeker/collator-selection.jsonnet
+++ b/.baedeker/collator-selection.jsonnet
@@ -31,7 +31,7 @@
 			bin: $.bin,
 			wantedKeys: 'para',
 		},
-		for name in ['alice', 'bob']
+		for name in ['alpha', 'beta', 'gamma', 'delta']
 	},
 };
 
modified.docker/docker-compose.gov.j2diffbeforeafterboth
--- a/.docker/docker-compose.gov.j2
+++ b/.docker/docker-compose.gov.j2
@@ -21,4 +21,4 @@
       options:
         max-size: "1m"
         max-file: "3"
-    command: cargo run --release --features={{ NETWORK }}-runtime,{{ WASM_NAME }}-runtime/gov-test-timings -- --dev -linfo --rpc-cors=all --unsafe-rpc-external
+    command: cargo run --release --features={{ NETWORK }}-runtime,gov-test-timings -- --dev -linfo --rpc-cors=all --unsafe-rpc-external
modified.github/workflows/collator-selection.ymldiffbeforeafterboth
--- a/.github/workflows/collator-selection.yml
+++ b/.github/workflows/collator-selection.yml
@@ -139,7 +139,7 @@
           context: .
           dockerfile: .docker/Dockerfile-unique
           args: |
-            --build-arg RUNTIME_FEATURES=${{ matrix.runtime_features }}
+            --build-arg RUNTIME_FEATURES=${{ matrix.runtime_features }},session-test-timings
             --build-arg RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}
           dockerhub_username: ${{ secrets.CORE_DOCKERHUB_USERNAME }}
           dockerhub_token: ${{ secrets.CORE_DOCKERHUB_TOKEN }}
@@ -161,7 +161,7 @@
           jpath: |
             .baedeker/vendor
           tla-str: |
-            relay_spec=westend-local            
+            relay_spec=westend-local
           inputs: |
             .baedeker/collator-selection.jsonnet
             snippet:(import 'baedeker-library/ops/rewrites.libsonnet').rewriteNodePaths({'bin/polkadot':{dockerImage:'${{ steps.polkadot.outputs.name }}'}})
modifiednode/cli/Cargo.tomldiffbeforeafterboth
--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -108,3 +108,5 @@
 runtime-benchmarks = ['opal-runtime/runtime-benchmarks', 'polkadot-cli/runtime-benchmarks', 'polkadot-service/runtime-benchmarks', 'quartz-runtime?/runtime-benchmarks', 'sc-service/runtime-benchmarks', 'unique-runtime?/runtime-benchmarks']
 sapphire-runtime = ['quartz-runtime', 'quartz-runtime/become-sapphire']
 try-runtime = ['opal-runtime?/try-runtime', 'quartz-runtime?/try-runtime', 'try-runtime-cli/try-runtime', 'unique-runtime?/try-runtime']
+session-test-timings = ['opal-runtime/session-test-timings', 'quartz-runtime?/session-test-timings', 'unique-runtime?/session-test-timings']
+gov-test-timings = ['opal-runtime/gov-test-timings', 'quartz-runtime?/gov-test-timings', 'unique-runtime?/gov-test-timings']
modifiedruntime/common/config/pallets/mod.rsdiffbeforeafterboth
--- a/runtime/common/config/pallets/mod.rs
+++ b/runtime/common/config/pallets/mod.rs
@@ -125,10 +125,20 @@
 	pub AppPromotionDailyRate: Perbill = Perbill::from_rational(5u32, 10_000);
 	pub const MaxCollators: u32 = MAX_COLLATORS;
 	pub const LicenseBond: Balance = GENESIS_LICENSE_BOND;
+
+	pub const DayRelayBlocks: BlockNumber = RELAY_DAYS;
+}
+
+#[cfg(not(feature = "session-test-timings"))]
+parameter_types! {
 	pub const SessionPeriod: BlockNumber = SESSION_LENGTH;
-	pub const DayRelayBlocks: BlockNumber = RELAY_DAYS;
 }
 
+#[cfg(feature = "session-test-timings")]
+parameter_types! {
+	pub const SessionPeriod: BlockNumber = 5 * MINUTES;
+}
+
 impl pallet_configuration::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type Balance = Balance;
modifiedruntime/opal/Cargo.tomldiffbeforeafterboth
--- a/runtime/opal/Cargo.toml
+++ b/runtime/opal/Cargo.toml
@@ -229,6 +229,7 @@
 preimage = []
 refungible = []
 unique-scheduler = []
+session-test-timings = []
 
 ################################################################################
 # local dependencies
modifiedruntime/quartz/Cargo.tomldiffbeforeafterboth
before · runtime/quartz/Cargo.toml
1################################################################################2# Package34[package]5authors = ['Unique Network <support@uniquenetwork.io>']6build = 'build.rs'7description = 'Quartz Runtime'8edition = '2021'9homepage = 'https://unique.network'10license = 'GPLv3'11name = 'quartz-runtime'12repository = 'https://github.com/UniqueNetwork/unique-chain'13version.workspace = true1415[package.metadata.docs.rs]16targets = ['x86_64-unknown-linux-gnu']1718[features]19become-sapphire = []20default = ['quartz-runtime', 'std']21limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']22pov-estimate = []23quartz-runtime = ['app-promotion', 'collator-selection', 'foreign-assets', 'governance', 'preimage', 'refungible']24runtime-benchmarks = [25	"pallet-preimage/runtime-benchmarks",26	'cumulus-pallet-parachain-system/runtime-benchmarks',27	'frame-benchmarking',28	'frame-support/runtime-benchmarks',29	'frame-system-benchmarking',30	'frame-system/runtime-benchmarks',31	'pallet-app-promotion/runtime-benchmarks',32	'pallet-balances/runtime-benchmarks',33	'pallet-collator-selection/runtime-benchmarks',34	'pallet-collective/runtime-benchmarks',35	'pallet-common/runtime-benchmarks',36	'pallet-configuration/runtime-benchmarks',37	'pallet-democracy/runtime-benchmarks',38	'pallet-ethereum/runtime-benchmarks',39	'pallet-evm-coder-substrate/runtime-benchmarks',40	'pallet-evm-migration/runtime-benchmarks',41	'pallet-foreign-assets/runtime-benchmarks',42	'pallet-fungible/runtime-benchmarks',43	'pallet-identity/runtime-benchmarks',44	'pallet-inflation/runtime-benchmarks',45	'pallet-maintenance/runtime-benchmarks',46	'pallet-membership/runtime-benchmarks',47	'pallet-nonfungible/runtime-benchmarks',48	'pallet-democracy/runtime-benchmarks',49	'pallet-collective/runtime-benchmarks',50	'pallet-ranked-collective/runtime-benchmarks',51	'pallet-membership/runtime-benchmarks',52	'pallet-referenda/runtime-benchmarks',53	'pallet-scheduler/runtime-benchmarks',54	'pallet-refungible/runtime-benchmarks',55	'pallet-scheduler/runtime-benchmarks',56	'pallet-structure/runtime-benchmarks',57	'pallet-timestamp/runtime-benchmarks',58	'pallet-unique/runtime-benchmarks',59	'pallet-xcm/runtime-benchmarks',60	'sp-runtime/runtime-benchmarks',61	'xcm-builder/runtime-benchmarks',62]63std = [64	'codec/std',65	'cumulus-pallet-aura-ext/std',66	'cumulus-pallet-parachain-system/std',67	'cumulus-pallet-xcm/std',68	'cumulus-pallet-xcmp-queue/std',69	'cumulus-primitives-core/std',70	'cumulus-primitives-utility/std',71	'frame-executive/std',72	'frame-support/std',73	'frame-system-rpc-runtime-api/std',74	'frame-system/std',75	'frame-try-runtime/std',76	'pallet-aura/std',77	'pallet-balances-adapter/std',78	'pallet-balances/std',79	'pallet-collective/std',80	'pallet-democracy/std',81	'pallet-membership/std',82	'pallet-scheduler/std',83	# 'pallet-contracts/std',84	# 'pallet-contracts-primitives/std',85	# 'pallet-contracts-rpc-runtime-api/std',86	# 'pallet-contract-helpers/std',87	"pallet-authorship/std",88	"pallet-identity/std",89	"pallet-preimage/std",90	"pallet-session/std",91	"pallet-state-trie-migration/std",92	"sp-consensus-aura/std",93	'app-promotion-rpc/std',94	'evm-coder/std',95	'fp-rpc/std',96	'fp-self-contained/std',97	'pallet-app-promotion/std',98	'pallet-base-fee/std',99	'pallet-charge-transaction/std',100	'pallet-collator-selection/std',101	'pallet-common/std',102	'pallet-configuration/std',103	'pallet-ethereum/std',104	'pallet-evm-coder-substrate/std',105	'pallet-evm-contract-helpers/std',106	'pallet-evm-migration/std',107	'pallet-evm-transaction-payment/std',108	'pallet-evm/std',109	'pallet-fungible/std',110	'pallet-inflation/std',111	'pallet-nonfungible/std',112	'pallet-democracy/std',113	'pallet-collective/std',114	'pallet-ranked-collective/std',115	'pallet-membership/std',116	'pallet-referenda/std',117	'pallet-gov-origins/std',118	'pallet-scheduler/std',119	'pallet-refungible/std',120	'pallet-structure/std',121	'pallet-sudo/std',122	'pallet-timestamp/std',123	'pallet-transaction-payment-rpc-runtime-api/std',124	'pallet-transaction-payment/std',125	'pallet-treasury/std',126	'pallet-unique/std',127	'parachain-info/std',128	'serde',129	'sp-api/std',130	'sp-block-builder/std',131	'sp-core/std',132	'sp-inherents/std',133	'sp-io/std',134	'sp-offchain/std',135	'sp-runtime/std',136	'sp-session/std',137	'sp-std/std',138	'sp-transaction-pool/std',139	'sp-version/std',140	'up-common/std',141	'up-data-structs/std',142	'up-pov-estimate-rpc/std',143	'up-rpc/std',144	'up-sponsorship/std',145	'xcm-builder/std',146	'xcm-executor/std',147	'xcm/std',148149	"orml-tokens/std",150	"orml-traits/std",151	"orml-vesting/std",152	"orml-xcm-support/std",153	"orml-xtokens/std",154	"pallet-foreign-assets/std",155	"pallet-maintenance/std",156]157try-runtime = [158	"pallet-authorship/try-runtime",159	"pallet-collator-selection/try-runtime",160	"pallet-identity/try-runtime",161	"pallet-preimage/try-runtime",162	"pallet-session/try-runtime",163	"pallet-state-trie-migration/try-runtime",164	'cumulus-pallet-aura-ext/try-runtime',165	'cumulus-pallet-dmp-queue/try-runtime',166	'cumulus-pallet-parachain-system/try-runtime',167	'cumulus-pallet-xcm/try-runtime',168	'cumulus-pallet-xcmp-queue/try-runtime',169	'fp-self-contained/try-runtime',170	'frame-executive/try-runtime',171	'frame-support/try-runtime',172	'frame-system/try-runtime',173	'frame-try-runtime',174	'orml-tokens/try-runtime',175	'orml-vesting/try-runtime',176	'orml-xtokens/try-runtime',177	'pallet-app-promotion/try-runtime',178	'pallet-aura/try-runtime',179	'pallet-balances-adapter/try-runtime',180	'pallet-balances/try-runtime',181	'pallet-charge-transaction/try-runtime',182	'pallet-common/try-runtime',183	'pallet-configuration/try-runtime',184	'pallet-ethereum/try-runtime',185	'pallet-evm-coder-substrate/try-runtime',186	'pallet-evm-contract-helpers/try-runtime',187	'pallet-evm-migration/try-runtime',188	'pallet-evm-transaction-payment/try-runtime',189	'pallet-evm/try-runtime',190	'pallet-foreign-assets/try-runtime',191	'pallet-fungible/try-runtime',192	'pallet-inflation/try-runtime',193	'pallet-maintenance/try-runtime',194	'pallet-nonfungible/try-runtime',195	'pallet-democracy/try-runtime',196	'pallet-collective/try-runtime',197	'pallet-ranked-collective/try-runtime',198	'pallet-membership/try-runtime',199	'pallet-referenda/try-runtime',200	'pallet-gov-origins/try-runtime',201	'pallet-scheduler/try-runtime',202	'pallet-refungible/try-runtime',203	'pallet-structure/try-runtime',204	'pallet-sudo/try-runtime',205	'pallet-timestamp/try-runtime',206	'pallet-transaction-payment/try-runtime',207	'pallet-treasury/try-runtime',208	'pallet-unique/try-runtime',209	'pallet-xcm/try-runtime',210	'parachain-info/try-runtime',211]212213app-promotion = []214collator-selection = []215foreign-assets = []216governance = []217preimage = []218refungible = []219unique-scheduler = []220gov-test-timings = []221222################################################################################223# local dependencies224225[dependencies]226# Note: `package = "parity-scale-codec"` must be supplied since the `Encode` macro searches for it.227codec = { workspace = true, package = "parity-scale-codec" }228229cumulus-pallet-aura-ext = { workspace = true }230cumulus-pallet-dmp-queue = { workspace = true }231cumulus-pallet-parachain-system = { workspace = true }232cumulus-pallet-xcm = { workspace = true }233cumulus-pallet-xcmp-queue = { workspace = true }234cumulus-primitives-core = { workspace = true }235cumulus-primitives-timestamp = { workspace = true }236cumulus-primitives-utility = { workspace = true }237frame-executive = { workspace = true }238frame-support = { workspace = true }239frame-system = { workspace = true }240frame-system-rpc-runtime-api = { workspace = true }241orml-tokens = { workspace = true }242orml-traits = { workspace = true }243orml-vesting = { workspace = true }244orml-xcm-support = { workspace = true }245orml-xtokens = { workspace = true }246pallet-aura = { workspace = true }247pallet-authorship = { workspace = true }248pallet-balances = { features = ["insecure_zero_ed"], workspace = true }249pallet-preimage = { workspace = true }250pallet-session = { workspace = true }251pallet-state-trie-migration = { workspace = true }252pallet-sudo = { workspace = true }253pallet-timestamp = { workspace = true }254pallet-transaction-payment = { workspace = true }255pallet-transaction-payment-rpc-runtime-api = { workspace = true }256pallet-treasury = { workspace = true }257pallet-xcm = { workspace = true }258parachain-info = { workspace = true }259polkadot-parachain = { workspace = true }260smallvec = { workspace = true }261sp-api = { workspace = true }262sp-arithmetic = { workspace = true }263sp-block-builder = { workspace = true }264sp-consensus-aura = { workspace = true }265sp-core = { workspace = true }266sp-inherents = { workspace = true }267sp-io = { workspace = true }268sp-offchain = { workspace = true }269sp-runtime = { workspace = true }270sp-session = { workspace = true }271sp-std = { workspace = true }272sp-transaction-pool = { workspace = true }273sp-version = { workspace = true }274xcm = { workspace = true }275xcm-builder = { workspace = true }276xcm-executor = { workspace = true }277278app-promotion-rpc = { workspace = true }279derivative = { workspace = true }280fp-evm = { workspace = true }281log = { workspace = true }282pallet-app-promotion = { workspace = true }283pallet-balances-adapter = { workspace = true }284pallet-collator-selection = { workspace = true }285pallet-common = { workspace = true }286pallet-configuration = { workspace = true }287pallet-fungible = { workspace = true }288pallet-identity = { workspace = true }289pallet-inflation = { workspace = true }290pallet-nonfungible = { workspace = true }291pallet-democracy = { workspace = true }292pallet-collective = { workspace = true }293pallet-ranked-collective = { workspace = true }294pallet-membership = { workspace = true }295pallet-referenda = { workspace = true }296pallet-gov-origins = { workspace = true }297pallet-scheduler = { workspace = true }298pallet-refungible = { workspace = true }299pallet-structure = { workspace = true }300pallet-unique = { workspace = true }301scale-info = { workspace = true }302up-common = { workspace = true }303up-data-structs = { workspace = true }304up-pov-estimate-rpc = { workspace = true }305up-rpc = { workspace = true }306# pallet-contract-helpers = { path = '../pallets/contract-helpers', default-features = false, version = '0.1.0' }307evm-coder = { workspace = true }308fp-rpc = { workspace = true }309fp-self-contained = { workspace = true }310num_enum = { version = "0.5.3", default-features = false }311pallet-base-fee = { workspace = true }312pallet-charge-transaction = { workspace = true }313pallet-ethereum = { workspace = true }314pallet-evm = { workspace = true }315pallet-evm-coder-substrate = { workspace = true }316pallet-evm-contract-helpers = { workspace = true }317pallet-evm-migration = { workspace = true }318pallet-evm-precompile-simple = { workspace = true }319pallet-evm-transaction-payment = { workspace = true }320pallet-foreign-assets = { workspace = true }321pallet-maintenance = { workspace = true }322precompile-utils-macro = { workspace = true }323up-sponsorship = { workspace = true }324325################################################################################326# Optional dependencies327328frame-benchmarking = { workspace = true, optional = true }329frame-system-benchmarking = { workspace = true, optional = true }330frame-try-runtime = { workspace = true, optional = true }331serde = { workspace = true, optional = true }332333334################################################################################335# Test dependencies336337pallet-test-utils = { workspace = true }338339################################################################################340# Other Dependencies341342hex-literal = { workspace = true }343impl-trait-for-tuples = { workspace = true }344345[build-dependencies]346substrate-wasm-builder = { workspace = true }
modifiedruntime/unique/Cargo.tomldiffbeforeafterboth
--- a/runtime/unique/Cargo.toml
+++ b/runtime/unique/Cargo.toml
@@ -221,6 +221,7 @@
 refungible = []
 unique-scheduler = []
 gov-test-timings = []
+session-test-timings = []
 
 ################################################################################
 # local dependencies
modifiedtests/src/collator-selection/collatorSelection.seqtest.tsdiffbeforeafterboth
--- a/tests/src/collator-selection/collatorSelection.seqtest.ts
+++ b/tests/src/collator-selection/collatorSelection.seqtest.ts
@@ -17,36 +17,48 @@
 import {IKeyringPair} from '@polkadot/types/types';
 import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from '../util';
 
+async function nodeAddress(name: string) {
+  // eslint-disable-next-line require-await
+  return await usingPlaygrounds(async (helper, _) => {
+    const envNodeStash = `RELAY_UNIQUE_NODE_${name.toUpperCase()}_STASH`;
+
+    const nodeStash = process.env[envNodeStash];
+    if(nodeStash) {
+      return helper.address.normalizeSubstrateToChainFormat(nodeStash);
+    } else {
+      throw Error(`"${envNodeStash}" env var is not set`);
+    }
+  });
+}
+
+async function getInitialInvulnerables() {
+  return await Promise.all([
+    nodeAddress('alpha'),
+    nodeAddress('beta'),
+    nodeAddress('gamma'),
+    nodeAddress('delta'),
+  ]);
+}
+
 async function resetInvulnerables() {
   await usingPlaygrounds(async (helper, privateKey) => {
     const superuser = await privateKey('//Alice');
-    const alice = await privateKey('//Alice');
-    const bob = await privateKey('//Bob');
+    const initialInvulnerables = await getInitialInvulnerables();
+
     const invulnerables = await helper.collatorSelection.getInvulnerables();
-    if(!invulnerables.includes(alice.address) || !invulnerables.includes(bob.address) || invulnerables.length != 2) {
-      console.warn('Alice and Bob are not the invulnerables! Reinstating them back. '
-        + 'Current invulnerables\' size: ' + invulnerables.length);
 
-      let nonce = await helper.chain.getNonce(alice.address);
-      // In case there are too many invulnerables already, remove some of them, leaving space for Alice and Bob.
-      if(invulnerables.length + 2 >= helper.collatorSelection.maxCollators()) {
-        await Promise.all([
-          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerables.pop()!], true, {nonce: nonce++}),
-          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerables.pop()!], true, {nonce: nonce++}),
-        ]);
-      }
+    // Remove all invulnerables but the first one
+    const firstInvulnerable = invulnerables[0];
+
+    let nonce = await helper.chain.getNonce(superuser.address);
+    await Promise.all(invulnerables.slice(1).map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++})));
 
-      nonce = await helper.chain.getNonce(alice.address);
-      await Promise.all([
-        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),
-        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),
-      ]);
+    // Add the initial invulnerables
+    await Promise.all(initialInvulnerables.map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [invulnerable], true, {nonce: nonce++})));
 
-      nonce = await helper.chain.getNonce(alice.address);
-      await Promise.all(invulnerables.map((invulnerable: any) => {
-        if(invulnerable == alice.address || invulnerable == bob.address) return new Promise<void>(res => res());
-        return helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++});
-      }));
+    // Remove the first invulnerable if it's not an initial one
+    if(!initialInvulnerables.includes(firstInvulnerable)) {
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [firstInvulnerable]);
     }
   });
 }
@@ -72,11 +84,11 @@
 
   describe('Dynamic shuffling of collators', () => {
     // These two are the default invulnerables, and should return to be invulnerables after this suite.
-    let alice: IKeyringPair;
-    let bob: IKeyringPair;
+    let alphaNode: string;
+    let betaNode: string;
 
-    let charlie: IKeyringPair;
-    let dave: IKeyringPair;
+    let gammaNode: string;
+    let deltaNode: string;
 
     before(async function() {
       await usingPlaygrounds(async (helper, privateKey) => {
@@ -84,99 +96,51 @@
         // Skip the collator block production in dev mode, since the blocks are sealed automatically.
         if(await helper.arrange.isDevNode()) this.skip();
 
-        alice = await privateKey('//Alice');
-        bob = await privateKey('//Bob');
-        charlie = await privateKey('//Charlie');
-        dave = await privateKey('//Dave');
-
-        expect((await helper.session.setOwnKeysFromAddress(charlie))
-          .status.toLowerCase()).to.be.equal('success');
-        expect((await helper.session.setOwnKeysFromAddress(dave))
-          .status.toLowerCase()).to.be.equal('success');
+        [alphaNode, betaNode, gammaNode, deltaNode] = await getInitialInvulnerables();
 
         const invulnerables = await helper.collatorSelection.getInvulnerables();
-        if(!invulnerables.includes(alice.address) || !invulnerables.includes(bob.address) || invulnerables.length != 2) {
-          console.warn('Alice and Bob are not the invulnerables! Reinstating them back. '
-            + 'Current invulnerables\' size: ' + invulnerables.length);
-
-          let nonce = await helper.chain.getNonce(superuser.address);
-          await Promise.all([
-            helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),
-            helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),
-          ]);
-
-          nonce = await helper.chain.getNonce(superuser.address);
-          await Promise.all(invulnerables.map((invulnerable: any) => {
-            if(invulnerable == alice.address || invulnerable == bob.address) return new Promise((res) => res);
-            return helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++});
-          }));
-        }
+        expect(invulnerables.length, 'Invalid initial invulnerables number').to.be.equal(4);
+        expect(invulnerables, 'Invalid initial invulnerables').containSubset([alphaNode, betaNode, gammaNode, deltaNode]);
       });
     });
 
     itSub('Change invulnerables and make sure they start producing blocks', async ({helper}) => {
       let nonce = await helper.chain.getNonce(superuser.address);
-      await expect(Promise.all([
-        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [charlie.address], true, {nonce: nonce++}),
-        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [dave.address], true, {nonce: nonce++}),
-      ])).to.be.fulfilled;
 
       nonce = await helper.chain.getNonce(superuser.address);
       await expect(Promise.all([
-        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alice.address], true, {nonce: nonce++}),
-        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [bob.address], true, {nonce: nonce++}),
+        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alphaNode], true, {nonce: nonce++}),
+        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [betaNode], true, {nonce: nonce++}),
       ])).to.be.fulfilled;
 
       const newInvulnerables = await helper.collatorSelection.getInvulnerables();
-      expect(newInvulnerables).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);
+      expect(newInvulnerables).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);
 
       await helper.wait.newSessions(2);
 
       const newValidators = await helper.callRpc('api.query.session.validators');
-      expect(newValidators).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);
+      expect(newValidators).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);
 
       const lastBlockNumber = await helper.chain.getLatestBlockNumber();
       await helper.wait.newBlocks(1);
-      const lastCharlieBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [charlie.address])).toNumber();
-      const lastDaveBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [dave.address])).toNumber();
-      expect(lastCharlieBlock >= lastBlockNumber || lastDaveBlock >= lastBlockNumber).to.be.true;
+      const lastGammaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [gammaNode])).toNumber();
+      const lastDeltaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [deltaNode])).toNumber();
+      expect(lastGammaBlock >= lastBlockNumber || lastDeltaBlock >= lastBlockNumber).to.be.true;
     });
 
     after(async () => {
-      await usingPlaygrounds(async (helper) => {
-        if(await helper.arrange.isDevNode()) return;
-
-        let nonce = await helper.chain.getNonce(superuser.address);
-        await Promise.all([
-          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),
-          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),
-        ]);
-
-        nonce = await helper.chain.getNonce(superuser.address);
-        await Promise.all([
-          await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [charlie.address], true, {nonce: nonce++}),
-          await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [dave.address], true, {nonce: nonce++}),
-        ]);
-      });
+      await resetInvulnerables();
     });
   });
 
   describe('Getting and releasing licenses to collate', () => {
-    let charlie: IKeyringPair;
-    let dave: IKeyringPair;
     let crowd: IKeyringPair[];
 
     before(async function() {
       await usingPlaygrounds(async (helper, privateKey) => {
-        charlie = await privateKey('//Charlie');
-        dave = await privateKey('//Dave');
         crowd = await helper.arrange.createCrowd(20, 100n, superuser);
 
         // set session keys for everyone
-        expect((await helper.session.setOwnKeysFromAddress(charlie))
-          .status.toLowerCase()).to.be.equal('success');
-        expect((await helper.session.setOwnKeysFromAddress(dave))
-          .status.toLowerCase()).to.be.equal('success');
         await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));
       });
     });
@@ -252,22 +216,13 @@
   });
 
   describe('Onboarding, collating, and offboarding as collator candidates', () => {
-    // These two are the default invulnerables, and should return to be invulnerables after this suite.
-    let charlie: IKeyringPair;
-    let dave: IKeyringPair;
     let crowd: IKeyringPair[];
 
     before(async function() {
       await usingPlaygrounds(async (helper, privateKey) => {
-        charlie = await privateKey('//Charlie');
-        dave = await privateKey('//Dave');
         crowd = await helper.arrange.createCrowd(20, 100n, superuser);
 
         // set session keys for everyone
-        expect((await helper.session.setOwnKeysFromAddress(charlie))
-          .status.toLowerCase()).to.be.equal('success');
-        expect((await helper.session.setOwnKeysFromAddress(dave))
-          .status.toLowerCase()).to.be.equal('success');
         await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));
       });
     });
@@ -341,10 +296,6 @@
   });
 
   describe('Addition and removal of invulnerables', () => {
-    before(async function() {
-      await resetInvulnerables();
-    });
-
     describe('Positive', () => {
       itSub('Adds an invulnerable', async ({helper}) => {
         const [account] = await helper.arrange.createAccounts([10n], superuser);
@@ -409,7 +360,7 @@
         // 28 non-functioning collators, teehee.
 
         const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;
-        const invulnerablesUntilLimit = helper.collatorSelection.maxCollators() - invulnerablesLength;
+        const invulnerablesUntilLimit = (await helper.collatorSelection.getDesiredCollators()) - invulnerablesLength;
         const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);
         const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);
 
@@ -448,6 +399,10 @@
           .to.be.rejectedWith(/BadOrigin/);
         expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);
       });
+
+      after(async function() {
+        await resetInvulnerables();
+      });
     });
   });