-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2835 from s2quake/feature/dpos-with-guild
Test for DPoS with guild
- Loading branch information
Showing
11 changed files
with
1,463 additions
and
4 deletions.
There are no files selected for viewing
303 changes: 303 additions & 0 deletions
303
.Lib9c.Tests/Action/ValidatorDelegation/ClaimRewardValidatorTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,303 @@ | ||
#nullable enable | ||
namespace Lib9c.Tests.Action.ValidatorDelegation | ||
{ | ||
using System; | ||
using System.Linq; | ||
using System.Numerics; | ||
using Libplanet.Action.State; | ||
using Libplanet.Crypto; | ||
using Libplanet.Types.Assets; | ||
using Nekoyume.Action.ValidatorDelegation; | ||
using Nekoyume.ValidatorDelegation; | ||
using Xunit; | ||
|
||
public class ClaimRewardValidatorTest : ValidatorDelegationTestBase | ||
{ | ||
[Fact] | ||
public void Serialization() | ||
{ | ||
var action = new ClaimRewardValidator(); | ||
var plainValue = action.PlainValue; | ||
|
||
var deserialized = new ClaimRewardValidator(); | ||
deserialized.LoadPlainValue(plainValue); | ||
} | ||
|
||
[Fact] | ||
public void Execute() | ||
{ | ||
// Given | ||
var world = World; | ||
var validatorPrivateKey = new PrivateKey(); | ||
var blockHeight = 1L; | ||
ActionContext actionContext; | ||
var validatorGold = NCG * 10; | ||
var allocatedReward = NCG * 100; | ||
world = EnsureValidatorToBePromoted( | ||
world, validatorPrivateKey, validatorGold, blockHeight++); | ||
world = EnsureValidatorToBeAllocatedReward( | ||
world, validatorPrivateKey, allocatedReward, ref blockHeight); | ||
|
||
// When | ||
var expectedBalance = allocatedReward; | ||
var lastCommit = CreateLastCommit(validatorPrivateKey, blockHeight - 1); | ||
var claimRewardValidator = new ClaimRewardValidator(validatorPrivateKey.Address); | ||
actionContext = new ActionContext | ||
{ | ||
PreviousState = world, | ||
BlockIndex = blockHeight++, | ||
Signer = validatorPrivateKey.Address, | ||
LastCommit = lastCommit, | ||
}; | ||
world = claimRewardValidator.Execute(actionContext); | ||
|
||
// Then | ||
var actualBalance = world.GetBalance(validatorPrivateKey.Address, NCG); | ||
|
||
Assert.Equal(expectedBalance, actualBalance); | ||
} | ||
|
||
[Theory] | ||
[InlineData(33.33)] | ||
[InlineData(11.11)] | ||
[InlineData(10)] | ||
[InlineData(1)] | ||
public void Execute_OneDelegator(double reward) | ||
{ | ||
// Given | ||
var world = World; | ||
var validatorPrivateKey = new PrivateKey(); | ||
var delegatorPrivateKey = new PrivateKey(); | ||
var blockHeight = 1L; | ||
var actionContext = new ActionContext { }; | ||
var promotedGold = NCG * 10; | ||
var allocatedReward = FungibleAssetValue.Parse(NCG, $"{reward:R}"); | ||
world = EnsureValidatorToBePromoted( | ||
world, validatorPrivateKey, promotedGold, blockHeight++); | ||
world = EnsureDelegatorToBeBond( | ||
world, delegatorPrivateKey, validatorPrivateKey, NCG * 10, blockHeight++); | ||
world = EnsureValidatorToBeAllocatedReward( | ||
world, validatorPrivateKey, allocatedReward, ref blockHeight); | ||
|
||
// When | ||
var expectedRepository = new ValidatorRepository(world, actionContext); | ||
var expectedDelegatee = expectedRepository.GetValidatorDelegatee( | ||
validatorPrivateKey.Address); | ||
var expectedCommission = GetCommission( | ||
allocatedReward, expectedDelegatee.CommissionPercentage); | ||
var expectedReward = allocatedReward - expectedCommission; | ||
var expectedValidatorBalance = expectedCommission + expectedReward.DivRem(2).Quotient; | ||
var expectedDelegatorBalance = expectedReward.DivRem(2).Quotient; | ||
var expectedRemainReward = allocatedReward; | ||
expectedRemainReward -= expectedValidatorBalance; | ||
expectedRemainReward -= expectedDelegatorBalance; | ||
|
||
var lastCommit = CreateLastCommit(validatorPrivateKey, blockHeight - 1); | ||
actionContext = new ActionContext | ||
{ | ||
PreviousState = world, | ||
BlockIndex = blockHeight++, | ||
Signer = validatorPrivateKey.Address, | ||
LastCommit = lastCommit, | ||
}; | ||
world = new ClaimRewardValidator(validatorPrivateKey.Address).Execute(actionContext); | ||
actionContext = new ActionContext | ||
{ | ||
PreviousState = world, | ||
BlockIndex = blockHeight++, | ||
Signer = delegatorPrivateKey.Address, | ||
LastCommit = lastCommit, | ||
}; | ||
world = new ClaimRewardValidator(validatorPrivateKey.Address).Execute(actionContext); | ||
|
||
// Then | ||
var repository = new ValidatorRepository(world, actionContext); | ||
var delegatee = repository.GetValidatorDelegatee(validatorPrivateKey.Address); | ||
var actualRemainReward = world.GetBalance(delegatee.RewardDistributorAddress, NCG); | ||
var actualValidatorBalance = world.GetBalance(validatorPrivateKey.Address, NCG); | ||
var actualDelegatorBalance = world.GetBalance(delegatorPrivateKey.Address, NCG); | ||
|
||
Assert.Equal(expectedRemainReward, actualRemainReward); | ||
Assert.Equal(expectedValidatorBalance, actualValidatorBalance); | ||
Assert.Equal(expectedDelegatorBalance, actualDelegatorBalance); | ||
} | ||
|
||
[Fact] | ||
public void Execute_TwoDelegators() | ||
{ | ||
// Given | ||
var world = World; | ||
var validatorPrivateKey = new PrivateKey(); | ||
var delegatorPrivateKey1 = new PrivateKey(); | ||
var delegatorPrivateKey2 = new PrivateKey(); | ||
var blockHeight = 1L; | ||
var actionContext = new ActionContext { }; | ||
var promotedGold = NCG * 10; | ||
var allocatedReward = FungibleAssetValue.Parse(NCG, $"{34.27:R}"); | ||
world = EnsureValidatorToBePromoted( | ||
world, validatorPrivateKey, promotedGold, blockHeight++); | ||
world = EnsureDelegatorToBeBond( | ||
world, delegatorPrivateKey1, validatorPrivateKey, NCG * 10, blockHeight++); | ||
world = EnsureDelegatorToBeBond( | ||
world, delegatorPrivateKey2, validatorPrivateKey, NCG * 10, blockHeight++); | ||
world = EnsureValidatorToBeAllocatedReward( | ||
world, validatorPrivateKey, allocatedReward, ref blockHeight); | ||
|
||
// When | ||
var expectedRepository = new ValidatorRepository(world, actionContext); | ||
var expectedDelegatee = expectedRepository.GetValidatorDelegatee( | ||
validatorPrivateKey.Address); | ||
var expectedCommission = GetCommission( | ||
allocatedReward, expectedDelegatee.CommissionPercentage); | ||
var expectedReward = allocatedReward - expectedCommission; | ||
var expectedValidatorBalance = expectedCommission + expectedReward.DivRem(3).Quotient; | ||
var expectedDelegator1Balance = expectedReward.DivRem(3).Quotient; | ||
var expectedDelegator2Balance = expectedReward.DivRem(3).Quotient; | ||
var expectedRemainReward = allocatedReward; | ||
expectedRemainReward -= expectedValidatorBalance; | ||
expectedRemainReward -= expectedDelegator1Balance; | ||
expectedRemainReward -= expectedDelegator2Balance; | ||
|
||
var lastCommit = CreateLastCommit(validatorPrivateKey, blockHeight - 1); | ||
actionContext = new ActionContext | ||
{ | ||
PreviousState = world, | ||
BlockIndex = blockHeight++, | ||
Signer = validatorPrivateKey.Address, | ||
LastCommit = lastCommit, | ||
}; | ||
world = new ClaimRewardValidator(validatorPrivateKey.Address).Execute(actionContext); | ||
actionContext = new ActionContext | ||
{ | ||
PreviousState = world, | ||
BlockIndex = blockHeight++, | ||
Signer = delegatorPrivateKey1.Address, | ||
LastCommit = lastCommit, | ||
}; | ||
world = new ClaimRewardValidator(validatorPrivateKey.Address).Execute(actionContext); | ||
actionContext = new ActionContext | ||
{ | ||
PreviousState = world, | ||
BlockIndex = blockHeight++, | ||
Signer = delegatorPrivateKey2.Address, | ||
LastCommit = lastCommit, | ||
}; | ||
world = new ClaimRewardValidator(validatorPrivateKey.Address).Execute(actionContext); | ||
|
||
// Then | ||
var repository = new ValidatorRepository(world, actionContext); | ||
var delegatee = repository.GetValidatorDelegatee(validatorPrivateKey.Address); | ||
var actualRemainReward = world.GetBalance(delegatee.RewardDistributorAddress, NCG); | ||
var actualValidatorBalance = world.GetBalance(validatorPrivateKey.Address, NCG); | ||
var actualDelegator1Balance = world.GetBalance(delegatorPrivateKey1.Address, NCG); | ||
var actualDelegator2Balance = world.GetBalance(delegatorPrivateKey2.Address, NCG); | ||
|
||
Assert.Equal(expectedRemainReward, actualRemainReward); | ||
Assert.Equal(expectedValidatorBalance, actualValidatorBalance); | ||
Assert.Equal(expectedDelegator1Balance, actualDelegator1Balance); | ||
Assert.Equal(expectedDelegator2Balance, actualDelegator2Balance); | ||
} | ||
|
||
[Fact] | ||
public void Execute_MultipleDelegators() | ||
{ | ||
// Given | ||
var length = Random.Shared.Next(3, 100); | ||
var world = World; | ||
var validatorPrivateKey = new PrivateKey(); | ||
var delegatorPrivateKeys = GetRandomArray(length, _ => new PrivateKey()); | ||
var delegatorNCGs = GetRandomArray(length, _ => GetRandomNCG()); | ||
var blockHeight = 1L; | ||
var actionContext = new ActionContext(); | ||
var promotedGold = GetRandomNCG(); | ||
var allocatedReward = GetRandomNCG(); | ||
world = EnsureValidatorToBePromoted( | ||
world, validatorPrivateKey, promotedGold, blockHeight++); | ||
world = EnsureDelegatorsToBeBond( | ||
world, delegatorPrivateKeys, validatorPrivateKey, delegatorNCGs, blockHeight++); | ||
world = EnsureValidatorToBeAllocatedReward( | ||
world, validatorPrivateKey, allocatedReward, ref blockHeight); | ||
|
||
// When | ||
var expectedRepository = new ValidatorRepository(world, actionContext); | ||
var expectedDelegatee = expectedRepository.GetValidatorDelegatee( | ||
validatorPrivateKey.Address); | ||
var expectedCommission = GetCommission( | ||
allocatedReward, expectedDelegatee.CommissionPercentage); | ||
var expectedReward = allocatedReward - expectedCommission; | ||
var expectedValidatorBalance = expectedCommission + CalculateReward( | ||
expectedRepository, validatorPrivateKey, validatorPrivateKey, expectedReward); | ||
var expectedDelegatorBalances = CalculateRewards( | ||
expectedRepository, validatorPrivateKey, delegatorPrivateKeys, expectedReward); | ||
var expectedRemainReward = allocatedReward; | ||
expectedRemainReward -= expectedValidatorBalance; | ||
for (var i = 0; i < length; i++) | ||
{ | ||
expectedRemainReward -= expectedDelegatorBalances[i]; | ||
} | ||
|
||
var lastCommit = CreateLastCommit(validatorPrivateKey, blockHeight - 1); | ||
actionContext = new ActionContext | ||
{ | ||
PreviousState = world, | ||
BlockIndex = blockHeight++, | ||
Signer = validatorPrivateKey.Address, | ||
LastCommit = lastCommit, | ||
}; | ||
world = new ClaimRewardValidator(validatorPrivateKey.Address).Execute(actionContext); | ||
for (var i = 0; i < length; i++) | ||
{ | ||
actionContext = new ActionContext | ||
{ | ||
PreviousState = world, | ||
BlockIndex = blockHeight++, | ||
Signer = delegatorPrivateKeys[i].Address, | ||
LastCommit = lastCommit, | ||
}; | ||
world = new ClaimRewardValidator(validatorPrivateKey.Address).Execute(actionContext); | ||
} | ||
|
||
// Then | ||
var repository = new ValidatorRepository(world, actionContext); | ||
var delegatee = repository.GetValidatorDelegatee(validatorPrivateKey.Address); | ||
var actualRemainReward = world.GetBalance(delegatee.RewardDistributorAddress, NCG); | ||
var actualValidatorBalance = world.GetBalance(validatorPrivateKey.Address, NCG); | ||
Assert.Equal(expectedRemainReward, actualRemainReward); | ||
Assert.Equal(expectedValidatorBalance, actualValidatorBalance); | ||
|
||
for (var i = 0; i < length; i++) | ||
{ | ||
var actualDelegatorBalance = world.GetBalance(delegatorPrivateKeys[i].Address, NCG); | ||
Assert.Equal(expectedDelegatorBalances[i], actualDelegatorBalance); | ||
} | ||
} | ||
|
||
private static FungibleAssetValue CalculateReward( | ||
ValidatorRepository repository, | ||
PrivateKey validatorPrivateKey, | ||
PrivateKey delegatorPrivateKey, | ||
FungibleAssetValue reward) | ||
{ | ||
var delegatee = repository.GetValidatorDelegatee(validatorPrivateKey.Address); | ||
var bond = repository.GetBond(delegatee, delegatorPrivateKey.Address); | ||
return CalculateReward(reward, bond.Share, delegatee.TotalShares); | ||
} | ||
|
||
private static FungibleAssetValue[] CalculateRewards( | ||
ValidatorRepository repository, | ||
PrivateKey validatorPrivateKey, | ||
PrivateKey[] delegatorPrivateKeys, | ||
FungibleAssetValue reward) | ||
{ | ||
return delegatorPrivateKeys | ||
.Select(item => CalculateReward(repository, validatorPrivateKey, item, reward)) | ||
.ToArray(); | ||
} | ||
|
||
private static FungibleAssetValue CalculateReward( | ||
FungibleAssetValue reward, BigInteger share, BigInteger totalShares) | ||
{ | ||
return (reward * share).DivRem(totalShares).Quotient; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.