Browse Source

worker payout test implemented, minor fixes

Gleb Urvanov 4 years ago
parent
commit
3905c2c0d3

+ 10 - 1
tests/network-tests/.env

@@ -30,4 +30,13 @@ WORKING_GROUP_N = 3
 WORKING_GROUP_APPLICATION_STAKE = 10
 # Working group role stake
 WORKING_GROUP_ROLE_STAKE = 10
-
+# Reward interval for working group tests
+LONG_REWARD_INTERWAL = 99999
+# First reward interval for working group reward test
+SHORT_FIRST_REWARD_INTERWAL = 3
+# Reward interval for working group reward test
+SHORT_REWARD_INTERWAL = 3
+# Payout amount for working group tests
+PAYOUT_AMOUNT = 3
+# Mint capacity for storage working group
+STORAGE_WORKING_GROUP_MINTING_CAPACITY = 100000

+ 1 - 1
tests/network-tests/package.json

@@ -7,7 +7,7 @@
     "test": "tap --files ts-node/register src/nicaea/tests/proposals/*Test.ts --files ts-node/register src/nicaea/tests/workingGroup/*Test.ts -T",
     "test-migration-constantinople": "tap --files src/rome/tests/romeRuntimeUpgradeTest.ts --files src/constantinople/tests/electingCouncilTest.ts -T",
     "test-migration-nicaea": "tap --files src/constantinople/tests/proposals/updateRuntimeTest.ts --files src/nicaea/tests/electingCouncilTest.ts -T",
-    "debug": "tap --files src/nicaea/tests/workingGroup/workerApplicationHappyCaseTest.ts -T",
+    "debug": "tap --files src/nicaea/tests/workingGroup/workerPayout.ts -T",
     "lint": "tslint --project tsconfig.json",
     "prettier": "prettier --write ./src"
   },

+ 67 - 5
tests/network-tests/src/nicaea/tests/workingGroup/impl/workingGroupModule.ts

@@ -4,6 +4,9 @@ import { ApiWrapper } from '../../../utils/apiWrapper';
 import { KeyringPair } from '@polkadot/keyring/types';
 import { Keyring } from '@polkadot/api';
 import { v4 as uuid } from 'uuid';
