Преглед изворни кода

decrease stake and slash leader proposal tests impelemented

Gleb Urvanov пре 4 година
родитељ
комит
7abd21c956

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

@@ -44,3 +44,7 @@ ALTERED_PAYOUT_AMOUNT = 7
 STORAGE_WORKING_GROUP_MINTING_CAPACITY = 100000
 # Default unstaking period for storage working group
 STORAGE_WORKING_GROUP_UNSTAKING_PERIOD = 1
+# Slash value for manage working group lead testing scenario
+SLASH_AMOUNT = 2
+# Stake decrement amount for manage working group lead testing scenario
+STAKE_DECREMENT = 3

+ 72 - 5
tests/network-tests/src/nicaea/tests/proposals/impl/proposalsModule.ts

@@ -19,7 +19,7 @@ export async function createWorkingGroupLeaderOpening(
 
   // Proposal stake calculation
   const proposalStake: BN = new BN(100000);
-  const proposalFee: BN = apiWrapper.estimateProposeCreateWorkingGroupLeaderOpening();
+  const proposalFee: BN = apiWrapper.estimateProposeCreateWorkingGroupLeaderOpeningFee();
   await apiWrapper.transferBalance(sudo, m1KeyPairs[0].address, proposalFee.add(proposalStake));
 
   // Opening construction
@@ -70,7 +70,7 @@ export async function beginWorkingGroupLeaderApplicationReview(
 
   // Proposal stake calculation
   const proposalStake: BN = new BN(25000);
-  const proposalFee: BN = apiWrapper.estimateProposeBeginWorkingGroupLeaderApplicationReview();
+  const proposalFee: BN = apiWrapper.estimateProposeBeginWorkingGroupLeaderApplicationReviewFee();
   await apiWrapper.transferBalance(sudo, m1KeyPairs[0].address, proposalFee.add(proposalStake));
 
   // Proposal creation
@@ -105,7 +105,7 @@ export async function fillLeaderOpeningProposal(
 
   // Proposal stake calculation
   const proposalStake: BN = new BN(50000);
-  const proposalFee: BN = apiWrapper.estimateProposeFillLeaderOpening();
+  const proposalFee: BN = apiWrapper.estimateProposeFillLeaderOpeningFee();
   await apiWrapper.transferBalance(sudo, m1KeyPairs[0].address, proposalFee.add(proposalStake));
 
   // Proposal creation
@@ -150,7 +150,7 @@ export async function terminateLeaderRoleProposal(
 
   // Proposal stake calculation
   const proposalStake: BN = new BN(100000);
-  const proposalFee: BN = apiWrapper.estimateProposeTerminateLeaderRole();
+  const proposalFee: BN = apiWrapper.estimateProposeTerminateLeaderRoleFee();
   await apiWrapper.transferBalance(sudo, m1KeyPairs[0].address, proposalFee.add(proposalStake));
 
   // Proposal creation
@@ -184,9 +184,10 @@ export async function setLeaderRewardProposal(
 
   // Proposal stake calculation
   const proposalStake: BN = new BN(50000);
-  const proposalFee: BN = apiWrapper.estimateProposeLeaderReward();
+  const proposalFee: BN = apiWrapper.estimateProposeLeaderRewardFee();
   await apiWrapper.transferBalance(sudo, m1KeyPairs[0].address, proposalFee.add(proposalStake));
 
+  // Proposal creation
   const proposalPromise = apiWrapper.expectProposalCreated();
   await apiWrapper.proposeLeaderReward(
     m1KeyPairs[0],
@@ -201,6 +202,72 @@ export async function setLeaderRewardProposal(
   return proposalNumber;
 }
 
+export async function decreaseLeaderStakeProposal(
+  apiWrapper: ApiWrapper,
+  m1KeyPairs: KeyringPair[],
+  sudo: KeyringPair,
+  stakeDecrement: BN,
+  workingGroup: WorkingGroups
+): Promise<BN> {
+  // Setup
+  const proposalTitle: string = 'Testing proposal ' + uuid().substring(0, 8);
+  const description: string = 'Testing decrease leader stake 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.estimateProposeDecreaseLeaderStakeFee();
+  await apiWrapper.transferBalance(sudo, m1KeyPairs[0].address, proposalFee.add(proposalStake));
+
+  // Proposal creation
+  const proposalPromise = apiWrapper.expectProposalCreated();
+  await apiWrapper.proposeDecreaseLeaderStake(
+    m1KeyPairs[0],
+    proposalTitle,
+    description,
+    proposalStake,
+    workerId,
+    stakeDecrement,
+    workingGroupString
+  );
+  const proposalNumber: BN = await proposalPromise;
+  return proposalNumber;
+}
+
+export async function slashLeaderProposal(
+  apiWrapper: ApiWrapper,
+  m1KeyPairs: KeyringPair[],
+  sudo: KeyringPair,
+  slashAmount: BN,
+  workingGroup: WorkingGroups
+): Promise<BN> {
+  // Setup
+  const proposalTitle: string = 'Testing proposal ' + uuid().substring(0, 8);
+  const description: string = 'Testing slash leader stake 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.estimateProposeSlashLeaderStakeFee();
+  await apiWrapper.transferBalance(sudo, m1KeyPairs[0].address, proposalFee.add(proposalStake));
+
+  // Proposal creation
+  const proposalPromise = apiWrapper.expectProposalCreated();
+  await apiWrapper.proposeSlashLeaderStake(
+    m1KeyPairs[0],
+    proposalTitle,
+    description,
+    proposalStake,
+    workerId,
+    slashAmount,
+    workingGroupString
+  );
+  const proposalNumber: BN = await proposalPromise;
+  return proposalNumber;
+}
+
 export async function voteForProposal(
   apiWrapper: ApiWrapper,
   m2KeyPairs: KeyringPair[],

+ 44 - 1
tests/network-tests/src/nicaea/tests/proposals/manageLeaderRole.ts

@@ -16,6 +16,8 @@ import {
   fillLeaderOpeningProposal,
   terminateLeaderRoleProposal,
   setLeaderRewardProposal,
+  decreaseLeaderStakeProposal,
+  slashLeaderProposal,
 } from './impl/proposalsModule';
 import {
   applyForOpening,
@@ -24,6 +26,8 @@ import {
   expectBeganApplicationReview,
   expectLeaderRoleTerminated,
   expectLeaderRewardAmountUpdated,
+  expectLeaderStakeDecreased,
+  expectLeaderSlashed,
 } from '../workingGroup/impl/workingGroupModule';
 
 tap.mocha.describe('Set lead proposal scenario', async () => {
@@ -48,7 +52,9 @@ tap.mocha.describe('Set lead proposal scenario', async () => {
   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 stakeDecrement: BN = new BN(process.env.STAKE_DECREMENT!);
+  const slashAmount: BN = new BN(process.env.SLASH_AMOUNT!);
+  const durationInBlocks: number = 70;
 
   const provider = new WsProvider(nodeUrl);
   const apiWrapper: ApiWrapper = await ApiWrapper.create(provider);
@@ -148,6 +154,43 @@ tap.mocha.describe('Set lead proposal scenario', async () => {
     await expectLeaderRewardAmountUpdated(apiWrapper, alteredPayoutAmount, WorkingGroups.storageWorkingGroup);
   });
 
+  let decreaseStakeProposalId: BN;
+  let newStake: BN;
+  tap.test(
+    'Propose decrease stake',
+    async () =>
+      (decreaseStakeProposalId = await decreaseLeaderStakeProposal(
+        apiWrapper,
+        m1KeyPairs,
+        sudo,
+        stakeDecrement,
+        WorkingGroups.storageWorkingGroup
+      ))
+  );
+  tap.test('Approve decreased leader stake', async () => {
+    newStake = applicationStake.sub(stakeDecrement);
+    voteForProposal(apiWrapper, m2KeyPairs, sudo, decreaseStakeProposalId);
+    await expectLeaderStakeDecreased(apiWrapper, newStake, WorkingGroups.storageWorkingGroup);
+  });
+
+  let slashProposalId: BN;
+  tap.test(
+    'Propose leader slash',
+    async () =>
+      (slashProposalId = await slashLeaderProposal(
+        apiWrapper,
+        m1KeyPairs,
+        sudo,
+        slashAmount,
+        WorkingGroups.storageWorkingGroup
+      ))
+  );
+  tap.test('Approve leader slash', async () => {
+    newStake = newStake.sub(slashAmount);
+    voteForProposal(apiWrapper, m2KeyPairs, sudo, slashProposalId);
+    await expectLeaderSlashed(apiWrapper, newStake, WorkingGroups.storageWorkingGroup);
+  });
+
   let terminateLeaderRoleProposalId: BN;
   tap.test(
     'Propose terminate leader role',

+ 30 - 0
tests/network-tests/src/nicaea/tests/workingGroup/impl/workingGroupModule.ts

@@ -552,3 +552,33 @@ export async function expectLeaderRewardAmountUpdated(
   );
   return;
 }
+
+export async function expectLeaderStakeDecreased(
+  apiWrapper: ApiWrapper,
+  expectedStake: BN,
+  module: WorkingGroups
+): Promise<void> {
+  await apiWrapper.expectWorkerStakeDecreased();
+  const leadWorkerId: BN = (await apiWrapper.getLeadWorkerId(module))!;
+  const receivedStake: BN = await apiWrapper.getWorkerStakeAmount(leadWorkerId, module);
+  assert(
+    receivedStake.eq(expectedStake),
+    `Unexpected stake amount for worker with id ${leadWorkerId}: ${receivedStake}, expected ${expectedStake}`
+  );
+  return;
+}
+
+export async function expectLeaderSlashed(
+  apiWrapper: ApiWrapper,
+  expectedStake: BN,
+  module: WorkingGroups
+): Promise<void> {
+  await apiWrapper.expectWorkerStakeSlashed();
+  const leadWorkerId: BN = (await apiWrapper.getLeadWorkerId(module))!;
+  const receivedStake: BN = await apiWrapper.getWorkerStakeAmount(leadWorkerId, module);
+  assert(
+    receivedStake.eq(expectedStake),
+    `Unexpected stake amount for worker with id after slash ${leadWorkerId}: ${receivedStake}, expected ${expectedStake}`
+  );
+  return;
+}

+ 107 - 5
tests/network-tests/src/nicaea/utils/apiWrapper.ts

@@ -320,7 +320,7 @@ export class ApiWrapper {
     );
   }
 
-  public estimateProposeCreateWorkingGroupLeaderOpening(): BN {
+  public estimateProposeCreateWorkingGroupLeaderOpeningFee(): BN {
     return this.estimateTxFee(
       this.api.tx.proposalsCodex.createAddWorkingGroupLeaderOpeningProposal(
         0,
@@ -365,7 +365,7 @@ export class ApiWrapper {
     );
   }
 
-  public estimateProposeBeginWorkingGroupLeaderApplicationReview(): BN {
+  public estimateProposeBeginWorkingGroupLeaderApplicationReviewFee(): BN {
     return this.estimateTxFee(
       this.api.tx.proposalsCodex.createBeginReviewWorkingGroupLeaderApplicationsProposal(
         0,
@@ -378,7 +378,7 @@ export class ApiWrapper {
     );
   }
 
-  public estimateProposeFillLeaderOpening(): BN {
+  public estimateProposeFillLeaderOpeningFee(): BN {
     const fillOpeningParameters: FillOpeningParameters = new FillOpeningParameters();
     fillOpeningParameters.setAmountPerPayout(new BN(1));
     fillOpeningParameters.setNextPaymentAtBlock(new BN(99999));
@@ -398,7 +398,7 @@ export class ApiWrapper {
     );
   }
 
-  public estimateProposeTerminateLeaderRole(): BN {
+  public estimateProposeTerminateLeaderRoleFee(): BN {
     return this.estimateTxFee(
       this.api.tx.proposalsCodex.createTerminateWorkingGroupLeaderRoleProposal(
         0,
@@ -415,7 +415,7 @@ export class ApiWrapper {
     );
   }
 
-  public estimateProposeLeaderReward(): BN {
+  public estimateProposeLeaderRewardFee(): BN {
     return this.estimateTxFee(
       this.api.tx.proposalsCodex.createSetWorkingGroupLeaderRewardProposal(
         0,
@@ -429,6 +429,34 @@ export class ApiWrapper {
     );
   }
 
+  public estimateProposeDecreaseLeaderStakeFee(): BN {
+    return this.estimateTxFee(
+      this.api.tx.proposalsCodex.createDecreaseWorkingGroupLeaderStakeProposal(
+        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'
+      )
+    );
+  }
+
+  public estimateProposeSlashLeaderStakeFee(): BN {
+    return this.estimateTxFee(
+      this.api.tx.proposalsCodex.createSlashWorkingGroupLeaderStakeProposal(
+        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);
   }
@@ -860,6 +888,30 @@ export class ApiWrapper {
     });
   }
 
+  public expectWorkerStakeDecreased(): 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() === 'StakeDecreased') {
+            resolve();
+          }
+        });
+      });
+    });
+  }
+
+  public expectWorkerStakeSlashed(): 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() === 'StakeSlashed') {
+            resolve();
+          }
+        });
+      });
+    });
+  }
+
   public expectApplicationReviewBegan(): Promise<BN> {
     return new Promise(async resolve => {
       await this.api.query.system.events<Vec<EventRecord>>(events => {
@@ -1038,6 +1090,56 @@ export class ApiWrapper {
     );
   }
 
+  public async proposeDecreaseLeaderStake(
+    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.createDecreaseWorkingGroupLeaderStakeProposal(
+        memberId,
+        title,
+        description,
+        proposalStake,
+        workerId,
+        rewardAmount,
+        workingGroup
+      ),
+      account,
+      false
+    );
+  }
+
+  public async proposeSlashLeaderStake(
+    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.createSlashWorkingGroupLeaderStakeProposal(
+        memberId,
+        title,
+        description,
+        proposalStake,
+        workerId,
+        rewardAmount,
+        workingGroup
+      ),
+      account,
+      false
+    );
+  }
+
   private createAddOpeningTransaction(
     opening: WorkingGroupOpening,
     module: WorkingGroups