Ver código fonte

set leader reward proposal implemented

Gleb Urvanov 4 anos atrás
pai
commit
964935636d

+ 2 - 0
tests/network-tests/.env

@@ -38,6 +38,8 @@ SHORT_FIRST_REWARD_INTERVAL = 3
 SHORT_REWARD_INTERVAL = 3
 # Payout amount for working group tests
 PAYOUT_AMOUNT = 3
+# Payout amount for leader-related proposals tests
+ALTERED_PAYOUT_AMOUNT = 7
 # Mint capacity for storage working group
 STORAGE_WORKING_GROUP_MINTING_CAPACITY = 100000
 # Default unstaking period for storage working group

+ 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/proposals/leaderHiringHappyCase.ts -T",
+    "debug": "tap --files src/nicaea/tests/proposals/manageLeaderRole.ts -T",
     "lint": "tslint --project tsconfig.json",
     "prettier": "prettier --write ./src"
   },

+ 32 - 0
tests/network-tests/src/nicaea/tests/proposals/impl/proposalsModule.ts

@@ -169,6 +169,38 @@ export async function terminateLeaderRoleProposal(
   return proposalNumber;
 }
 
+export async function setLeaderRewardProposal(
+  apiWrapper: ApiWrapper,
+  m1KeyPairs: KeyringPair[],
+  sudo: KeyringPair,
+  payoutAmount: BN,
+  workingGroup: WorkingGroups
+): Promise<BN> {
+  // Setup
+  const proposalTitle: string = 'Testing proposal ' + uuid().substring(0, 8);
+  const description: string = 'Testing set leader reward proposal ' + uuid().substring(0, 8);
+  const workingGroupString: string = apiWrapper.getWorkingGroupString(workingGroup);
+  const workerId: BN = (await apiWrapper.getLeadWorkerId(workingGroup))!;
+
+  // Proposal stake calculation
+  const proposalStake: BN = new BN(50000);
+  const proposalFee: BN = apiWrapper.estimateProposeLeaderReward();
+  await apiWrapper.transferBalance(sudo, m1KeyPairs[0].address, proposalFee.add(proposalStake));
+
+  const proposalPromise = apiWrapper.expectProposalCreated();
+  await apiWrapper.proposeLeaderReward(
+    m1KeyPairs[0],
+    proposalTitle,
+    description,
+    proposalStake,
+    workerId,
+    payoutAmount,
+    workingGroupString
+  );
+  const proposalNumber: BN = await proposalPromise;
+  return proposalNumber;
+}
+
 export async function voteForProposal(
   apiWrapper: ApiWrapper,
   m2KeyPairs: KeyringPair[],

+ 170 - 0
tests/network-tests/src/nicaea/tests/proposals/manageLeaderRole.ts

@@ -0,0 +1,170 @@
+import { KeyringPair } from '@polkadot/keyring/types';
+import { membershipTest } from '../impl/membershipCreation';
+import { councilTest } from '../impl/electingCouncil';
+import { initConfig } from '../../utils/config';
+import { Keyring, WsProvider } from '@polkadot/api';
+import BN from 'bn.js';
+import { setTestTimeout } from '../../utils/setTestTimeout';
+import tap from 'tap';
+import { registerJoystreamTypes } from '@nicaea/types';
+import { closeApi } from '../impl/closeApi';
+import { ApiWrapper, WorkingGroups } from '../../utils/apiWrapper';
+import {
+  createWorkingGroupLeaderOpening,
+  voteForProposal,
+  beginWorkingGroupLeaderApplicationReview,
+  fillLeaderOpeningProposal,
+  terminateLeaderRoleProposal,
+  setLeaderRewardProposal,
+} from './impl/proposalsModule';
+import {
+  applyForOpening,
+  expectLeadOpeningAdded,
+  expectLeaderSet,
+  expectBeganApplicationReview,
+  expectLeaderRoleTerminated,
+  expectLeaderRewardAmountUpdated,
+} from '../workingGroup/impl/workingGroupModule';
+
+tap.mocha.describe('Set lead proposal scenario', async () => {
+  initConfig();
+  registerJoystreamTypes();
+
+  const m1KeyPairs: KeyringPair[] = new Array();
+  const m2KeyPairs: KeyringPair[] = new Array();
+  const leadKeyPair: KeyringPair[] = new Array();
+
+  const keyring = new Keyring({ type: 'sr25519' });
+  const N: number = +process.env.MEMBERSHIP_CREATION_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 K: number = +process.env.COUNCIL_ELECTION_K!;
+  const greaterStake: BN = new BN(+process.env.COUNCIL_STAKE_GREATER_AMOUNT!);
+  const lesserStake: BN = new BN(+process.env.COUNCIL_STAKE_LESSER_AMOUNT!);
+  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_INTERVAL!);
+  const rewardInterval: BN = new BN(process.env.LONG_REWARD_INTERVAL!);
+  const payoutAmount: BN = new BN(process.env.PAYOUT_AMOUNT!);
+  const alteredPayoutAmount: BN = new BN(process.env.ALTERED_PAYOUT_AMOUNT!);
+  const durationInBlocks: number = 60;
+
+  const provider = new WsProvider(nodeUrl);
+  const apiWrapper: ApiWrapper = await ApiWrapper.create(provider);
+  const sudo: KeyringPair = keyring.addFromUri(sudoUri);
+
+  setTestTimeout(apiWrapper, durationInBlocks);
+  membershipTest(apiWrapper, m1KeyPairs, keyring, N, paidTerms, sudoUri);
+  membershipTest(apiWrapper, m2KeyPairs, keyring, N, paidTerms, sudoUri);
+  membershipTest(apiWrapper, leadKeyPair, keyring, 1, paidTerms, sudoUri);
+  councilTest(apiWrapper, m1KeyPairs, m2KeyPairs, keyring, K, sudoUri, greaterStake, lesserStake);
+
+  let createOpeningProposalId: BN;
+  let openingId: BN;
+  tap.test(
+    'Propose create leader opening',
+    async () =>
+      (createOpeningProposalId = await createWorkingGroupLeaderOpening(
+        apiWrapper,
+        m1KeyPairs,
+        sudo,
+        applicationStake,
+        roleStake,
+        'Storage'
+      ))
+  );
+  tap.test('Approve add opening proposal', async () => {
+    voteForProposal(apiWrapper, m2KeyPairs, sudo, createOpeningProposalId);
+    openingId = await expectLeadOpeningAdded(apiWrapper);
+  });
+
+  tap.test(
+    'Apply for lead opening',
+    async () =>
+      await applyForOpening(
+        apiWrapper,
+        leadKeyPair,
+        sudo,
+        applicationStake,
+        roleStake,
+        new BN(openingId),
+        WorkingGroups.storageWorkingGroup,
+        false
+      )
+  );
+  let beginReviewProposalId: BN;
+  tap.test(
+    'Propose begin leader application review',
+    async () =>
+      (beginReviewProposalId = await beginWorkingGroupLeaderApplicationReview(
+        apiWrapper,
+        m1KeyPairs,
+        sudo,
+        new BN(openingId),
+        'Storage'
+      ))
+  );
+  tap.test('Approve begin review proposal', async () => {
+    voteForProposal(apiWrapper, m2KeyPairs, sudo, beginReviewProposalId);
+    expectBeganApplicationReview(apiWrapper);
+  });
+
+  let fillLeaderOpeningProposalId: BN;
+  tap.test(
+    'Propose fill leader opening',
+    async () =>
+      (fillLeaderOpeningProposalId = await fillLeaderOpeningProposal(
+        apiWrapper,
+        m1KeyPairs,
+        leadKeyPair[0].address,
+        sudo,
+        firstRewardInterval,
+        rewardInterval,
+        payoutAmount,
+        new BN(openingId),
+        WorkingGroups.storageWorkingGroup
+      ))
+  );
+  tap.test('Approve fill leader opening', async () => {
+    voteForProposal(apiWrapper, m2KeyPairs, sudo, fillLeaderOpeningProposalId);
+    await expectLeaderSet(apiWrapper, leadKeyPair[0].address, WorkingGroups.storageWorkingGroup);
+  });
+
+  let rewardProposalId: BN;
+  tap.test(
+    'Propose leader reward',
+    async () =>
+      (rewardProposalId = await setLeaderRewardProposal(
+        apiWrapper,
+        m1KeyPairs,
+        sudo,
+        alteredPayoutAmount,
+        WorkingGroups.storageWorkingGroup
+      ))
+  );
+  tap.test('Approve new leader reward', async () => {
+    voteForProposal(apiWrapper, m2KeyPairs, sudo, rewardProposalId);
+    await expectLeaderRewardAmountUpdated(apiWrapper, alteredPayoutAmount, WorkingGroups.storageWorkingGroup);
+  });
+
+  let terminateLeaderRoleProposalId: BN;
+  tap.test(
+    'Propose terminate leader role',
+    async () =>
+      (terminateLeaderRoleProposalId = await terminateLeaderRoleProposal(
+        apiWrapper,
+        m1KeyPairs,
+        leadKeyPair[0].address,
+        sudo,
+        false,
+        WorkingGroups.storageWorkingGroup
+      ))
+  );
+  tap.test('Approve leader role termination', async () => {
+    voteForProposal(apiWrapper, m2KeyPairs, sudo, terminateLeaderRoleProposalId);
+    await expectLeaderRoleTerminated(apiWrapper, WorkingGroups.storageWorkingGroup);
+  });
+
+  closeApi(apiWrapper);
+});