+import { RewardRelationship, IRewardRelationship } from '@nicaea/types/recurring-rewards';
+import { Worker } from '@nicaea/types/working-group';
+import { Utils } from '../../../utils/utils';
 
 export async function setLead(apiWrapper: ApiWrapper, lead: KeyringPair, sudo: KeyringPair) {
   await apiWrapper.sudoSetLead(sudo, lead);
@@ -179,7 +182,10 @@ export async function fillOpening(
   membersKeyPairs: KeyringPair[],
   lead: KeyringPair,
   sudo: KeyringPair,
-  openingId: BN
+  openingId: BN,
+  firstPayoutInterval: BN,
+  payoutInterval: BN,
+  amountPerPayout: BN
 ) {
   // Fee estimation and transfer
   const beginReviewFee: BN = apiWrapper.estimateBeginApplicantReviewFee();
@@ -191,7 +197,15 @@ export async function fillOpening(
   ).flat();
 
   // Fill worker opening
-  await apiWrapper.fillOpening(lead, openingId, applicationIds, new BN(1), new BN(99999999), new BN(99999999));
+  const now: BN = await apiWrapper.getBestBlock();
+  await apiWrapper.fillOpening(
+    lead,
+    openingId,
+    applicationIds,
+    amountPerPayout,
+    now.add(firstPayoutInterval),
+    payoutInterval
+  );
 
   // Assertions
   const openingWorkersAccounts: string[] = (await apiWrapper.getWorkers()).map(worker =>
@@ -206,7 +220,10 @@ export async function fillLeaderOpening(
   apiWrapper: ApiWrapper,
   membersKeyPairs: KeyringPair[],
   sudo: KeyringPair,
-  openingId: BN
+  openingId: BN,
+  firstPayoutInterval: BN,
+  payoutInterval: BN,
+  amountPerPayout: BN
 ) {
   const applicationIds: BN[] = (
     await Promise.all(
@@ -214,8 +231,16 @@ export async function fillLeaderOpening(
     )
   ).flat();
 
-  // Fill worker opening
-  await apiWrapper.sudoFillOpening(sudo, openingId, applicationIds, new BN(1), new BN(99999999), new BN(99999999));
+  // Fill leader opening
+  const now: BN = await apiWrapper.getBestBlock();
+  await apiWrapper.sudoFillOpening(
+    sudo,
+    openingId,
+    applicationIds,
+    amountPerPayout,
+    now.add(firstPayoutInterval),
+    payoutInterval
+  );
 
   // Assertions
   const openingWorkersAccounts: string[] = (await apiWrapper.getWorkers()).map(worker =>
@@ -378,3 +403,40 @@ export async function leaveRole(apiWrapper: ApiWrapper, membersKeyPairs: Keyring
 
   await apiWrapper.batchLeaveRole(membersKeyPairs, uuid().substring(0, 8), false);
 }
+
+export async function awaitPayout(apiWrapper: ApiWrapper, membersKeyPairs: KeyringPair[]) {
+  const workerId: BN = await apiWrapper.getWorkerIdByRoleAccount(membersKeyPairs[0].address);
+  const worker: Worker = await apiWrapper.getWorker(workerId);
+  const reward: RewardRelationship = await apiWrapper.getRewardRelationship(worker.reward_relationship.unwrap());
+  const now: BN = await apiWrapper.getBestBlock();
+  const nextPaymentBlock: BN = new BN(reward.getField('next_payment_at_block').toString());
+  const payoutInterval: BN = new BN(reward.getField('payout_interval').toString());
+  const amountPerPayout: BN = new BN(reward.getField('amount_per_payout').toString());
+
+  assert(now.lt(nextPaymentBlock), `Payout already happened in block ${nextPaymentBlock} now ${now}`);
+  const balance = await apiWrapper.getBalance(membersKeyPairs[0].address);
+
+  const firstPayoutWaitingPeriod = nextPaymentBlock.sub(now).addn(1);
+  await Utils.wait(apiWrapper.getBlockDuration().mul(firstPayoutWaitingPeriod).toNumber());
+
+  const balanceAfterFirstPayout = await apiWrapper.getBalance(membersKeyPairs[0].address);
+  const expectedBalanceFirst = balance.add(amountPerPayout);
+  assert(
+    balanceAfterFirstPayout.eq(expectedBalanceFirst),
+    `Unexpected balance, expected ${expectedBalanceFirst} got ${balanceAfterFirstPayout}`
+  );
+
+  const secondPayoutWaitingPeriod = payoutInterval.addn(1);
+  await Utils.wait(apiWrapper.getBlockDuration().mul(secondPayoutWaitingPeriod).toNumber());
+
+  const balanceAfterSecondPayout = await apiWrapper.getBalance(membersKeyPairs[0].address);
+  const expectedBalanceSecond = expectedBalanceFirst.add(amountPerPayout);
+  assert(
+    balanceAfterSecondPayout.eq(expectedBalanceSecond),
+    `Unexpected balance, expected ${expectedBalanceSecond} got ${balanceAfterSecondPayout}`
+  );
+}
+
+export async function setMintCapacity(apiWrapper: ApiWrapper, sudo: KeyringPair, capacity: BN) {
+  await apiWrapper.sudoSetWorkingGroupMintCapacity(sudo, capacity);
+}

+ 20 - 4
tests/network-tests/src/nicaea/tests/workingGroup/manageWorkerAsLeadTest.ts

@@ -38,6 +38,9 @@ tap.mocha.describe('Manage worker as worker scenario', async () => {
   const sudoUri: string = process.env.SUDO_ACCOUNT_URI!;
   const applicationStake: BN = new BN(process.env.WORKING_GROUP_APPLICATION_STAKE!);
   const roleStake: BN = new BN(process.env.WORKING_GROUP_ROLE_STAKE!);
+  const firstRewardInterval: BN = new BN(process.env.LONG_REWARD_INTERWAL!);
+  const rewardInterval: BN = new BN(process.env.LONG_REWARD_INTERWAL!);
+  const payoutAmount: BN = new BN(process.env.PAYOUT_AMOUNT!);
   const durationInBlocks: number = 40;
   const openingActivationDelay: BN = new BN(0);
 
@@ -47,7 +50,7 @@ tap.mocha.describe('Manage worker as worker scenario', async () => {
 
   setTestTimeout(apiWrapper, durationInBlocks);
   membershipTest(apiWrapper, nKeyPairs, keyring, N, paidTerms, sudoUri);
-  membershipTest(apiWrapper, leadKeyPair, keyring, N, paidTerms, sudoUri);
+  membershipTest(apiWrapper, leadKeyPair, keyring, 1, paidTerms, sudoUri);
 
   let leadOpenignId: BN;
   tap.test(
@@ -67,7 +70,9 @@ tap.mocha.describe('Manage worker as worker scenario', async () => {
     async () => await applyForOpening(apiWrapper, leadKeyPair, sudo, applicationStake, roleStake, leadOpenignId, false)
   );
   tap.test('Begin lead application review', async () => beginLeaderApplicationReview(apiWrapper, sudo, leadOpenignId));
-  tap.test('Fill lead opening', async () => fillLeaderOpening(apiWrapper, leadKeyPair, sudo, leadOpenignId));
+  tap.test('Fill lead opening', async () =>
+    fillLeaderOpening(apiWrapper, leadKeyPair, sudo, leadOpenignId, firstRewardInterval, rewardInterval, payoutAmount)
+  );
 
   let openignId: BN;
   tap.test(
@@ -88,9 +93,20 @@ tap.mocha.describe('Manage worker as worker scenario', async () => {
     async () => await applyForOpening(apiWrapper, nKeyPairs, sudo, applicationStake, roleStake, openignId, false)
   );
   tap.test('Begin application review', async () => beginApplicationReview(apiWrapper, leadKeyPair[0], sudo, openignId));
-  tap.test('Fill worker opening', async () => fillOpening(apiWrapper, nKeyPairs, leadKeyPair[0], sudo, openignId));
+  tap.test('Fill worker opening', async () =>
+    fillOpening(
+      apiWrapper,
+      nKeyPairs,
+      leadKeyPair[0],
+      sudo,
+      openignId,
+      firstRewardInterval,
+      rewardInterval,
+      payoutAmount
+    )
+  );
 
-  tap.test('Unset lead', async () => unsetLead(apiWrapper, sudo));
+  tap.test('Leaving lead role', async () => leaveRole(apiWrapper, leadKeyPair, sudo));
   tap.test('Decrease worker stake, expect failure', async () =>
     decreaseStake(apiWrapper, nKeyPairs, leadKeyPair[0], sudo, true)
   );

+ 20 - 4
tests/network-tests/src/nicaea/tests/workingGroup/manageWorkerAsWorkerTest.ts

@@ -36,7 +36,10 @@ tap.mocha.describe('Manage worker as worker scenario', async () => {
   const sudoUri: string = process.env.SUDO_ACCOUNT_URI!;
   const applicationStake: BN = new BN(process.env.WORKING_GROUP_APPLICATION_STAKE!);
   const roleStake: BN = new BN(process.env.WORKING_GROUP_ROLE_STAKE!);
-  const durationInBlocks: number = 30;
+  const firstRewardInterval: BN = new BN(process.env.LONG_REWARD_INTERWAL!);
+  const rewardInterval: BN = new BN(process.env.LONG_REWARD_INTERWAL!);
+  const payoutAmount: BN = new BN(process.env.PAYOUT_AMOUNT!);
+  const durationInBlocks: number = 38;
   const openingActivationDelay: BN = new BN(0);
 
   const provider = new WsProvider(nodeUrl);
@@ -45,7 +48,7 @@ tap.mocha.describe('Manage worker as worker scenario', async () => {
 
   setTestTimeout(apiWrapper, durationInBlocks);
   membershipTest(apiWrapper, nKeyPairs, keyring, N, paidTerms, sudoUri);
-  membershipTest(apiWrapper, leadKeyPair, keyring, N, paidTerms, sudoUri);
+  membershipTest(apiWrapper, leadKeyPair, keyring, 1, paidTerms, sudoUri);
 
   let leadOpenignId: BN;
   tap.test(
@@ -65,7 +68,9 @@ tap.mocha.describe('Manage worker as worker scenario', async () => {
     async () => await applyForOpening(apiWrapper, leadKeyPair, sudo, applicationStake, roleStake, leadOpenignId, false)
   );
   tap.test('Begin lead application review', async () => beginLeaderApplicationReview(apiWrapper, sudo, leadOpenignId));
-  tap.test('Fill lead opening', async () => fillLeaderOpening(apiWrapper, leadKeyPair, sudo, leadOpenignId));
+  tap.test('Fill lead opening', async () =>
+    fillLeaderOpening(apiWrapper, leadKeyPair, sudo, leadOpenignId, firstRewardInterval, rewardInterval, payoutAmount)
+  );
 
   let openignId: BN;
   tap.test(
@@ -86,7 +91,18 @@ tap.mocha.describe('Manage worker as worker scenario', async () => {
     async () => await applyForOpening(apiWrapper, nKeyPairs, sudo, applicationStake, roleStake, openignId, false)
   );
   tap.test('Begin application review', async () => beginApplicationReview(apiWrapper, leadKeyPair[0], sudo, openignId));
-  tap.test('Fill worker opening', async () => fillOpening(apiWrapper, nKeyPairs, leadKeyPair[0], sudo, openignId));
+  tap.test('Fill worker opening', async () =>
+    fillOpening(
+      apiWrapper,
+      nKeyPairs,
+      leadKeyPair[0],
+      sudo,
+      openignId,
+      firstRewardInterval,
+      rewardInterval,
+      payoutAmount
+    )
+  );
 
   tap.test('Increase worker stake', async () => increaseStake(apiWrapper, nKeyPairs, sudo));
   tap.test('Update reward account', async () => updateRewardAccount(apiWrapper, nKeyPairs, keyring, sudo));

+ 17 - 2
tests/network-tests/src/nicaea/tests/workingGroup/workerApplicationHappyCaseTest.ts

@@ -34,6 +34,9 @@ tap.mocha.describe('Worker application happy case scenario', async () => {
   const sudoUri: string = process.env.SUDO_ACCOUNT_URI!;
   const applicationStake: BN = new BN(process.env.WORKING_GROUP_APPLICATION_STAKE!);
   const roleStake: BN = new BN(process.env.WORKING_GROUP_ROLE_STAKE!);
+  const firstRewardInterval: BN = new BN(process.env.LONG_REWARD_INTERWAL!);
+  const rewardInterval: BN = new BN(process.env.LONG_REWARD_INTERWAL!);
+  const payoutAmount: BN = new BN(process.env.PAYOUT_AMOUNT!);
   const durationInBlocks: number = 48;
   const openingActivationDelay: BN = new BN(0);
 
@@ -63,7 +66,9 @@ tap.mocha.describe('Worker application happy case scenario', async () => {
     async () => await applyForOpening(apiWrapper, leadKeyPair, sudo, applicationStake, roleStake, leadOpenignId, false)
   );
   tap.test('Begin lead application review', async () => beginLeaderApplicationReview(apiWrapper, sudo, leadOpenignId));
-  tap.test('Fill lead opening', async () => fillLeaderOpening(apiWrapper, leadKeyPair, sudo, leadOpenignId));
+  tap.test('Fill lead opening', async () =>
+    fillLeaderOpening(apiWrapper, leadKeyPair, sudo, leadOpenignId, firstRewardInterval, rewardInterval, payoutAmount)
+  );
 
   let workerOpenignId: BN;
   tap.test(
@@ -90,8 +95,18 @@ tap.mocha.describe('Worker application happy case scenario', async () => {
     beginApplicationReview(apiWrapper, leadKeyPair[0], sudo, workerOpenignId)
   );
   tap.test('Fill worker opening', async () =>
-    fillOpening(apiWrapper, nKeyPairs, leadKeyPair[0], sudo, workerOpenignId)
+    fillOpening(
+      apiWrapper,
+      nKeyPairs,
+      leadKeyPair[0],
+      sudo,
+      workerOpenignId,
+      firstRewardInterval,
+      rewardInterval,
+      payoutAmount
+    )
   );
+
   tap.test('Leaving lead role', async () => leaveRole(apiWrapper, leadKeyPair, sudo));
 
   closeApi(apiWrapper);

+ 8 - 3
tests/network-tests/src/nicaea/tests/workingGroup/workerApplicationRejectionCaseTest.ts

@@ -34,7 +34,10 @@ tap.mocha.describe('Worker application happy case scenario', async () => {
   const sudoUri: string = process.env.SUDO_ACCOUNT_URI!;
   const applicationStake: BN = new BN(process.env.WORKING_GROUP_APPLICATION_STAKE!);
   const roleStake: BN = new BN(process.env.WORKING_GROUP_ROLE_STAKE!);
-  const durationInBlocks: number = 28;
+  const firstRewardInterval: BN = new BN(process.env.LONG_REWARD_INTERWAL!);
+  const rewardInterval: BN = new BN(process.env.LONG_REWARD_INTERWAL!);
+  const payoutAmount: BN = new BN(process.env.PAYOUT_AMOUNT!);
+  const durationInBlocks: number = 38;
   const openingActivationDelay: BN = new BN(100);
 
   const provider = new WsProvider(nodeUrl);
@@ -44,7 +47,7 @@ tap.mocha.describe('Worker application happy case scenario', async () => {
 
   setTestTimeout(apiWrapper, durationInBlocks);
   membershipTest(apiWrapper, nKeyPairs, keyring, N, paidTerms, sudoUri);
-  membershipTest(apiWrapper, leadKeyPair, keyring, N, paidTerms, sudoUri);
+  membershipTest(apiWrapper, leadKeyPair, keyring, 1, paidTerms, sudoUri);
 
   let leadOpenignId: BN;
   tap.test(
@@ -64,7 +67,9 @@ tap.mocha.describe('Worker application happy case scenario', async () => {
     async () => await applyForOpening(apiWrapper, leadKeyPair, sudo, applicationStake, roleStake, leadOpenignId, false)
   );
   tap.test('Begin lead application review', async () => beginLeaderApplicationReview(apiWrapper, sudo, leadOpenignId));
-  tap.test('Fill lead opening', async () => fillLeaderOpening(apiWrapper, leadKeyPair, sudo, leadOpenignId));
+  tap.test('Fill lead opening', async () =>
+    fillLeaderOpening(apiWrapper, leadKeyPair, sudo, leadOpenignId, firstRewardInterval, rewardInterval, payoutAmount)
+  );
 
   let openignId: BN;
   tap.test(

+ 114 - 0
tests/network-tests/src/nicaea/tests/workingGroup/workerPayout.ts

@@ -0,0 +1,114 @@
+import tap from 'tap';
+import { initConfig } from '../../utils/config';
+import { registerJoystreamTypes } from '@nicaea/types';
+import { closeApi } from '../impl/closeApi';
+import { ApiWrapper } from '../../utils/apiWrapper';
+import { WsProvider, Keyring } from '@polkadot/api';
+import { KeyringPair } from '@polkadot/keyring/types';
+import { setTestTimeout } from '../../utils/setTestTimeout';
+import { membershipTest } from '../impl/membershipCreation';
+import {
+  addWorkerOpening,
+  applyForOpening,
+  beginApplicationReview,
+  fillOpening,
+  addLeaderOpening,
+  beginLeaderApplicationReview,
+  fillLeaderOpening,
+  leaveRole,
+  awaitPayout,
+  setMintCapacity,
+} from './impl/workingGroupModule';
+import BN from 'bn.js';
+
+tap.mocha.describe('Worker application happy case scenario', async () => {
+  initConfig();
+  registerJoystreamTypes();
+
+  const nKeyPairs: KeyringPair[] = new Array();
+  const leadKeyPair: KeyringPair[] = new Array();
+
+  const keyring = new Keyring({ type: 'sr25519' });
+  const N: number = +process.env.WORKING_GROUP_N!;
+  const paidTerms: number = +process.env.MEMBERSHIP_PAID_TERMS!;
+  const nodeUrl: string = process.env.NODE_URL!;
+  const sudoUri: string = process.env.SUDO_ACCOUNT_URI!;
+  const applicationStake: BN = new BN(process.env.WORKING_GROUP_APPLICATION_STAKE!);
+  const roleStake: BN = new BN(process.env.WORKING_GROUP_ROLE_STAKE!);
+  const firstRewardInterval: BN = new BN(process.env.SHORT_FIRST_REWARD_INTERWAL!);
+  const rewardInterval: BN = new BN(process.env.SHORT_REWARD_INTERWAL!);
+  const payoutAmount: BN = new BN(process.env.PAYOUT_AMOUNT!);
+  const mintCapacity: BN = new BN(process.env.STORAGE_WORKING_GROUP_MINTING_CAPACITY!);
+  const durationInBlocks: number = 48;
+  const openingActivationDelay: BN = new BN(0);
+
+  const provider = new WsProvider(nodeUrl);
+  const apiWrapper: ApiWrapper = await ApiWrapper.create(provider);
+  const sudo: KeyringPair = keyring.addFromUri(sudoUri);
+
+  setTestTimeout(apiWrapper, durationInBlocks);
+  membershipTest(apiWrapper, nKeyPairs, keyring, N, paidTerms, sudoUri);
+  membershipTest(apiWrapper, leadKeyPair, keyring, 1, paidTerms, sudoUri);
+
+  let leadOpenignId: BN;
+  tap.test(
+    'Add lead opening',
+    async () =>
+      (leadOpenignId = await addLeaderOpening(
+        apiWrapper,
+        nKeyPairs,
+        sudo,
+        applicationStake,
+        roleStake,
+        openingActivationDelay
+      ))
+  );
+  tap.test(
+    'Apply for lead opening',
+    async () => await applyForOpening(apiWrapper, leadKeyPair, sudo, applicationStake, roleStake, leadOpenignId, false)
+  );
+  tap.test('Begin lead application review', async () => beginLeaderApplicationReview(apiWrapper, sudo, leadOpenignId));
+  tap.test('Fill lead opening', async () =>
+    fillLeaderOpening(apiWrapper, leadKeyPair, sudo, leadOpenignId, firstRewardInterval, rewardInterval, payoutAmount)
+  );
+
+  let workerOpenignId: BN;
+  tap.test(
+    'Add worker opening',
+    async () =>
+      (workerOpenignId = await addWorkerOpening(
+        apiWrapper,
+        nKeyPairs,
+        leadKeyPair[0],
+        sudo,
+        applicationStake,
+        roleStake,
+        openingActivationDelay
+      ))
+  );
+  tap.test('Apply for worker opening', async () =>
+    applyForOpening(apiWrapper, nKeyPairs, sudo, applicationStake, roleStake, workerOpenignId, false)
+  );
+  tap.test('Begin application review', async () =>
+    beginApplicationReview(apiWrapper, leadKeyPair[0], sudo, workerOpenignId)
+  );
+  tap.test('Set mint capacity', async () => setMintCapacity(apiWrapper, sudo, mintCapacity));
+  tap.test('Fill worker opening', async () =>
+    fillOpening(
+      apiWrapper,
+      nKeyPairs,
+      leadKeyPair[0],
+      sudo,
+      workerOpenignId,
+      firstRewardInterval,
+      rewardInterval,
+      payoutAmount
+    )
+  );
+
+  tap.test('Await worker payout', async () => awaitPayout(apiWrapper, nKeyPairs));
+
+  tap.test('Leaving lead role', async () => leaveRole(apiWrapper, leadKeyPair, sudo));
+
+  closeApi(apiWrapper);
+});

+ 8 - 0
tests/network-tests/src/nicaea/utils/apiWrapper.ts

@@ -416,6 +416,14 @@ export class ApiWrapper {
     );
   }
 
+  public sudoSetWorkingGroupMintCapacity(sudo: KeyringPair, capacity: BN): Promise<void> {
+    return this.sender.signAndSend(
+      this.api.tx.sudo.sudo(this.api.tx.storageWorkingGroup.setMintCapacity(capacity)),
+      sudo,
+      false
+    );
+  }
+
   public getBestBlock(): Promise<BN> {
     return this.api.derive.chain.bestNumber();
   }