difftreelog
Merge pull request #988 from UniqueNetwork/fix/collector-selection-tests-release-60
in: master
9 files changed
.baedeker/collator-selection.jsonnetdiffbeforeafterboth31 bin: $.bin,31 bin: $.bin,32 wantedKeys: 'para',32 wantedKeys: 'para',33 },33 },34 for name in ['alice', 'bob']34 for name in ['alpha', 'beta', 'gamma', 'delta']35 },35 },36};36};3737.docker/docker-compose.gov.j2diffbeforeafterboth21 options:21 options:22 max-size: "1m"22 max-size: "1m"23 max-file: "3"23 max-file: "3"24 command: cargo run --release --features={{ NETWORK }}-runtime,{{ WASM_NAME }}-runtime/gov-test-timings -- --dev -linfo --rpc-cors=all --unsafe-rpc-external24 command: cargo run --release --features={{ NETWORK }}-runtime,gov-test-timings -- --dev -linfo --rpc-cors=all --unsafe-rpc-external2525.github/workflows/collator-selection.ymldiffbeforeafterboth138 tag: ${{ matrix.network }}-${{ env.REF_SLUG }}-${{ env.BUILD_SHA }}138 tag: ${{ matrix.network }}-${{ env.REF_SLUG }}-${{ env.BUILD_SHA }}139 context: .139 context: .140 dockerfile: .docker/Dockerfile-unique140 dockerfile: .docker/Dockerfile-unique141 args: |141 args: |142 --build-arg RUNTIME_FEATURES=${{ matrix.runtime_features }}142 --build-arg RUNTIME_FEATURES=${{ matrix.runtime_features }},session-test-timings143 --build-arg RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}143 --build-arg RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}144 dockerhub_username: ${{ secrets.CORE_DOCKERHUB_USERNAME }}144 dockerhub_username: ${{ secrets.CORE_DOCKERHUB_USERNAME }}145 dockerhub_token: ${{ secrets.CORE_DOCKERHUB_TOKEN }}145 dockerhub_token: ${{ secrets.CORE_DOCKERHUB_TOKEN }}146146node/cli/Cargo.tomldiffbeforeafterboth108runtime-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']108runtime-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']109sapphire-runtime = ['quartz-runtime', 'quartz-runtime/become-sapphire']109sapphire-runtime = ['quartz-runtime', 'quartz-runtime/become-sapphire']110try-runtime = ['opal-runtime?/try-runtime', 'quartz-runtime?/try-runtime', 'try-runtime-cli/try-runtime', 'unique-runtime?/try-runtime']110try-runtime = ['opal-runtime?/try-runtime', 'quartz-runtime?/try-runtime', 'try-runtime-cli/try-runtime', 'unique-runtime?/try-runtime']111session-test-timings = ['opal-runtime/session-test-timings', 'quartz-runtime?/session-test-timings', 'unique-runtime?/session-test-timings']112gov-test-timings = ['opal-runtime/gov-test-timings', 'quartz-runtime?/gov-test-timings', 'unique-runtime?/gov-test-timings']111113runtime/common/config/pallets/mod.rsdiffbeforeafterboth125 pub AppPromotionDailyRate: Perbill = Perbill::from_rational(5u32, 10_000);125 pub AppPromotionDailyRate: Perbill = Perbill::from_rational(5u32, 10_000);126 pub const MaxCollators: u32 = MAX_COLLATORS;126 pub const MaxCollators: u32 = MAX_COLLATORS;127 pub const LicenseBond: Balance = GENESIS_LICENSE_BOND;127 pub const LicenseBond: Balance = GENESIS_LICENSE_BOND;128 pub const SessionPeriod: BlockNumber = SESSION_LENGTH;128129 pub const DayRelayBlocks: BlockNumber = RELAY_DAYS;129 pub const DayRelayBlocks: BlockNumber = RELAY_DAYS;130}130}131132#[cfg(not(feature = "session-test-timings"))]133parameter_types! {134 pub const SessionPeriod: BlockNumber = SESSION_LENGTH;135}136137#[cfg(feature = "session-test-timings")]138parameter_types! {139 pub const SessionPeriod: BlockNumber = 5 * MINUTES;140}131141132impl pallet_configuration::Config for Runtime {142impl pallet_configuration::Config for Runtime {133 type RuntimeEvent = RuntimeEvent;143 type RuntimeEvent = RuntimeEvent;runtime/opal/Cargo.tomldiffbeforeafterboth229preimage = []229preimage = []230refungible = []230refungible = []231unique-scheduler = []231unique-scheduler = []232session-test-timings = []232233233################################################################################234################################################################################234# local dependencies235# local dependenciesruntime/quartz/Cargo.tomldiffbeforeafterboth218refungible = []218refungible = []219unique-scheduler = []219unique-scheduler = []220gov-test-timings = []220gov-test-timings = []221session-test-timings = []221222222################################################################################223################################################################################223# local dependencies224# local dependenciesruntime/unique/Cargo.tomldiffbeforeafterboth221refungible = []221refungible = []222unique-scheduler = []222unique-scheduler = []223gov-test-timings = []223gov-test-timings = []224session-test-timings = []224225225################################################################################226################################################################################226# local dependencies227# local dependenciestests/src/collator-selection/collatorSelection.seqtest.tsdiffbeforeafterboth17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';18import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from '../util';18import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from '../util';1920async function nodeAddress(name: string) {21 // eslint-disable-next-line require-await22 return await usingPlaygrounds(async (helper, _) => {23 const envNodeStash = `RELAY_UNIQUE_NODE_${name.toUpperCase()}_STASH`;2425 const nodeStash = process.env[envNodeStash];26 if(nodeStash) {27 return helper.address.normalizeSubstrateToChainFormat(nodeStash);28 } else {29 throw Error(`"${envNodeStash}" env var is not set`);30 }31 });32}3334async function getInitialInvulnerables() {35 return await Promise.all([36 nodeAddress('alpha'),37 nodeAddress('beta'),38 nodeAddress('gamma'),39 nodeAddress('delta'),40 ]);41}194220async function resetInvulnerables() {43async function resetInvulnerables() {21 await usingPlaygrounds(async (helper, privateKey) => {44 await usingPlaygrounds(async (helper, privateKey) => {22 const superuser = await privateKey('//Alice');45 const superuser = await privateKey('//Alice');23 const alice = await privateKey('//Alice');46 const initialInvulnerables = await getInitialInvulnerables();24 const bob = await privateKey('//Bob');4725 const invulnerables = await helper.collatorSelection.getInvulnerables();48 const invulnerables = await helper.collatorSelection.getInvulnerables();26 if(!invulnerables.includes(alice.address) || !invulnerables.includes(bob.address) || invulnerables.length != 2) {4927 console.warn('Alice and Bob are not the invulnerables! Reinstating them back. '50 // Remove all invulnerables but the first one28 + 'Current invulnerables\' size: ' + invulnerables.length);51 const firstInvulnerable = invulnerables[0];295230 let nonce = await helper.chain.getNonce(alice.address);53 let nonce = await helper.chain.getNonce(superuser.address);31 // In case there are too many invulnerables already, remove some of them, leaving space for Alice and Bob.32 if(invulnerables.length + 2 >= helper.collatorSelection.maxCollators()) {33 await Promise.all([54 await Promise.all(invulnerables.slice(1).map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++})));34 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerables.pop()!], true, {nonce: nonce++}),5535 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerables.pop()!], true, {nonce: nonce++}),56 // Add the initial invulnerables36 ]);37 }3839 nonce = await helper.chain.getNonce(alice.address);40 await Promise.all([57 await Promise.all(initialInvulnerables.map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [invulnerable], true, {nonce: nonce++})));41 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),5842 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),59 // Remove the first invulnerable if it's not an initial one43 ]);4445 nonce = await helper.chain.getNonce(alice.address);46 await Promise.all(invulnerables.map((invulnerable: any) => {47 if(invulnerable == alice.address || invulnerable == bob.address) return new Promise<void>(res => res());60 if(!initialInvulnerables.includes(firstInvulnerable)) {48 return helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++});61 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [firstInvulnerable]);49 }));62 }50 }51 });63 });52}64}5365728473 describe('Dynamic shuffling of collators', () => {85 describe('Dynamic shuffling of collators', () => {74 // These two are the default invulnerables, and should return to be invulnerables after this suite.86 // These two are the default invulnerables, and should return to be invulnerables after this suite.75 let alice: IKeyringPair;87 let alphaNode: string;76 let bob: IKeyringPair;88 let betaNode: string;778978 let charlie: IKeyringPair;90 let gammaNode: string;79 let dave: IKeyringPair;91 let deltaNode: string;809281 before(async function() {93 before(async function() {82 await usingPlaygrounds(async (helper, privateKey) => {94 await usingPlaygrounds(async (helper, privateKey) => {83 // todo:collator see again if blocks start to be finalized in dev mode95 // todo:collator see again if blocks start to be finalized in dev mode84 // Skip the collator block production in dev mode, since the blocks are sealed automatically.96 // Skip the collator block production in dev mode, since the blocks are sealed automatically.85 if(await helper.arrange.isDevNode()) this.skip();97 if(await helper.arrange.isDevNode()) this.skip();869887 alice = await privateKey('//Alice');99 [alphaNode, betaNode, gammaNode, deltaNode] = await getInitialInvulnerables();88 bob = await privateKey('//Bob');89 charlie = await privateKey('//Charlie');90 dave = await privateKey('//Dave');9110092 expect((await helper.session.setOwnKeysFromAddress(charlie))101 const invulnerables = await helper.collatorSelection.getInvulnerables();93 .status.toLowerCase()).to.be.equal('success');94 expect((await helper.session.setOwnKeysFromAddress(dave))102 expect(invulnerables.length, 'Invalid initial invulnerables number').to.be.equal(4);95 .status.toLowerCase()).to.be.equal('success');9697 const invulnerables = await helper.collatorSelection.getInvulnerables();98 if(!invulnerables.includes(alice.address) || !invulnerables.includes(bob.address) || invulnerables.length != 2) {99 console.warn('Alice and Bob are not the invulnerables! Reinstating them back. '103 expect(invulnerables, 'Invalid initial invulnerables').containSubset([alphaNode, betaNode, gammaNode, deltaNode]);100 + 'Current invulnerables\' size: ' + invulnerables.length);101102 let nonce = await helper.chain.getNonce(superuser.address);103 await Promise.all([104 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),105 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),106 ]);107108 nonce = await helper.chain.getNonce(superuser.address);109 await Promise.all(invulnerables.map((invulnerable: any) => {110 if(invulnerable == alice.address || invulnerable == bob.address) return new Promise((res) => res);111 return helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++});112 }));113 }114 });104 });115 });105 });116106117 itSub('Change invulnerables and make sure they start producing blocks', async ({helper}) => {107 itSub('Change invulnerables and make sure they start producing blocks', async ({helper}) => {118 let nonce = await helper.chain.getNonce(superuser.address);108 let nonce = await helper.chain.getNonce(superuser.address);119 await expect(Promise.all([120 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [charlie.address], true, {nonce: nonce++}),121 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [dave.address], true, {nonce: nonce++}),122 ])).to.be.fulfilled;123109124 nonce = await helper.chain.getNonce(superuser.address);110 nonce = await helper.chain.getNonce(superuser.address);125 await expect(Promise.all([111 await expect(Promise.all([126 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alice.address], true, {nonce: nonce++}),112 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alphaNode], true, {nonce: nonce++}),127 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [bob.address], true, {nonce: nonce++}),113 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [betaNode], true, {nonce: nonce++}),128 ])).to.be.fulfilled;114 ])).to.be.fulfilled;129115130 const newInvulnerables = await helper.collatorSelection.getInvulnerables();116 const newInvulnerables = await helper.collatorSelection.getInvulnerables();131 expect(newInvulnerables).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);117 expect(newInvulnerables).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);132118133 await helper.wait.newSessions(2);119 await helper.wait.newSessions(2);134120135 const newValidators = await helper.callRpc('api.query.session.validators');121 const newValidators = await helper.callRpc('api.query.session.validators');136 expect(newValidators).to.contain(charlie.address).and.contain(dave.address).and.be.length(2);122 expect(newValidators).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);137123138 const lastBlockNumber = await helper.chain.getLatestBlockNumber();124 const lastBlockNumber = await helper.chain.getLatestBlockNumber();139 await helper.wait.newBlocks(1);125 await helper.wait.newBlocks(1);140 const lastCharlieBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [charlie.address])).toNumber();126 const lastGammaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [gammaNode])).toNumber();141 const lastDaveBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [dave.address])).toNumber();127 const lastDeltaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [deltaNode])).toNumber();142 expect(lastCharlieBlock >= lastBlockNumber || lastDaveBlock >= lastBlockNumber).to.be.true;128 expect(lastGammaBlock >= lastBlockNumber || lastDeltaBlock >= lastBlockNumber).to.be.true;143 });129 });144130145 after(async () => {131 after(async () => {146 await usingPlaygrounds(async (helper) => {132 await resetInvulnerables();147 if(await helper.arrange.isDevNode()) return;148149 let nonce = await helper.chain.getNonce(superuser.address);150 await Promise.all([151 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [alice.address], true, {nonce: nonce++}),152 helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [bob.address], true, {nonce: nonce++}),153 ]);154155 nonce = await helper.chain.getNonce(superuser.address);156 await Promise.all([157 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [charlie.address], true, {nonce: nonce++}),158 await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [dave.address], true, {nonce: nonce++}),159 ]);160 });161 });133 });162 });134 });163135164 describe('Getting and releasing licenses to collate', () => {136 describe('Getting and releasing licenses to collate', () => {165 let charlie: IKeyringPair;166 let dave: IKeyringPair;167 let crowd: IKeyringPair[];137 let crowd: IKeyringPair[];168138169 before(async function() {139 before(async function() {170 await usingPlaygrounds(async (helper, privateKey) => {140 await usingPlaygrounds(async (helper, privateKey) => {171 charlie = await privateKey('//Charlie');172 dave = await privateKey('//Dave');173 crowd = await helper.arrange.createCrowd(20, 100n, superuser);141 crowd = await helper.arrange.createCrowd(20, 100n, superuser);174142175 // set session keys for everyone143 // set session keys for everyone176 expect((await helper.session.setOwnKeysFromAddress(charlie))177 .status.toLowerCase()).to.be.equal('success');178 expect((await helper.session.setOwnKeysFromAddress(dave))179 .status.toLowerCase()).to.be.equal('success');180 await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));144 await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));181 });145 });182 });146 });252 });216 });253217254 describe('Onboarding, collating, and offboarding as collator candidates', () => {218 describe('Onboarding, collating, and offboarding as collator candidates', () => {255 // These two are the default invulnerables, and should return to be invulnerables after this suite.256 let charlie: IKeyringPair;257 let dave: IKeyringPair;258 let crowd: IKeyringPair[];219 let crowd: IKeyringPair[];259220260 before(async function() {221 before(async function() {261 await usingPlaygrounds(async (helper, privateKey) => {222 await usingPlaygrounds(async (helper, privateKey) => {262 charlie = await privateKey('//Charlie');263 dave = await privateKey('//Dave');264 crowd = await helper.arrange.createCrowd(20, 100n, superuser);223 crowd = await helper.arrange.createCrowd(20, 100n, superuser);265224266 // set session keys for everyone225 // set session keys for everyone267 expect((await helper.session.setOwnKeysFromAddress(charlie))268 .status.toLowerCase()).to.be.equal('success');269 expect((await helper.session.setOwnKeysFromAddress(dave))270 .status.toLowerCase()).to.be.equal('success');271 await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));226 await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));272 });227 });273 });228 });341 });296 });342297343 describe('Addition and removal of invulnerables', () => {298 describe('Addition and removal of invulnerables', () => {344 before(async function() {345 await resetInvulnerables();346 });347348 describe('Positive', () => {299 describe('Positive', () => {349 itSub('Adds an invulnerable', async ({helper}) => {300 itSub('Adds an invulnerable', async ({helper}) => {409 // 28 non-functioning collators, teehee.360 // 28 non-functioning collators, teehee.410361411 const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;362 const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;412 const invulnerablesUntilLimit = helper.collatorSelection.maxCollators() - invulnerablesLength;363 const invulnerablesUntilLimit = (await helper.collatorSelection.getDesiredCollators()) - invulnerablesLength;413 const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);364 const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);414 const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);365 const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);415366449 expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);400 expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);450 });401 });402403 after(async function() {404 await resetInvulnerables();405 });451 });406 });452 });407 });453408