+ 19 - 1
tests/network-tests/src/nicaea/tests/workingGroup/impl/workingGroupModule.ts

@@ -2,6 +2,7 @@ import BN from 'bn.js';
 import { assert } from 'chai';
 import { ApiWrapper, WorkingGroups } from '../../../utils/apiWrapper';
 import { KeyringPair } from '@polkadot/keyring/types';
+import { Balance } from '@polkadot/types/interfaces';
 import { Keyring } from '@polkadot/api';
 import { v4 as uuid } from 'uuid';
 import { RewardRelationship } from '@nicaea/types/recurring-rewards';
@@ -529,8 +530,25 @@ export async function expectBeganApplicationReview(apiWrapper: ApiWrapper): Prom
 }
 
 export async function expectLeaderRoleTerminated(apiWrapper: ApiWrapper, module: WorkingGroups): Promise<void> {
-  await apiWrapper.expectLeaderUnset();
+  await apiWrapper.expectLeaderTerminated();
   const leadWorkerId: BN | undefined = await apiWrapper.getLeadWorkerId(module);
   assert(leadWorkerId === undefined, `Unexpected lead worker id: ${leadWorkerId}, expected none`);
   return;
 }
+
+export async function expectLeaderRewardAmountUpdated(
+  apiWrapper: ApiWrapper,
+  expectedReward: BN,
+  module: WorkingGroups
+): Promise<void> {
+  await apiWrapper.expectWorkerRewardAmountUpdated();
+  const leadWorkerId: BN = (await apiWrapper.getLeadWorkerId(module))!;
+  const receivedReward: BN = (await apiWrapper.getRewardRelationship(leadWorkerId)).getField<Balance>(
+    'amount_per_payout'
+  );
+  assert(
+    receivedReward.eq(expectedReward),
+    `Unexpected reward amount for worker with id ${leadWorkerId}: ${receivedReward}, expected ${expectedReward}`
+  );
+  return;
+}

