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
before · runtime/common/config/pallets/mod.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617use alloc::string::{String, ToString};18use frame_support::parameter_types;19use sp_runtime::traits::AccountIdConversion;20use crate::{21	runtime_common::{22		dispatch::CollectionDispatchT,23		config::{substrate::TreasuryModuleId, ethereum::EvmCollectionHelpersAddress},24		weights::CommonWeights,25		RelayChainBlockNumberProvider,26	},27	Runtime, RuntimeEvent, RuntimeCall, VERSION, TOKEN_SYMBOL, DECIMALS, Balances,28};29use frame_support::traits::{ConstU32, ConstU64, Currency};30use up_common::{31	types::{AccountId, Balance, BlockNumber},32	constants::*,33};34use up_data_structs::{35	mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},36};37use sp_arithmetic::Perbill;3839#[cfg(feature = "governance")]40use crate::runtime_common::config::governance;4142#[cfg(feature = "unique-scheduler")]43pub mod scheduler;4445#[cfg(feature = "foreign-assets")]46pub mod foreign_asset;4748#[cfg(feature = "app-promotion")]49pub mod app_promotion;5051#[cfg(feature = "collator-selection")]52pub mod collator_selection;5354#[cfg(feature = "preimage")]55pub mod preimage;5657parameter_types! {58	pub const CollectionCreationPrice: Balance = 2 * UNIQUE;59	pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account_truncating();60}6162impl pallet_common::Config for Runtime {63	type WeightInfo = pallet_common::weights::SubstrateWeight<Self>;64	type RuntimeEvent = RuntimeEvent;65	type Currency = Balances;66	type CollectionCreationPrice = CollectionCreationPrice;67	type TreasuryAccountId = TreasuryAccountId;68	type CollectionDispatch = CollectionDispatchT<Self>;6970	type EvmTokenAddressMapping = EvmTokenAddressMapping;71	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;72	type ContractAddress = EvmCollectionHelpersAddress;73}7475impl pallet_structure::Config for Runtime {76	type RuntimeEvent = RuntimeEvent;77	type RuntimeCall = RuntimeCall;78	type WeightInfo = pallet_structure::weights::SubstrateWeight<Self>;79}8081impl pallet_fungible::Config for Runtime {82	type WeightInfo = pallet_fungible::weights::SubstrateWeight<Self>;83}84impl pallet_refungible::Config for Runtime {85	type WeightInfo = pallet_refungible::weights::SubstrateWeight<Self>;86}87impl pallet_nonfungible::Config for Runtime {88	type WeightInfo = pallet_nonfungible::weights::SubstrateWeight<Self>;89}9091parameter_types! {92	pub const Decimals: u8 = DECIMALS;93	pub Name: String = String::from_utf8_lossy(VERSION.impl_name.as_ref()).to_string();94	pub Symbol: String = TOKEN_SYMBOL.to_string();95}96impl pallet_balances_adapter::Config for Runtime {97	type Inspect = Balances;98	type Mutate = Balances;99	type CurrencyBalance = <Balances as Currency<Self::AccountId>>::Balance;100	type Decimals = Decimals;101	type Name = Name;102	type Symbol = Symbol;103	type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;104}105106parameter_types! {107	pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied108}109110/// Used for the pallet inflation111impl pallet_inflation::Config for Runtime {112	type Currency = Balances;113	type TreasuryAccountId = TreasuryAccountId;114	type InflationBlockInterval = InflationBlockInterval;115	type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;116}117118impl pallet_unique::Config for Runtime {119	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;120	type CommonWeightInfo = CommonWeights<Self>;121	type RefungibleExtensionsWeightInfo = CommonWeights<Self>;122}123124parameter_types! {125	pub AppPromotionDailyRate: Perbill = Perbill::from_rational(5u32, 10_000);126	pub const MaxCollators: u32 = MAX_COLLATORS;127	pub const LicenseBond: Balance = GENESIS_LICENSE_BOND;128	pub const SessionPeriod: BlockNumber = SESSION_LENGTH;129	pub const DayRelayBlocks: BlockNumber = RELAY_DAYS;130}131132impl pallet_configuration::Config for Runtime {133	type RuntimeEvent = RuntimeEvent;134	type Balance = Balance;135	type DefaultWeightToFeeCoefficient = ConstU64<{ up_common::constants::WEIGHT_TO_FEE_COEFF }>;136	type DefaultMinGasPrice = ConstU64<{ up_common::constants::MIN_GAS_PRICE }>;137	type DefaultCollatorSelectionMaxCollators = MaxCollators;138	type DefaultCollatorSelectionKickThreshold = SessionPeriod;139	type DefaultCollatorSelectionLicenseBond = LicenseBond;140	type MaxXcmAllowedLocations = ConstU32<16>;141	type AppPromotionDailyRate = AppPromotionDailyRate;142	type DayRelayBlocks = DayRelayBlocks;143	type WeightInfo = pallet_configuration::weights::SubstrateWeight<Self>;144}145146impl pallet_maintenance::Config for Runtime {147	type RuntimeEvent = RuntimeEvent;148149	type RuntimeCall = RuntimeCall;150151	#[cfg(feature = "governance")]152	type ManagerOrigin = governance::RootOrTechnicalCommitteeMember;153154	#[cfg(not(feature = "governance"))]155	type ManagerOrigin = frame_system::EnsureRoot<AccountId>;156157	type PreimageOrigin = frame_system::EnsureRoot<AccountId>;158159	#[cfg(feature = "preimage")]160	type Preimages = crate::Preimage;161	#[cfg(not(feature = "preimage"))]162	type Preimages = ();163	type WeightInfo = pallet_maintenance::weights::SubstrateWeight<Self>;164}
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
--- a/runtime/quartz/Cargo.toml
+++ b/runtime/quartz/Cargo.toml
@@ -218,6 +218,7 @@
 refungible = []
 unique-scheduler = []
 gov-test-timings = []
+session-test-timings = []
 
 ################################################################################
 # local dependencies
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();
+      });
     });
   });