Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: 🔧 Update dancelight smoketests #867

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0b8db22
refactor: root pnpm workspaces
mario-sangar Feb 3, 2025
935bd1c
Merge branch 'master' into f/mario-sangar-root-pnpm-workspaces
girazoki Feb 3, 2025
6590d05
refactor: :recycle: Replace prettier with Biome
timbrinded Feb 4, 2025
cab83ab
update packages
timbrinded Feb 4, 2025
d1a5f07
Merge branch 'master' of github.com:moondance-labs/tanssi into refact…
timbrinded Feb 4, 2025
71b23fa
fix lint issues
timbrinded Feb 4, 2025
4a78286
regenerate api-augment
timbrinded Feb 4, 2025
fa6d8f9
fix tc failure
timbrinded Feb 4, 2025
d7bbe22
fix: 😰 Fix all linting issues
timbrinded Feb 5, 2025
e8ab9b1
Merge branch 'master' of github.com:moondance-labs/tanssi into refact…
timbrinded Feb 5, 2025
f9b1343
fix: frontier tests
timbrinded Feb 5, 2025
1d78f13
fix: relay-tests
timbrinded Feb 5, 2025
d232b07
fix: zombie-relay-test
timbrinded Feb 5, 2025
62cdcdc
fix test
timbrinded Feb 5, 2025
5ecf2cd
Merge branch 'master' into refactor/switch-biome
timbrinded Feb 5, 2025
b45ccaf
remove eslint
timbrinded Feb 5, 2025
748901a
Merge branch 'refactor/switch-biome' of github.com:moondance-labs/tan…
timbrinded Feb 5, 2025
244fa77
Merge branch 'master' into refactor/switch-biome
timbrinded Feb 5, 2025
7aa9c62
fix smoke tests
timbrinded Feb 6, 2025
cc58367
ignore IDE files
timbrinded Feb 6, 2025
6062344
fix data preserver fee calc
timbrinded Feb 6, 2025
3e83f65
Merge branch 'master' of github.com:moondance-labs/tanssi into refact…
timbrinded Feb 7, 2025
f4437c3
refactor: ♻️ fix babe types
timbrinded Feb 7, 2025
70da8e3
refactor: ♻️ Update authority smoke test
timbrinded Feb 7, 2025
811b04b
fix: update beefy test
timbrinded Feb 7, 2025
b5593e7
progress
timbrinded Feb 9, 2025
a82ecfa
update validator rewards smoke
timbrinded Feb 10, 2025
fd38b36
update inflation rewards smoke
timbrinded Feb 10, 2025
d8b24e2
update session/ext validators test
timbrinded Feb 10, 2025
c7ba6cd
update config consistency test
timbrinded Feb 10, 2025
a9ad1a1
update remaining dancelight smoke tests
timbrinded Feb 10, 2025
4e5e697
Merge branch 'master' of github.com:moondance-labs/tanssi into feat/a…
timbrinded Feb 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "@tanssi/api-augment/dancelight";
import { beforeAll, describeSuite, expect } from "@moonwall/cli";

import type { ApiPromise } from "@polkadot/api";

