Skip to content

Commit

Permalink
new tests
Browse files Browse the repository at this point in the history
  • Loading branch information
girazoki committed Feb 7, 2024
1 parent dad7943 commit b7cc9ab
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 5 deletions.
16 changes: 14 additions & 2 deletions pallets/collator-assignment/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,6 @@ pub mod pallet {
let collators_per_container =
T::HostConfiguration::collators_per_container(target_session_index);
for para_id in &container_chain_ids {
T::CollatorAssignmentHook::on_collators_assigned(*para_id);
chains.push(ChainNumCollators {
para_id: *para_id,
min_collators: collators_per_container,
Expand All @@ -228,7 +227,6 @@ pub mod pallet {
let collators_per_parathread =
T::HostConfiguration::collators_per_parathread(target_session_index);
for para_id in &parathreads {
T::CollatorAssignmentHook::on_collators_assigned(*para_id);
chains.push(ChainNumCollators {
para_id: *para_id,
min_collators: collators_per_parathread,
Expand Down Expand Up @@ -289,6 +287,20 @@ pub mod pallet {
}
};

// TODO: this probably is asking for a refactor
// only apply the onCollatorAssignedHook if sufficient collators
for para_id in &container_chain_ids {
if !new_assigned.container_chains.get(para_id).unwrap_or(&vec![]).is_empty() {
T::CollatorAssignmentHook::on_collators_assigned(*para_id);
}
}

for para_id in &parathreads {
if !new_assigned.container_chains.get(para_id).unwrap_or(&vec![]).is_empty() {
T::CollatorAssignmentHook::on_collators_assigned(*para_id);
}
}

let mut pending = PendingCollatorContainerChain::<T>::get();
let old_assigned_changed = old_assigned != new_assigned;
let mut pending_changed = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describeSuite({

it({
id: "E01",
title: "Collators are unassigned when a container chain does not have enough credits",
title: "Collators are unassigned when a container chain does not have enough block credits",
test: async function () {
// Create blocks until authorNoting.blockNum does not increase anymore.
// Check that collatorAssignment does not have collators and num credits is less than 2 sessions.
Expand All @@ -45,7 +45,7 @@ describeSuite({
});
it({
id: "E02",
title: "Collators are not assigned when we buy 2 session + ED -1",
title: "Collators are not assigned when we buy 2 session + ED -1 of block credits",
test: async function () {
const tx2000OneSession = polkadotJs.tx.servicesPayment.setBlockProductionCredits(
paraId2000,
Expand All @@ -71,7 +71,7 @@ describeSuite({
});
it({
id: "E03",
title: "Collators are assigned when we buy at least 2 session + ED",
title: "Collators are assigned when we buy at least 2 session + ED of block credits",
test: async function () {
// Now, buy the remaining
const purchasedCredits = 1n;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import "@tanssi/api-augment";
import { describeSuite, expect, beforeAll } from "@moonwall/cli";
import { ApiPromise } from "@polkadot/api";
import { KeyringPair } from "@moonwall/util";
import { jumpSessions } from "util/block";

describeSuite({
id: "CT0604",
title: "Services payment test suite",
foundationMethods: "dev",
testCases: ({ it, context }) => {
let polkadotJs: ApiPromise;
let alice: KeyringPair;
const paraId2000 = 2000n;
const paraId2001 = 2001n;
const costPerSession = 100_000_000n;
beforeAll(async () => {
polkadotJs = context.polkadotJs();
alice = context.keyring.alice;
});

it({
id: "E01",
title: "Collators are unassigned when a container chain does not have enough collator assignment credits",
test: async function () {
// Create blocks until authorNoting.blockNum does not increase anymore.
// Check that collatorAssignment does not have collators and num credits is less than 2 sessions.

const tx2000free = polkadotJs.tx.servicesPayment.setCollatorAssignmentCredits(paraId2000, 0n);
const tx2001free = polkadotJs.tx.servicesPayment.setCollatorAssignmentCredits(paraId2001, 0n);

await context.createBlock([await polkadotJs.tx.sudo.sudo(tx2000free).signAsync(alice)]);
await context.createBlock([await polkadotJs.tx.sudo.sudo(tx2001free).signAsync(alice)]);

// Check that after 2 sessions, container chain 2000 has collators and is producing blocks
await jumpSessions(context, 2);

const collators = await polkadotJs.query.collatorAssignment.collatorContainerChain();
expect(
collators.toJSON().containerChains[paraId2000],
`Container chain ${paraId2000} should have 0 collators`
).toBeUndefined();
},
});
it({
id: "E02",
title: "Collators are not assigned when we buy 2 session + ED -1 of collator assignment credits",
test: async function () {
const tx2000OneSession = polkadotJs.tx.servicesPayment.setCollatorAssignmentCredits(paraId2000, 1);
await context.createBlock([await polkadotJs.tx.sudo.sudo(tx2000OneSession).signAsync(alice)]);
const existentialDeposit = await polkadotJs.consts.balances.existentialDeposit.toBigInt();
// Now, buy some credits for container chain 2000. we only buy ones session -1
const purchasedCredits = costPerSession + existentialDeposit - 1n;
// Check that after 2 sessions, container chain 2000 has not collators
const tx = polkadotJs.tx.servicesPayment.purchaseCredits(paraId2000, purchasedCredits);
await context.createBlock([await tx.signAsync(alice)]);

// Check that after 2 sessions, container chain 2000 has 0 collators and is not producing blocks
await jumpSessions(context, 2);

const collators = await polkadotJs.query.collatorAssignment.collatorContainerChain();
expect(
collators.toJSON().containerChains[paraId2000],
`Container chain ${paraId2000} should have 0 collators`
).toBeUndefined();
},
});
it({
id: "E03",
title: "Collators are assigned when we buy at least 2 session + ED of block credits",
test: async function () {
// Now, buy the remaining
const purchasedCredits = 1n;
// Purchase the remaining 1
const tx = polkadotJs.tx.servicesPayment.purchaseCredits(paraId2000, purchasedCredits);
await context.createBlock([await tx.signAsync(alice)]);

// Check that after 2 sessions, container chain 2000 has collators and is producing blocks
await jumpSessions(context, 2);

const collators = await polkadotJs.query.collatorAssignment.collatorContainerChain();
expect(
collators.toJSON().containerChains[paraId2000].length,
`Container chain ${paraId2000} has 0 collators`
).toBeGreaterThan(0);
},
});
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
import "@tanssi/api-augment";
import { describeSuite, expect, beforeAll } from "@moonwall/cli";
import { ApiPromise } from "@polkadot/api";
import { generateKeyringPair, KeyringPair } from "@moonwall/util";
import { jumpSessions } from "util/block";
import { paraIdTank } from "util/payment";

describeSuite({
id: "CT0601",
title: "Services payment test suite",
foundationMethods: "dev",
testCases: ({ it, context }) => {
let polkadotJs: ApiPromise;
let alice: KeyringPair;
const startingCredits = 100n;

beforeAll(async () => {
polkadotJs = context.polkadotJs();
alice = context.keyring.alice;
});
it({
id: "E01",
title: "Genesis container chains have credits and collators and should have one less credit",
test: async function () {
await context.createBlock();
const parasRegistered = await polkadotJs.query.registrar.registeredParaIds();

for (const paraId of parasRegistered) {
// Should have credits
const credits = await polkadotJs.query.servicesPayment.collatorAssignmentCredits(paraId);

// Should have assigned collators
const collators = await polkadotJs.query.collatorAssignment.collatorContainerChain();

// Container chain 2001 does not have any collators, this will result in only 1 container chain
// producing blocks at a time. So if both container chains have 1000 credits, container 2000
// will produce blocks 0-999, and container 2001 will produce blocks 1000-1999.
if (paraId.toBigInt() === 2000n) {
expect(
credits.unwrap().toBigInt(),
`Container chain ${paraId} should have applied session credits`
).toBe(startingCredits - 1n);
expect(
collators.toJSON().containerChains[paraId.toString()].length,
`Container chain ${paraId} has 0 collators`
).toBeGreaterThan(0);
} else {
expect(
credits.unwrap().toBigInt(),
`Container chain ${paraId} should not have substracted credits`
).toBe(startingCredits);
expect(
collators.toJSON().containerChains[paraId.toString()].length,
`Container chain ${paraId} has 0 collators`
).toBe(0);
}
}
},
});

it({
id: "E02",
title: "Getting assignation should consume credits",
test: async function () {
// Moving to the next session should have reduced the credit by one to both parachains
// even if one does not produce blocks

const paraId = 2000n;
await jumpSessions(context, 1);
const credits = await polkadotJs.query.servicesPayment.collatorAssignmentCredits(paraId);
expect(
credits.unwrap().toBigInt(),
`Container chain ${paraId} does not have enough credits at genesis`
).toBe(startingCredits - 2n);
},
});

it({
id: "E03",
title: "Collators are unassigned when a container chain does not have enough credits",
test: async function () {
// Create blocks until authorNoting.blockNum does not increase anymore.
// Check that collatorAssignment does not have collators and num credits is less than 2 sessions.

const paraId = 2000n;

// Create blocks until the block number stops increasing
let containerBlockNum3 = -1;
let containerBlockNum4 = await (await polkadotJs.query.authorNoting.latestAuthor(paraId)).toJSON()
.blockNumber;

while (containerBlockNum3 != containerBlockNum4) {
await context.createBlock();
containerBlockNum3 = containerBlockNum4;
containerBlockNum4 = await (await polkadotJs.query.authorNoting.latestAuthor(paraId)).toJSON()
.blockNumber;
}

// Now the container chain should have less than 2 sessions worth of credits
const credits = (await polkadotJs.query.servicesPayment.collatorAssignmentCredits(paraId)).toJSON();
expect(
credits,
"Container chain 2000 has stopped producing blocks, so it should not have enough credits"
).toBeLessThan(2n);

const collators = await polkadotJs.query.collatorAssignment.collatorContainerChain();
expect(
collators.toJSON().containerChains[paraId],
`Container chain ${paraId} should have 0 collators`
).toBeUndefined();
},
});

it({
id: "E04",
title: "Root can remove credits",
test: async function () {
// Remove all the credits of container chain 2001, which should have assigned collators now
// This checks that the node does not panic when we try to subtract credits from 0 (saturating_sub)
const paraId = 2001n;
const credits = (await polkadotJs.query.servicesPayment.collatorAssignmentCredits(paraId)).toJSON();
expect(credits, "Container chain 2001 does not have enough credits").toBeGreaterThanOrEqual(2n);

// Should have assigned collators
const collators = await polkadotJs.query.collatorAssignment.collatorContainerChain();
expect(
collators.toJSON().containerChains[paraId].length,
`Container chain ${paraId} has 0 collators`
).toBeGreaterThan(0);

// Set credits to 0
const tx = polkadotJs.tx.servicesPayment.setCollatorAssignmentCredits(paraId, 0n);
await context.createBlock([await polkadotJs.tx.sudo.sudo(tx).signAsync(alice)]);

// After 2 sessions, the container-chain should not be assigned
await jumpSessions(context, 2);
const collatorsAfter = await polkadotJs.query.collatorAssignment.collatorContainerChain();
expect(
collatorsAfter.toJSON().containerChains[paraId],
`Container chain ${paraId} should have 0 collators`
).toBeUndefined();
},
});

it({
id: "E05",
title: "Can buy additional credits",
test: async function () {
// As alice, buy credits for para 2000. Check that it is assigned collators again
const paraId = 2000n;

// Create blocks until no collators are assigned to any container chain
for (;;) {
await context.createBlock();
const collators = await polkadotJs.query.collatorAssignment.collatorContainerChain();
if (Object.keys(collators.toJSON().containerChains).length == 0) {
break;
}
}

// Use random account instead of alice because alice is getting block rewards
const randomAccount = generateKeyringPair("sr25519");
const value = 100_000_000_000n;
await context.createBlock([
await polkadotJs.tx.balances.transferAllowDeath(randomAccount.address, value).signAsync(alice),
]);

// Now, buy some credits for container chain 2000
const balanceBefore = (
await polkadotJs.query.system.account(randomAccount.address)
).data.free.toBigInt();
const purchasedCredits = 100n;

const requiredBalance = purchasedCredits * 100_000_000n;
const tx = polkadotJs.tx.servicesPayment.purchaseCredits(paraId, requiredBalance);
await context.createBlock([await tx.signAsync(randomAccount)]);

const balanceAfter = (
await polkadotJs.query.system.account(randomAccount.address)
).data.free.toBigInt();
expect(balanceAfter).toBeLessThan(balanceBefore);

const balanceTank = (await polkadotJs.query.system.account(paraIdTank(paraId))).data.free.toBigInt();
expect(balanceTank).toBe(requiredBalance);

// Check that after 2 sessions, container chain 2000 has collators and is producing blocks
await jumpSessions(context, 2);

const collators = await polkadotJs.query.collatorAssignment.collatorContainerChain();
expect(
collators.toJSON().containerChains[paraId].length,
`Container chain ${paraId} has 0 collators`
).toBeGreaterThan(0);
expect(balanceTank).toBe(requiredBalance);
},
});
},
});

0 comments on commit b7cc9ab

Please sign in to comment.