difftreelog
test(collator-selection) intermediate changes and fixes to tests + minor refactor
in: master
6 files changed
pallets/collator-selection/src/lib.rsdiffbeforeafterboth--- a/pallets/collator-selection/src/lib.rs
+++ b/pallets/collator-selection/src/lib.rs
@@ -555,7 +555,7 @@
T::Currency::resolve_creating(&T::TreasuryAccountId::get(), imbalance);
- // Self::deposit_event(Event::CandidateSlashed(who.clone()));
+ // Self::deposit_event(Event::CandidateSlashed(who.clone()));
} else {
//T::Currency::unreserve(who, deposit);
deposit_returned = deposit;
pallets/collator-selection/src/tests.rsdiffbeforeafterboth--- a/pallets/collator-selection/src/tests.rs
+++ b/pallets/collator-selection/src/tests.rs
@@ -50,28 +50,32 @@
});
}
+// todo:collator add more tests later
+
#[test]
-fn it_should_set_invulnerables() {
+fn it_should_add_invulnerables() {
new_test_ext().execute_with(|| {
- let new_set = vec![1, 2, 3, 4];
- assert_ok!(CollatorSelection::set_invulnerables(
+ assert_ok!(CollatorSelection::add_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
- new_set.clone()
+ 1
));
- assert_eq!(CollatorSelection::invulnerables(), new_set);
+ assert_ok!(CollatorSelection::add_invulnerable(
+ RuntimeOrigin::signed(RootAccount::get()),
+ 2
+ ));
+ assert_eq!(CollatorSelection::invulnerables(), vec![1, 2]);
// cannot set with non-root.
assert_noop!(
- CollatorSelection::set_invulnerables(RuntimeOrigin::signed(1), new_set.clone()),
+ CollatorSelection::add_invulnerable(RuntimeOrigin::signed(1), 3),
BadOrigin
);
// cannot set invulnerables without associated validator keys
- let invulnerables = vec![7];
assert_noop!(
- CollatorSelection::set_invulnerables(
+ CollatorSelection::add_invulnerable(
RuntimeOrigin::signed(RootAccount::get()),
- invulnerables.clone()
+ 7
),
Error::<Test>::ValidatorNotRegistered
);
@@ -79,6 +83,41 @@
}
#[test]
+fn it_should_remove_invulnerables() {
+ new_test_ext().execute_with(|| {
+ assert_ok!(CollatorSelection::add_invulnerable(
+ RuntimeOrigin::signed(RootAccount::get()),
+ 1
+ ));
+ assert_ok!(CollatorSelection::add_invulnerable(
+ RuntimeOrigin::signed(RootAccount::get()),
+ 2
+ ));
+
+ // cannot remove with non-root.
+ assert_noop!(
+ CollatorSelection::remove_invulnerable(RuntimeOrigin::signed(1), 3),
+ BadOrigin
+ );
+
+ assert_ok!(CollatorSelection::remove_invulnerable(
+ RuntimeOrigin::signed(RootAccount::get()),
+ 2
+ ));
+ assert_eq!(CollatorSelection::invulnerables(), vec![1]);
+
+ // cannot remove an invulnerable if there would be 0 invulnerables.
+ assert_noop!(
+ CollatorSelection::add_invulnerable(
+ RuntimeOrigin::signed(RootAccount::get()),
+ 1
+ ),
+ Error::<Test>::NotInvulnerable
+ );
+ });
+}
+
+#[test]
fn set_desired_candidates_works() {
new_test_ext().execute_with(|| {
// given
@@ -404,6 +443,7 @@
deposit: 10,
};
assert_eq!(CollatorSelection::candidates(), vec![collator]);
+ assert_eq!(CollatorSelection::kick_threshold(), 1);
assert_eq!(CollatorSelection::last_authored_block(4), 20);
initialize_to_block(30);
// 3 gets kicked after 1 session delay
@@ -457,6 +497,7 @@
let collator_selection = collator_selection::GenesisConfig::<Test> {
desired_candidates: 2,
candidacy_bond: 10,
+ kick_threshold: 1,
invulnerables,
};
// collator selection must be initialized before session.
primitives/common/src/constants.rsdiffbeforeafterboth--- a/primitives/common/src/constants.rs
+++ b/primitives/common/src/constants.rs
@@ -47,7 +47,7 @@
/// Amount of Balance reserved for candidate registration.
pub const GENESIS_CANDIDACY_BOND: u128 = EXISTENTIAL_DEPOSIT;
/// How long a periodic session lasts in blocks.
-pub const SESSION_LENGTH: BlockNumber = MINUTES;
+pub const SESSION_LENGTH: BlockNumber = HOURS;
// Targeting 0.1 UNQ per transfer
pub const WEIGHT_TO_FEE_COEFF: u32 = /*<weight2fee>*/175_199_920/*</weight2fee>*/;
tests/package.jsondiffbeforeafterboth1{2 "name": "unique-tests",3 "version": "1.0.0",4 "description": "Unique Chain Tests",5 "main": "",6 "devDependencies": {7 "@polkadot/typegen": "9.9.4",8 "@types/chai": "^4.3.3",9 "@types/chai-as-promised": "^7.1.5",10 "@types/chai-like": "^1.1.1",11 "@types/mocha": "^10.0.0",12 "@types/node": "^18.11.2",13 "@typescript-eslint/eslint-plugin": "^5.40.1",14 "@typescript-eslint/parser": "^5.40.1",15 "chai": "^4.3.6",16 "eslint": "^8.25.0",17 "eslint-plugin-mocha": "^10.1.0",18 "mocha": "^10.1.0",19 "ts-node": "^10.9.1",20 "typescript": "^4.8.4"21 },22 "mocha": {23 "timeout": 9999999,24 "require": [25 "ts-node/register"26 ]27 },28 "scripts": {29 "lint": "eslint --ext .ts,.js src/",30 "fix": "eslint --ext .ts,.js src/ --fix",31 "setup": "ts-node ./src/util/globalSetup.ts",32 "test": "yarn setup && mocha --timeout 9999999 -r ts-node/register './src/**/*.*test.ts'",33 "testParallelFull": "yarn testParallel && yarn testSequential",34 "testParallel": "yarn setup && mocha --parallel --timeout 9999999 -r ts-node/register './src/**/*.test.ts'",35 "testSequential": "yarn setup && mocha --timeout 9999999 -r ts-node/register './src/**/*.seqtest.ts'",36 "testStructure": "yarn setup && mocha --timeout 9999999 -r ts-node/register ./**/nesting/*.*test.ts",37 "testEth": "yarn setup && mocha --timeout 9999999 -r ts-node/register './**/eth/**/*.*test.ts'",38 "testEthNesting": "yarn setup && mocha --timeout 9999999 -r ts-node/register './**/eth/nesting/**/*.*test.ts'",39 "testEthFractionalizer": "yarn setup && mocha --timeout 9999999 -r ts-node/register './**/eth/fractionalizer/**/*.*test.ts'",40 "testEthMarketplace": "yarn setup && mocha --timeout 9999999 -r ts-node/register './**/eth/marketplace/**/*.*test.ts'",41 "testEvent": "yarn setup && mocha --timeout 9999999 -r ts-node/register ./src/check-event/*.*test.ts",42 "testRmrk": "yarn setup && mocha --timeout 9999999 -r ts-node/register ./**/rmrk/*.*test.ts",43 "testEthPayable": "mocha --timeout 9999999 -r ts-node/register './**/eth/payable.test.ts'",44 "testEvmCoder": "mocha --timeout 9999999 -r ts-node/register './**/eth/evmCoder.test.ts'",45 "testNesting": "mocha --timeout 9999999 -r ts-node/register ./**/nest.test.ts",46 "testUnnesting": "mocha --timeout 9999999 -r ts-node/register ./**/unnest.test.ts",47 "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.*test.ts ./**/tokenProperties.*test.ts ./**/getPropertiesRpc.test.ts",48 "testCollectionProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.*test.ts",49 "testTokenProperties": "mocha --timeout 9999999 -r ts-node/register ./**/tokenProperties.*test.ts",50 "testMigration": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts",51 "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",52 "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts",53 "testChangeCollectionOwner": "mocha --timeout 9999999 -r ts-node/register ./**/change-collection-owner.test.ts",54 "testSetCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionSponsor.test.ts",55 "testConfirmSponsorship": "mocha --timeout 9999999 --parallel -r ts-node/register ./**/confirmSponsorship.test.ts",56 "testRemoveCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionAdmin.test.ts",57 "testRemoveCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionSponsor.test.ts",58 "testAllowLists": "mocha --timeout 9999999 -r ts-node/register ./**/allowLists.test.ts",59 "testConnection": "mocha --timeout 9999999 -r ts-node/register ./**/connection.test.ts",60 "testContracts": "mocha --timeout 9999999 -r ts-node/register ./**/contracts.test.ts",61 "testCreateItem": "mocha --timeout 9999999 -r ts-node/register ./**/createItem.test.ts",62 "testCreateMultipleItems": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItems.test.ts",63 "testCreateMultipleItemsEx": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItemsEx.test.ts",64 "testApprove": "mocha --timeout 9999999 -r ts-node/register ./**/approve.test.ts",65 "testTransferFrom": "mocha --timeout 9999999 -r ts-node/register ./**/transferFrom.test.ts",66 "testCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts",67 "testDestroyCollection": "mocha --timeout 9999999 -r ts-node/register ./**/destroyCollection.test.ts",68 "testToggleContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/toggleContractAllowList.test.ts",69 "testAddToContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/addToContractAllowList.test.ts",70 "testTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/transfer.test.ts",71 "testBurnItem": "mocha --timeout 9999999 -r ts-node/register ./**/burnItem.test.ts",72 "testAdminTransferAndBurn": "mocha --timeout 9999999 -r ts-node/register ./**/adminTransferAndBurn.test.ts",73 "testSetPermissions": "mocha --timeout 9999999 -r ts-node/register ./**/setPermissions.test.ts",74 "testCreditFeesToTreasury": "mocha --timeout 9999999 -r ts-node/register ./**/creditFeesToTreasury.seqtest.ts",75 "testContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/eth/contractSponsoring.test.ts",76 "testEnableContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/enableContractSponsoring.test.ts",77 "testRemoveFromContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/removeFromContractAllowList.test.ts",78 "testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts",79 "testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts",80 "testNextSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/nextSponsoring.test.ts",81 "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",82 "testMaintenance": "mocha --timeout 9999999 -r ts-node/register ./**/maintenanceMode.seqtest.ts",83 "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.seqtest.ts",84 "testScheduler": "mocha --timeout 9999999 -r ts-node/register ./**/scheduler.seqtest.ts",85 "testSchedulingEVM": "mocha --timeout 9999999 -r ts-node/register ./**/eth/scheduling.test.ts",86 "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",87 "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",88 "testCollatorSelection": "mocha --timeout 9999999 -r ts-node/register ./**/collatorSelection.test.ts",89 "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",90 "testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",91 "testEthCreateNFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createNFTCollection.test.ts",92 "testEthCreateRFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createRFTCollection.test.ts",93 "testEthNFT": "mocha --timeout 9999999 -r ts-node/register ./**/eth/nonFungible.test.ts",94 "testRFT": "mocha --timeout 9999999 -r ts-node/register ./**/refungible.test.ts",95 "testEthRFT": "mocha --timeout 9999999 -r ts-node/register ./**/eth/reFungible.test.ts ./**/eth/reFungibleToken.test.ts",96 "testFT": "mocha --timeout 9999999 -r ts-node/register ./**/fungible.test.ts",97 "testEthFT": "mocha --timeout 9999999 -r ts-node/register ./**/eth/fungible.test.ts",98 "testRPC": "mocha --timeout 9999999 -r ts-node/register ./**/rpc.test.ts",99 "testPromotion": "yarn setup && mocha --timeout 9999999 -r ts-node/register ./**/app-promotion.*test.ts",100 "testXcmUnique": "RUN_XCM_TESTS=1 mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmUnique.test.ts",101 "testXcmQuartz": "RUN_XCM_TESTS=1 mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmQuartz.test.ts",102 "testXcmOpal": "RUN_XCM_TESTS=1 mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmOpal.test.ts",103 "testXcmTransferAcala": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferAcala.test.ts acalaId=2000 uniqueId=5000",104 "testXcmTransferStatemine": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferStatemine.test.ts statemineId=1000 uniqueId=5000",105 "testXcmTransferMoonbeam": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferMoonbeam.test.ts",106 "benchMintingFee": "ts-node src/benchmarks/mintFee/benchmark.ts",107 "testApiConsts": "mocha --timeout 9999999 -r ts-node/register ./**/apiConsts.test.ts",108 "load": "mocha --timeout 9999999 -r ts-node/register './**/*.load.ts'",109 "loadTransfer": "ts-node src/transfer.nload.ts",110 "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",111 "polkadot-types-from-defs": "ts-node ./node_modules/.bin/polkadot-types-from-defs --endpoint src/interfaces/metadata.json --input src/interfaces/ --package .",112 "polkadot-types-from-chain": "ts-node ./node_modules/.bin/polkadot-types-from-chain --endpoint src/interfaces/metadata.json --output src/interfaces/ --package .",113 "polkadot-types": "echo \"export default {}\" > src/interfaces/lookup.ts && yarn polkadot-types-fetch-metadata && yarn polkadot-types-from-defs && yarn polkadot-types-from-defs && yarn polkadot-types-from-chain"114 },115 "author": "",116 "license": "SEE LICENSE IN ../LICENSE",117 "homepage": "",118 "dependencies": {119 "@polkadot/api": "9.9.4",120 "@polkadot/util-crypto": "10.2.1",121 "chai-as-promised": "^7.1.1",122 "chai-like": "^1.1.1",123 "csv-writer": "^1.6.0",124 "find-process": "^1.4.7",125 "solc": "0.8.17",126 "web3": "^1.8.0"127 }128}tests/src/collatorSelection.seqtest.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/collatorSelection.seqtest.ts
@@ -0,0 +1,267 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from './util';
+
+async function resetInvulnerables() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const superuser = await privateKey('//Alice');
+ const alice = await privateKey('//Alice');
+ const bob = await privateKey('//Bob');
+ 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);
+ 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(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++});
+ }));
+ }
+ });
+}
+
+// todo:collator Most preferable to launch this test in parallel somehow -- or change the session period (1 hr).
+// + 18 tests: 5 (1+4) on session change
+describe('Integration Test: Collator Selection', () => {
+ let superuser: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ requirePalletsOrSkip(this, helper, [Pallets.CollatorSelection]);
+ superuser = await privateKey('//Alice');
+ });
+ });
+
+ 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 charlie: IKeyringPair;
+ let dave: IKeyringPair;
+
+ before(async function() {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ alice = await privateKey('//Alice');
+ bob = await privateKey('//Bob');
+ charlie = await privateKey('//Charlie');
+ dave = await privateKey('//Dave');
+
+ expect((await helper.collatorSelection.setOwnKeys(charlie))
+ .status.toLowerCase()).to.be.equal('success');
+ expect((await helper.collatorSelection.setOwnKeys(dave))
+ .status.toLowerCase()).to.be.equal('success');
+
+ // todo:collator check necessity + add RPC for invulnerables / just improve in general
+ // validators = await helper.callRpc('api.query.session.validators');
+ 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++});
+ }));
+ }
+ });
+ });
+
+ 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++}),
+ ])).to.be.fulfilled;
+
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ expect(newInvulnerables).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);
+
+ const expectedSessionIndex = (await helper.callRpc('api.query.session.currentIndex')).toNumber() + 2;
+ let currentSessionIndex = -1;
+ console.log('Waiting for the session after the next.'
+ + ' This might take a while -- check SessionPeriod in pallet_session::Config for session time.');
+
+ while (currentSessionIndex < expectedSessionIndex) {
+ // eslint-disable-next-line no-async-promise-executor
+ currentSessionIndex = await expect(helper.wait.withTimeout(new Promise(async (resolve) => {
+ await helper.wait.newBlocks(1);
+ const res = (await helper.callRpc('api.query.session.currentIndex')).toNumber();
+ resolve(res);
+ }), 24000, 'The chain has stopped producing blocks!')).to.be.fulfilled;
+ }
+
+ const newValidators = await helper.callRpc('api.query.session.validators');
+ expect(newValidators).to.contain(charlie.address).and.contain(dave.address).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;
+ });
+
+ // todo:collator keyless invulnerables? will hang, so, a breaking test, eh
+ // register candidate without sudos and the like
+
+ after(async () => {
+ await usingPlaygrounds(async (helper) => {
+ if (helper.fetchMissingPalletNames([Pallets.CollatorSelection]).length != 0) 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++}),
+ ]);
+ });
+ });
+ });
+
+ // todo:collator make sure that there is enough session time for a set of tests
+ // 28 non-functioning collators, teehee.
+
+ describe.skip('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);
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+
+ await helper.collatorSelection.setOwnKeys(account);
+ await helper.getSudo().collatorSelection.addInvulnerable(superuser, account.address);
+
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ expect(invulnerables.concat(account.address)).to.have.all.members(newInvulnerables);
+ });
+
+ itSub('Removes an invulnerable', async ({helper}) => {
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+ const lastInvulnerable = invulnerables.pop();
+
+ await helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable);
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ // invulnerables had its last element removed, so they should be equal
+ expect(newInvulnerables).to.have.all.members(invulnerables);
+ });
+ });
+
+ describe('Negative', () => {
+ itSub('Does not duplicate an invulnerable', async ({helper}) => {
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+ // adding an already invulnerable should not fail, but should not duplicate it either
+ await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, invulnerables[0]))
+ .to.be.fulfilled;
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ expect(newInvulnerables).to.have.all.members(invulnerables);
+ });
+
+ itSub('Cannot allow invulnerables to be empty', async ({helper}) => {
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+ const lastInvulnerable = invulnerables.pop();
+
+ let nonce = await helper.chain.getNonce(superuser.address);
+ await Promise.all(invulnerables.map((i: any) =>
+ helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i], true, {nonce: nonce++})));
+
+ await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable))
+ .to.be.rejected;//todo:collator With(/collatorSelection.TooFewInvulnerables/);
+
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ expect(newInvulnerables).to.be.deep.equal([lastInvulnerable]);
+
+ // restore the invulnerables to the previous state
+ nonce = await helper.chain.getNonce(superuser.address);
+ await Promise.all(invulnerables.map((i: any) =>
+ helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i], true, {nonce: nonce++})));
+ });
+
+ itSub('Cannot have too many invulnerables', async ({helper}) => {
+ const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;
+ const invulnerablesUntilLimit = 30 - invulnerablesLength;
+ const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);
+ const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);
+
+ await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
+ helper.collatorSelection.setOwnKeys(i)));
+ await helper.collatorSelection.setOwnKeys(lastInvulnerable);
+
+ let nonce = await helper.chain.getNonce(superuser.address);
+ await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
+ helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i.address], true, {nonce: nonce++})));
+
+ await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, lastInvulnerable.address))
+ .to.be.rejected; // todo:collator With(/collatorSelection.TooManyInvulnerables/);
+
+ // restore the invulnerables to the previous state
+ nonce = await helper.chain.getNonce(superuser.address);
+ await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
+ helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i.address], true, {nonce: nonce++})));
+ });
+
+ itSub('Forbids a non-sudo to add an invulnerable', async ({helper}) => {
+ const [account] = await helper.arrange.createAccounts([10n], superuser);
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+
+ await helper.collatorSelection.setOwnKeys(account);
+ await expect(helper.collatorSelection.addInvulnerable(superuser, account.address))
+ .to.be.rejectedWith(/BadOrigin/);
+
+ const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+ expect(newInvulnerables).to.be.members(invulnerables);
+ });
+
+ itSub('Forbids a non-sudo to remove an invulnerable', async ({helper}) => {
+ const invulnerables = await helper.collatorSelection.getInvulnerables();
+ await expect(helper.collatorSelection.removeInvulnerable(superuser, invulnerables[0]))
+ .to.be.rejectedWith(/BadOrigin/);
+ expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);
+ });
+ });
+
+ // todo:collator after
+ });
+});
\ No newline at end of file
tests/src/collatorSelection.test.tsdiffbeforeafterboth--- a/tests/src/collatorSelection.test.ts
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from './util';
-
-async function resetInvulnerables() {
- await usingPlaygrounds(async (helper, privateKey) => {
- const superuser = await privateKey('//Alice');
- const alice = await privateKey('//Alice');
- const bob = await privateKey('//Bob');
- 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);
- 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(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++});
- }));
- }
- });
-}
-
-// todo:collator Most preferable to launch this test in parallel somehow -- or change the session period (1 hr).
-// + 18 tests: 5 (1+4) on session change
-describe('Integration Test: Collator Selection', () => {
- let superuser: IKeyringPair;
-
- // These are the default invulnerables, and should return to be invulnerables after this suite.
- let alice: IKeyringPair;
- let bob: IKeyringPair;
-
- let charlie: IKeyringPair;
- let dave: IKeyringPair;
- //let eve: IKeyringPair;
-
- before(async function() {
- await usingPlaygrounds(async (helper, privateKey) => {
- requirePalletsOrSkip(this, helper, [Pallets.CollatorSelection]);
-
- //todo:collator
- //const donor = await privateKey({filename: __filename});
- //[charlie, dave] = await helper.arrange.createAccounts([100n, 100n], donor);
- alice = await privateKey('//Alice');
- bob = await privateKey('//Bob');
- charlie = await privateKey('//Charlie');
- dave = await privateKey('//Dave');
-
- superuser = await privateKey('//Alice');
- });
- });
-
- describe('Dynamic shuffling of collators', () => {
- before(async function() {
- await usingPlaygrounds(async (helper) => {
- expect((await helper.collatorSelection.setOwnKeys(charlie))
- .status.toLowerCase()).to.be.equal('success');
- expect((await helper.collatorSelection.setOwnKeys(dave))
- .status.toLowerCase()).to.be.equal('success');
-
- // todo:collator check necessity + add RPC for invulnerables / just improve in general
- // validators = await helper.callRpc('api.query.session.validators');
- const invulnerables = await helper.callRpc('api.query.collatorSelection.invulnerables');
- 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);
-
- await Promise.all([
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: 0}),
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: 1}),
- ]);
-
- let nonce = 0;
- 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++});
- }));
- }
- });
- });
-
- itSub('Change invulnerables and make sure they start producing blocks', async ({helper}) => {
- await expect(Promise.all([
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [charlie.address], true, {nonce: 0}),
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [dave.address], true, {nonce: 1}),
- ])).to.be.fulfilled;
-
- await expect(Promise.all([
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alice.address], true, {nonce: 0}),
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [bob.address], true, {nonce: 1}),
- ])).to.be.fulfilled;
-
- const newInvulnerables = await helper.callRpc('api.query.collatorSelection.invulnerables');
- expect(newInvulnerables).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);
-
- const expectedSessionIndex = (await helper.callRpc('api.query.session.currentIndex')).toNumber() + 2;
- let currentSessionIndex = -1;
- console.log('Waiting for the session after the next.'
- + ' This might take a while -- check SessionPeriod in pallet_session::Config for session time.');
-
- while (currentSessionIndex < expectedSessionIndex) {
- // eslint-disable-next-line no-async-promise-executor
- currentSessionIndex = await expect(helper.wait.withTimeout(new Promise(async (resolve) => {
- //todo:collator
- console.log('starting wait...');
- console.time('ein');
- await helper.wait.newBlocks(1);
- console.timeLog('ein');
- const res = (await helper.callRpc('api.query.session.currentIndex')).toNumber();
- console.timeEnd('ein');
- resolve(res);
- }), 24000, 'The chain has stopped producing blocks!')).to.be.fulfilled;
- }
-
- const newValidators = await helper.callRpc('api.query.session.validators');
- expect(newValidators).to.contain(charlie.address).and.contain(dave.address).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;
- });
-
- // todo:collator keyless invulnerables? will hang, so, a breaking test, eh
- // register candidate without sudos and the like
-
- after(async () => {
- await usingPlaygrounds(async (helper) => {
- if (helper.fetchMissingPalletNames([Pallets.CollatorSelection]).length != 0) return;
-
- await Promise.all([
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: 0}),
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: 1}),
- ]);
-
- await Promise.all([
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [charlie.address], true, {nonce: 0}),
- await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [dave.address], true, {nonce: 1}),
- ]);
- });
- });
- });
-
- // todo:collator make sure that there is enough session time for a set of tests
- // 28 non-functioning collators, teehee.
-
- 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);
- const invulnerables = await helper.collatorSelection.getInvulnerables();
-
- await helper.collatorSelection.setOwnKeys(account);
- await helper.getSudo().collatorSelection.addInvulnerable(superuser, account.address);
-
- const newInvulnerables = await helper.collatorSelection.getInvulnerables();
- expect(invulnerables.concat(account.address)).to.have.all.members(newInvulnerables);
- });
-
- itSub('Removes an invulnerable', async ({helper}) => {
- const invulnerables = await helper.collatorSelection.getInvulnerables();
- const lastInvulnerable = invulnerables.pop();
-
- await helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable);
- const newInvulnerables = await helper.collatorSelection.getInvulnerables();
- // invulnerables had its last element removed, so they should be equal
- expect(newInvulnerables).to.have.all.members(invulnerables);
- });
- });
-
- describe('Negative', () => {
- itSub('Does not duplicate an invulnerable', async ({helper}) => {
- const invulnerables = await helper.collatorSelection.getInvulnerables();
- // adding an already invulnerable should not fail, but should not duplicate it either
- await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, invulnerables[0]))
- .to.be.fulfilled;
- const newInvulnerables = await helper.collatorSelection.getInvulnerables();
- expect(newInvulnerables).to.have.all.members(invulnerables);
- });
-
- itSub('Cannot allow invulnerables to be empty', async ({helper}) => {
- const invulnerables = await helper.collatorSelection.getInvulnerables();
- const lastInvulnerable = invulnerables.pop();
-
- let nonce = await helper.chain.getNonce(superuser.address);
- await Promise.all(invulnerables.map((i: any) =>
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i], true, {nonce: nonce++})));
-
- await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable))
- .to.be.rejected;//todo:collator With(/collatorSelection.TooFewInvulnerables/);
-
- const newInvulnerables = await helper.collatorSelection.getInvulnerables();
- expect(newInvulnerables).to.be.deep.equal([lastInvulnerable]);
-
- // restore the invulnerables to the previous state
- nonce = await helper.chain.getNonce(superuser.address);
- await Promise.all(invulnerables.map((i: any) =>
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i], true, {nonce: nonce++})));
- });
-
- itSub('Cannot have too many invulnerables', async ({helper}) => {
- const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;
- const invulnerablesUntilLimit = 30 - invulnerablesLength;
- const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);
- const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);
-
- await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
- helper.collatorSelection.setOwnKeys(i)));
- await helper.collatorSelection.setOwnKeys(lastInvulnerable);
-
- let nonce = await helper.chain.getNonce(superuser.address);
- await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i.address], true, {nonce: nonce++})));
-
- await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, lastInvulnerable.address))
- .to.be.rejected; // todo:collator With(/collatorSelection.TooManyInvulnerables/);
-
- // restore the invulnerables to the previous state
- nonce = await helper.chain.getNonce(superuser.address);
- await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
- helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i.address], true, {nonce: nonce++})));
- });
-
- itSub('Forbids a non-sudo to add an invulnerable', async ({helper}) => {
- const [account] = await helper.arrange.createAccounts([10n], bob);
- const invulnerables = await helper.collatorSelection.getInvulnerables();
-
- await helper.collatorSelection.setOwnKeys(account);
- await expect(helper.collatorSelection.addInvulnerable(bob, account.address))
- .to.be.rejectedWith(/BadOrigin/);
-
- const newInvulnerables = await helper.collatorSelection.getInvulnerables();
- expect(newInvulnerables).to.be.members(invulnerables);
- });
-
- itSub('Forbids a non-sudo to remove an invulnerable', async ({helper}) => {
- const invulnerables = await helper.collatorSelection.getInvulnerables();
- await expect(helper.collatorSelection.removeInvulnerable(superuser, invulnerables[0]))
- .to.be.rejectedWith(/BadOrigin/);
- expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);
- });
- });
-
- // todo:collator after
- });
-});
\ No newline at end of file