describeSuite({
Expand All @@ -17,22 +17,32 @@ describeSuite({
id: "C01",
title: "Collator assignation and authority assignation should match with observed mapping in containers",
test: async () => {
const assignmentCollatorAccount = (
await api.query.tanssiCollatorAssignment.collatorContainerChain()
).toJSON();
const assignmentCollatorAccount = await api.query.tanssiCollatorAssignment.collatorContainerChain();
const sessionIndex = (await api.query.session.currentIndex()).toNumber();
const assignmentCollatorKey = (
await api.query.tanssiAuthorityAssignment.collatorContainerChain(sessionIndex)
).toJSON();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We abuse toJSON because it makes it easier to see the diff when an expect fails. Can you verify that expect(assignmentCollatorKey).toBeNull() shows a nice error message with the assignmentCollatorKey?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will check. Problem about using toJSON() is that it casts it to any. What we currently have is that it will show you an error without even having to run the tests

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@timbrinded please check this expect thing

).unwrap();
const authorityKeyMapping = (
await api.query.tanssiAuthorityMapping.authorityIdMapping(sessionIndex)
).toJSON();
for (const container of Object.keys(assignmentCollatorKey.containerChains)) {
for (const key of assignmentCollatorKey.containerChains[container]) {
const assignedAccount = authorityKeyMapping[key.toString()];
expect(
assignmentCollatorAccount.containerChains[container].includes(assignedAccount.toString())
).to.be.true;
).unwrap();

const remappedAssignmentCollatorAccount = Object.fromEntries(
[...assignmentCollatorAccount.containerChains.entries()].map(([key, value]) => [
key.toString(),
value.map((v) => v.toHuman()),
])
);

const remappedAuthorityKeyMapping = Object.fromEntries(
[...authorityKeyMapping.entries()].map(([key, value]) => [key.toHex(), value.toHuman()])
);

const containerChains = assignmentCollatorKey.containerChains.keys();

for (const container of containerChains) {
for (const key of assignmentCollatorKey.containerChains.get(container)) {
const assignedAccount = remappedAuthorityKeyMapping[key.toHex()];
expect(remappedAssignmentCollatorAccount[container.toString()]).toContain(assignedAccount);
}
}
},
Expand Down
88 changes: 49 additions & 39 deletions test/suites/smoke-test-dancelight/test-babe.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
import "@tanssi/api-augment/dancelight";
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
import { getBlockArray } from "@moonwall/util";
import type { ApiPromise } from "@polkadot/api";
import type { GenericExtrinsic, U32 } from "@polkadot/types";
import type { FrameSystemEventRecord } from "@polkadot/types/lookup";
import type { GenericExtrinsic, u64 } from "@polkadot/types";
import type {
FrameSystemEventRecord,
SpConsensusBabeAppPublic,
SpConsensusBabeDigestsPreDigest,
} from "@polkadot/types/lookup";
import type { AnyTuple } from "@polkadot/types/types";
import { hexToU8a, stringToHex } from "@polkadot/util";
import { sr25519Verify } from "@polkadot/wasm-crypto";
import Bottleneck from "bottleneck";
import type { AccountId32, BlockHash, DigestItem, Header } from "@polkadot/types/interfaces";
import type { HexString } from "@polkadot/util/types";
import type { ApiDecoration } from "@polkadot/api/types";

const timePeriod = process.env.TIME_PERIOD ? Number(process.env.TIME_PERIOD) : 1 * 60 * 60 * 1000;
const timeout = Math.max(Math.floor(timePeriod / 12), 5000);
const hours = (timePeriod / (1000 * 60 * 60)).toFixed(2);

type BlockFilteredRecord = {
blockNum: number;
blockHash;
header;
preHash;
extrinsics: GenericExtrinsic<AnyTuple>[];
events: FrameSystemEventRecord[];
logs;
authorities;
accountsWithBabeKeys;
};

describeSuite({
id: "SMOK02",
title: "Sample suite that only runs on Dancelight chains",
Expand All @@ -49,7 +45,7 @@ describeSuite({
const authorities = await apiAt.query.session.validators();
const babeAuthorities = await apiAt.query.babe.authorities();

const blockBabeEpochStart = (await apiAt.query.babe.epochStart()).toJSON()[0];
const blockBabeEpochStart = (await apiAt.query.babe.epochStart())[0].toNumber();
const apiAtSessionChange = await api.at(await api.rpc.chain.getBlockHash(blockBabeEpochStart));

// If there has been a recent change in session keys,
Expand All @@ -66,13 +62,15 @@ describeSuite({

return {
blockNum: blockNum,
header,
blockHash,
preHash,
extrinsics: signedBlock.block.extrinsics,
events: await apiAt.query.system.events(),
logs: signedBlock.block.header.digest.logs,
authorities,
accountsWithBabeKeys,
};
} satisfies BlockFilteredRecord;
};
const limiter = new Bottleneck({ maxConcurrent: 5, minTime: 100 });
blockData = await Promise.all(blockNumArray.map((num) => limiter.schedule(() => getBlockData(num))));
Expand All @@ -85,7 +83,7 @@ describeSuite({
// Check the previous epoch digest.
// The [0] index indicates the block number in which the previous session started.
// The [1] index indicates the block number in which the current session started.
const blockToCheck = ((await api.query.babe.epochStart()) as unknown as [U32, U32])[0];
const blockToCheck = (await api.query.babe.epochStart())[0];
const apiAtSessionChange = await api.at(await api.rpc.chain.getBlockHash(blockToCheck));

const digestsInSessionChange = (await apiAtSessionChange.query.system.digest()).logs;
Expand All @@ -104,23 +102,25 @@ describeSuite({
filteredDigests[0].asConsensus[1].toHex()
);

expect(babeConsensusLog[1]).to.deep.equal(babeAuthoritiesFromPallet);
expect(babeConsensusLog[1].eq(babeAuthoritiesFromPallet)).toBe(true);

const keyOwnersArray = [];
const keyOwnersArray: string[] = [];
const keyOwnersInPalletSession = await keyOwners(babeAuthoritiesFromPallet, api);

for (const keyOwner of keyOwnersInPalletSession) {
keyOwnersArray.push(keyOwner[0]);
}

// Get validators from pallet session
const sessionValidators = await api.query.session.validators();
const sessionValidators = (await api.query.session.validators()).map((validator) =>
validator.toPrimitive()
);

keyOwnersArray.sort();
sessionValidators.sort();

// Check that key owners found are the same validators in pallet session
expect(keyOwnersArray).to.deep.equal(sessionValidators.toJSON());
expect(keyOwnersArray).toEqual(sessionValidators);
},
});

Expand All @@ -135,17 +135,17 @@ describeSuite({
);
expect(babeLogs.length).to.eq(1);

const babeLogEnum = api.registry.createType(
const babeLogEnum: SpConsensusBabeDigestsPreDigest = api.registry.createType(
"SpConsensusBabeDigestsPreDigest",
babeLogs[0].asPreRuntime[1].toHex()
);

expect(babeLogEnum.isSecondaryVRF || babeLogEnum.isPrimary).toBeTruthy();
expect(babeLogEnum.isSecondaryVRF || babeLogEnum.isPrimary).toBe(true);
const babeLog = babeLogEnum.isSecondaryVRF ? babeLogEnum.asSecondaryVRF : babeLogEnum.asPrimary;

// Get expected author from BABE log and on chain authorities
const authorityIndex = babeLog.authorityIndex;
const orchestratorAuthorities = authorities.toJSON();
const orchestratorAuthorities = authorities;
const expectedAuthor = orchestratorAuthorities[authorityIndex.toNumber()];

// Get block author signature from seal log
Expand All @@ -162,7 +162,7 @@ describeSuite({
// Verify seal signature
const message = hexToU8a(preHash);
const signature = hexToU8a(sealLog.toHex());
const authorBabe = accountsWithBabeKeys.find((acc) => acc[0] === expectedAuthor);
const authorBabe = accountsWithBabeKeys.find((acc) => acc[0] === expectedAuthor.toHuman());
expect(authorBabe, `Missing babe key for block author: ${expectedAuthor}`).toBeTruthy();
const pubKey = hexToU8a(authorBabe[1]);

Expand All @@ -189,7 +189,7 @@ describeSuite({

// Given a block header, returns its preHash. This is the hash of the header before adding the seal.
// The hash of the block header after adding the seal is the block hash.
function getPreHash(api, header) {
function getPreHash(api: ApiPromise, header: Header) {
const logsNoSeal = header.digest.logs.filter((log) => !log.isSeal);
const headerWithoutSeal = api.registry.createType("Header", {
parentHash: header.parentHash,
Expand All @@ -205,22 +205,32 @@ function getPreHash(api, header) {

// Helper function to retrieve the validators from pallet session given
// the babe authorities (babeKeys) and a specific api instance.
async function keyOwners(babeAuthoritiesFromPallet, api) {
const keyOwnersInPalletSession = [];
async function keyOwners(
babeAuthoritiesFromPallet: [SpConsensusBabeAppPublic, u64][],
api: ApiPromise | ApiDecoration<"promise">
) {
const keyOwnersInPalletSession: [string, string][] = [];

for (const authority of babeAuthoritiesFromPallet) {
const param = api.registry.createType("(SpCoreCryptoKeyTypeId, Bytes)", [
stringToHex("babe"),
authority[0].toHex(),
]);
const keyOwner = await api.query.session.keyOwner(param);

expect(
keyOwner.isSome,
`Validator with babe key ${authority[0].toJSON()} not found in pallet session!`
).toBeTruthy();
keyOwnersInPalletSession.push([keyOwner.toJSON(), authority[0].toJSON()]);
const keyOwner = await api.query.session.keyOwner([stringToHex("babe"), authority[0].toHex()]);

expect(keyOwner.isSome, `Validator with babe key ${authority[0].toHuman()} not found in pallet session!`).toBe(
true
);
keyOwnersInPalletSession.push([keyOwner.unwrap().toHuman(), authority[0].toJSON()]);
}

return keyOwnersInPalletSession;
}

interface BlockFilteredRecord {
blockNum: number;
blockHash: BlockHash;
header: Header;
preHash: HexString;
extrinsics: GenericExtrinsic<AnyTuple>[];
events: FrameSystemEventRecord[];
logs: DigestItem[];
authorities: AccountId32[];
accountsWithBabeKeys: [string, string][];
}
14 changes: 10 additions & 4 deletions test/suites/smoke-test-dancelight/test-beefy-mmr-digests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "@tanssi/api-augment/dancelight";
import { beforeAll, describeSuite, expect } from "@moonwall/cli";

import { stringToHex } from "@polkadot/util";
import type { ApiPromise } from "@polkadot/api";

Expand All @@ -18,7 +18,7 @@ describeSuite({
id: "C01",
title: "Session change block should update BEEFY and MMR root digests properly",
test: async () => {
const blockToCheck = (await api.query.babe.epochStart()).toJSON()[1];
const blockToCheck = (await api.query.babe.epochStart())[1].toNumber();

const apiAtBeforeSessionChange = await api.at(await api.rpc.chain.getBlockHash(blockToCheck - 5));
const beefyNextAuthorities = await apiAtBeforeSessionChange.query.beefy.nextAuthorities();
Expand All @@ -37,10 +37,16 @@ describeSuite({
expect(filteredDigests[0].asConsensus[1].toHex().startsWith("0x01")).to.be.true;

// Check if each authority is included in the BEEFY digest
for (const authority of Object.values(beefyNextAuthorities.toJSON())) {
expect(filteredDigests[0].asConsensus[1].toHex().includes(authority.slice(2))).to.be.true;
const failures = beefyNextAuthorities
.map((authority) => authority.toHex().slice(2))
.filter((authority) => !filteredDigests[0].asConsensus[1].toHex().includes(authority));

for (const failure of failures) {
console.error(`${failure} is not included in the BEEFY digest`);
}

expect(failures.length).to.eq(0);

const firstMmrRootDigest = filteredDigests[1].asConsensus[1].toHex();

// 0x03 corresponds to ConsensusLog::MmrRoot enum variant.
Expand Down
43 changes: 23 additions & 20 deletions test/suites/smoke-test-dancelight/test-configuration-consistency.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "@tanssi/api-augment/dancelight";
import { beforeAll, describeSuite, expect } from "@moonwall/cli";

import type { ApiPromise } from "@polkadot/api";
import { hasEnoughCredits } from "util/payment";
import type { u32, Vec } from "@polkadot/types-codec";
Expand All @@ -23,29 +23,36 @@ describeSuite({
title: "Config for registered paras should be consistent",
test: async () => {
const sessionIndex = (await api.query.session.currentIndex()).toNumber();
const blockToCheck = (await api.query.babe.epochStart()).toJSON()[1];
const blockToCheck = (await api.query.babe.epochStart())[1].toNumber();

const apiBeforeLatestNewSession = await api.at(await api.rpc.chain.getBlockHash(blockToCheck - 1));
const config = await api.query.collatorConfiguration.activeConfig();

// get pending authorities
// the reason for getting pending is that the hasEnoughCredits check it's done over the pending ones
const pendingAuthorityAssignment = (
await api.query.tanssiAuthorityAssignment.collatorContainerChain(sessionIndex + 1)
).toJSON();

const pendingAuthorityAssignment = Object.fromEntries(
[
...(await api.query.tanssiAuthorityAssignment.collatorContainerChain(sessionIndex + 1))
.unwrap()
.containerChains.entries(),
].map(([key, value]) => [key.toString(), value.map((v) => v.toHuman())])
);
// get current authorities
// we need to know whether a chain is assigned currently
const currentAuthorityAssignment = (
await api.query.tanssiAuthorityAssignment.collatorContainerChain(sessionIndex)
).toJSON();

const currentAuthorityAssignment = Object.fromEntries(
[
...(await api.query.tanssiAuthorityAssignment.collatorContainerChain(sessionIndex))
.unwrap()
.containerChains.entries(),
].map(([key, value]) => [key.toString(), value.map((v) => v.toHuman())])
);
const currentAuthorities = await api.query.session.validators();

const currentCollatorNumber = Math.min(currentAuthorities.length, config.maxCollators);
const currentCollatorNumber = Math.min(currentAuthorities.length, config.maxCollators.toNumber());

const maxParas = Math.trunc(
(currentCollatorNumber - config.minOrchestratorCollators) / config.collatorsPerContainer
(currentCollatorNumber - config.minOrchestratorCollators.toNumber()) /
config.collatorsPerContainer.toNumber()
);

// If we have container chain collators, is because the collator number is higher
Expand Down Expand Up @@ -76,8 +83,8 @@ describeSuite({
let sessionRequirements: bigint;

if (
currentAuthorityAssignment.containerChains[container.toString()] === null ||
currentAuthorityAssignment.containerChains[container.toString()].length === 0
currentAuthorityAssignment[container.toString()] === null ||
currentAuthorityAssignment[container.toString()].length === 0
) {
sessionRequirements = 1n;
} else {
Expand All @@ -99,9 +106,7 @@ describeSuite({
// Here we only check that that we have collators
// If we are able to cover all paras, then all of them should have collators if credits
if (maxParas >= containersToCompareAgainst.length) {
expect(
pendingAuthorityAssignment.containerChains[container.toString()].length
).to.be.greaterThan(0);
expect(pendingAuthorityAssignment[container.toString()].length).to.be.greaterThan(0);
}
} else {
numWithNoCredits += 1;
Expand All @@ -114,9 +119,7 @@ describeSuite({
containersToCompareAgainst.length - numWithNoCredits,
maxParas
);
expect(Object.keys(pendingAuthorityAssignment.containerChains).length).to.be.equal(
expectedNumberOfChainsAssigned
);
expect(Object.keys(pendingAuthorityAssignment).length).to.be.equal(expectedNumberOfChainsAssigned);
}
},
});
Expand Down
Loading
Loading