+ 53 - 2
tests/network-tests/src/nicaea/utils/apiWrapper.ts

@@ -415,6 +415,20 @@ export class ApiWrapper {
     );
   }
 
+  public estimateProposeLeaderReward(): BN {
+    return this.estimateTxFee(
+      this.api.tx.proposalsCodex.createSetWorkingGroupLeaderRewardProposal(
+        0,
+        'Some testing text used for estimation purposes which is longer than text expected during the test',
+        'Some testing text used for estimation purposes which is longer than text expected during the test',
+        0,
+        0,
+        0,
+        'Storage'
+      )
+    );
+  }
+
   private applyForCouncilElection(account: KeyringPair, amount: BN): Promise<void> {
     return this.sender.signAndSend(this.api.tx.councilElection.apply(amount), account, false);
   }
@@ -822,11 +836,23 @@ export class ApiWrapper {
     });
   }
 
-  public expectLeaderUnset(): Promise<void> {
+  public expectLeaderTerminated(): Promise<void> {
+    return new Promise(async resolve => {
+      await this.api.query.system.events<Vec<EventRecord>>(events => {
+        events.forEach(record => {
+          if (record.event.method && record.event.method.toString() === 'TerminatedLeader') {
+            resolve();
+          }
+        });
+      });
+    });
+  }
+
+  public expectWorkerRewardAmountUpdated(): Promise<void> {
     return new Promise(async resolve => {
       await this.api.query.system.events<Vec<EventRecord>>(events => {
         events.forEach(record => {
-          if (record.event.method && record.event.method.toString() === 'LeaderUnset') {
+          if (record.event.method && record.event.method.toString() === 'WorkerRewardAmountUpdated') {
             resolve();
           }
         });
@@ -987,6 +1013,31 @@ export class ApiWrapper {
     );
   }
 
+  public async proposeLeaderReward(
+    account: KeyringPair,
+    title: string,
+    description: string,
+    proposalStake: BN,
+    workerId: BN,
+    rewardAmount: BN,
+    workingGroup: string
+  ): Promise<void> {
+    const memberId: BN = (await this.getMemberIds(account.address))[0];
+    return this.sender.signAndSend(
+      this.api.tx.proposalsCodex.createSetWorkingGroupLeaderRewardProposal(
+        memberId,
+        title,
+        description,
+        proposalStake,
+        workerId,
+        rewardAmount,
+        workingGroup
+      ),
+      account,
+      false
+    );
+  }
+
   private createAddOpeningTransaction(
     opening: WorkingGroupOpening,
     module: WorkingGroups