Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix distribution with RewardBase #3086

Merged
merged 32 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d9e9a5e
fix: Only a validator can change the commission
s2quake Dec 5, 2024
3ac6d2b
test: Fix test failure for commission change action
s2quake Dec 5, 2024
d36fb9b
fix: A validator can stake whether it is claimable or not.
s2quake Dec 5, 2024
96fa908
test: Test code for validator staking
s2quake Dec 5, 2024
93f810e
fix: The validator cannot claim the stake reward
s2quake Dec 6, 2024
af418fe
test: Test code for a validator claims the stake reward
s2quake Dec 6, 2024
0d5299d
fix: Cannot set commission with the same value
s2quake Dec 9, 2024
66b1d57
test: Test code for SetValidatorCommission action
s2quake Dec 9, 2024
7ea81ce
feat: Introduce RewardBase
OnedgeLee Dec 4, 2024
0964d90
feat: Implement Getter and Setter for RewardBase
OnedgeLee Dec 5, 2024
e1f0e4d
feat: Make use of RewardBase
OnedgeLee Dec 9, 2024
8b19125
fix: Fix to return null when RewardBase not exists
OnedgeLee Dec 9, 2024
00cc540
fix: Fix malfunctions for RewardBase
OnedgeLee Dec 10, 2024
a176e91
fix: Malfunctions for reward
OnedgeLee Dec 10, 2024
3131722
test: Fix tests for rewards
OnedgeLee Dec 10, 2024
ea242b5
fix: Reward migration
OnedgeLee Dec 10, 2024
b408d1d
test: Add reward migration test
OnedgeLee Dec 10, 2024
c2d6966
chore: Redefine RewardBase.Margin as a constant
OnedgeLee Dec 10, 2024
8d5f9f5
chore: Fix Equals for RewardBase
OnedgeLee Dec 10, 2024
0d10efa
fix: Fix Migration to skip set RewardBase when not needed
OnedgeLee Dec 11, 2024
77605bf
doc: Add docstrings for RewardBase
OnedgeLee Dec 11, 2024
107f1ad
fix: Fix bug for zero-transfer
OnedgeLee Dec 12, 2024
4f8a3b7
chore: Apply reviews for better structure.
OnedgeLee Dec 12, 2024
8b5e42c
chore: Fix RewardBase to use BigInteger instead of FAV
OnedgeLee Dec 12, 2024
e58e468
chore: Change MaxAbstainAllowance to 9
OnedgeLee Dec 12, 2024
e64a0bf
fix: ReleaseUnbondings to set unbondings properly
OnedgeLee Dec 12, 2024
d60a473
chore: Rename parameter name as camelCase
OnedgeLee Dec 12, 2024
86b8103
test: Fix reward calculation test method
OnedgeLee Dec 12, 2024
e0f4cb0
fix: Fix release unbondings to update unbonding list
OnedgeLee Dec 13, 2024
815fa51
refactor: Refactor RewardBase not to store TotalShares
OnedgeLee Dec 13, 2024
04db96d
doc: Add documents for new features
OnedgeLee Dec 13, 2024
2c67f64
chore: Fix typo
OnedgeLee Dec 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .Lib9c.Tests/Action/ClaimStakeRewardTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,35 @@ public void Execute_V6()
}
}

[Fact]
public void Execute_Throw_When_Validator_Tries_To_Claim()
{
// When
var world = _initialState;
var validatorKey = new PrivateKey().PublicKey;
var validatorAddress = validatorKey.Address;
var height = 0L;
world = DelegationUtil.EnsureValidatorPromotionReady(world, validatorKey, height);
var stakeAddr = StakeState.DeriveAddress(AgentAddr);
var stakeStateV2 = PrepareStakeStateV2(
_stakePolicySheet,
0,
LegacyStakeState.RewardInterval);
var action = new ClaimStakeReward(validatorAddress);
var actionContext = new ActionContext
{
PreviousState = world,
Signer = validatorAddress,
BlockIndex = height,
};

// When
var e = Assert.Throws<InvalidOperationException>(() => action.Execute(actionContext));

// Then
Assert.Equal("The validator cannot claim the stake reward.", e.Message);
}

private static StakeState PrepareStakeStateV2(
StakePolicySheet stakePolicySheet,
long startedBlockIndex,
Expand Down
79 changes: 78 additions & 1 deletion .Lib9c.Tests/Action/StakeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class StakeTest
{
private readonly IWorld _initialState;
private readonly Currency _ncg;
private readonly PublicKey _agentPublicKey = new PrivateKey().PublicKey;
private readonly Address _agentAddr;
private readonly StakePolicySheet _stakePolicySheet;

Expand Down Expand Up @@ -66,7 +67,9 @@ public StakeTest(ITestOutputHelper outputHelper)
_agentAddr,
_,
_initialState
) = InitializeUtil.InitializeStates(sheetsOverride: sheetsOverride);
) = InitializeUtil.InitializeStates(
sheetsOverride: sheetsOverride,
agentAddr: _agentPublicKey.Address);
_ncg = _initialState.GetGoldCurrency();
_stakePolicySheet = _initialState.GetSheet<StakePolicySheet>();
}
Expand Down Expand Up @@ -471,6 +474,80 @@ public void Execute_Success_When_Exist_StakeStateV3_Without_Guild(
Assert.Equal(Currencies.GuildGold * amount, stakeBalance);
}

[Theory]
[InlineData(0, 500, false)]
[InlineData(50, 100, false)]
[InlineData(0, long.MaxValue, false)]
[InlineData(0, 500, true)]
[InlineData(50, 100, true)]
[InlineData(0, long.MaxValue, true)]
public void Execute_Success_When_Validator_Tries_To_Increase_Amount_Without_Claim(
long previousAmount,
long amount,
bool withoutInterval)
{
if (previousAmount >= amount)
{
throw new ArgumentException(
"previousAmount should be less than amount.", nameof(previousAmount));
}

var interval = LegacyStakeState.RewardInterval;
var stakeStateAddr = StakeState.DeriveAddress(_agentAddr);
var stakeState = new StakeState(
contract: new Contract(_stakePolicySheet),
startedBlockIndex: 0L,
receivedBlockIndex: interval,
stateVersion: 3);
var world = _initialState;
var height = 0L;

world = DelegationUtil.EnsureValidatorPromotionReady(world, _agentPublicKey, height++);

if (previousAmount > 0)
{
var ncgToStake = _ncg * previousAmount;
var gg = FungibleAssetValue.Parse(Currencies.GuildGold, ncgToStake.GetQuantityString(true));
world = DelegationUtil.MintGuildGold(world, _agentAddr, gg, height);
world = world.MintAsset(new ActionContext(), _agentAddr, ncgToStake);
world = world.TransferAsset(
new ActionContext(), _agentAddr, stakeStateAddr, ncgToStake);
}

world = world.SetLegacyState(stakeStateAddr, stakeState.Serialize());

if (amount - previousAmount > 0)
{
var ncgToStake = _ncg * (amount - previousAmount);
world = world.MintAsset(new ActionContext(), _agentAddr, ncgToStake);
}

var nextState = Execute(
height + (withoutInterval ? 1 : interval),
world,
new TestRandom(),
_agentAddr,
amount);

if (amount > 0)
{
Assert.True(nextState.TryGetStakeState(_agentAddr, out StakeState nextStakeState));
Assert.Equal(3, nextStakeState.StateVersion);
}

world = DelegationUtil.EnsureStakeReleased(
nextState, height + LegacyStakeState.LockupInterval);

var expectedBalance = _ncg * Math.Max(0, previousAmount - amount);
var actualBalance = world.GetBalance(_agentAddr, _ncg);
var nonValidatorDelegateeBalance = world.GetBalance(
Addresses.NonValidatorDelegatee, Currencies.GuildGold);
var stakeBalance = world.GetBalance(stakeStateAddr, Currencies.GuildGold);
Assert.Equal(expectedBalance, actualBalance);
Assert.Equal(Currencies.GuildGold * 0, nonValidatorDelegateeBalance);
Assert.Equal(Currencies.GuildGold * amount, stakeBalance);
}

private IWorld Execute(
long blockIndex,
IWorld previousState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ var expectedProposerReward

var validatorAddress = vote.ValidatorPublicKey.Address;
var actualDelegatee = actualRepository.GetValidatorDelegatee(validatorAddress);
var validatorRewardAddress = actualDelegatee.CurrentLumpSumRewardsRecordAddress();
var validatorRewardAddress = actualDelegatee.DistributionPoolAddress();
var actualDelegationBalance = world.GetBalance(validatorAddress, DelegationCurrency);
var actualCommission = world.GetBalance(validatorAddress, GuildAllocateRewardCurrency);
var actualUnclaimedReward = world.GetBalance(validatorRewardAddress, GuildAllocateRewardCurrency);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Lib9c.Tests.Action.ValidatorDelegation
using System.Collections.Generic;
using System.Numerics;
using Libplanet.Crypto;
using Nekoyume.Action;
using Nekoyume.Action.ValidatorDelegation;
using Nekoyume.ValidatorDelegation;
using Xunit;
Expand Down Expand Up @@ -49,14 +50,12 @@ private static readonly long CommissionPercentageChangeCooldown
[Fact]
public void Serialization()
{
var address = new PrivateKey().Address;
BigInteger commissionPercentage = 10;
var action = new SetValidatorCommission(address, commissionPercentage);
var action = new SetValidatorCommission(commissionPercentage);
var plainValue = action.PlainValue;

var deserialized = new SetValidatorCommission();
deserialized.LoadPlainValue(plainValue);
Assert.Equal(address, deserialized.ValidatorDelegatee);
Assert.Equal(commissionPercentage, deserialized.CommissionPercentage);
}

Expand All @@ -73,7 +72,7 @@ public void Execute()

// When
var setValidatorCommission = new SetValidatorCommission(
validatorKey.Address, commissionPercentage: 11);
commissionPercentage: 11);
var actionContext = new ActionContext
{
PreviousState = world,
Expand Down Expand Up @@ -109,7 +108,6 @@ public void Execute_Theory(int oldCommissionPercentage, int newCommissionPercent

// When
var setValidatorCommission = new SetValidatorCommission(
validatorKey.Address,
newCommissionPercentage);
var actionContext = new ActionContext
{
Expand Down Expand Up @@ -148,7 +146,6 @@ public void Execute_Theory_WithValueGreaterThanMaximum_Throw(int commissionPerce
BlockIndex = height + CommissionPercentageChangeCooldown,
};
var setValidatorCommission = new SetValidatorCommission(
validatorKey.Address,
commissionPercentage);

// Then
Expand Down Expand Up @@ -178,7 +175,6 @@ public void Execute_Theory_WithNegative_Throw(int commissionPercentage)
BlockIndex = height + CommissionPercentageChangeCooldown,
};
var setValidatorCommission = new SetValidatorCommission(
validatorKey.Address,
commissionPercentage);

// Then
Expand Down Expand Up @@ -206,8 +202,7 @@ public void Execute_Theory_WithInvalidValue_Throw(int cooldown)
Signer = validatorKey.Address,
BlockIndex = height + cooldown,
};
var setValidatorCommission = new SetValidatorCommission(
validatorKey.Address, commissionPercentage: 14);
var setValidatorCommission = new SetValidatorCommission(commissionPercentage: 14);

// Then
Assert.Throws<InvalidOperationException>(
Expand Down Expand Up @@ -235,8 +230,7 @@ public void Execute_Theory_WitValue(int period)
Signer = validatorKey.Address,
BlockIndex = height + period,
};
var setValidatorCommission = new SetValidatorCommission(
validatorKey.Address, commissionPercentage: expectedCommission);
var setValidatorCommission = new SetValidatorCommission(expectedCommission);
world = setValidatorCommission.Execute(actionContext);

// Then
Expand All @@ -246,5 +240,59 @@ public void Execute_Theory_WitValue(int period)

Assert.Equal(expectedCommission, actualPercentage);
}

[Fact]
public void Execute_NotValidator_Throw()
{
// Given
var world = World;
var validatorKey = new PrivateKey();
var agentAddress = new PrivateKey().Address;
var validatorGold = DelegationCurrency * 10;
var height = 1L;
world = EnsureToMintAsset(world, validatorKey, validatorGold, height++);
world = EnsurePromotedValidator(world, validatorKey, validatorGold, height);

// When
var setValidatorCommission = new SetValidatorCommission(
commissionPercentage: 11);
var actionContext = new ActionContext
{
PreviousState = world,
Signer = agentAddress,
BlockIndex = height + CommissionPercentageChangeCooldown,
};

Assert.Throws<FailedLoadStateException>(
() => setValidatorCommission.Execute(actionContext));
}

[Fact]
public void Execute_With_SameValue_Throw()
{
// Given
var world = World;
var validatorKey = new PrivateKey();
var validatorGold = DelegationCurrency * 10;
var height = 1L;
world = EnsureToMintAsset(world, validatorKey, validatorGold, height++);
world = EnsurePromotedValidator(world, validatorKey, validatorGold, height);

// When
var repository = new ValidatorRepository(world, new ActionContext());
var delegatee = repository.GetValidatorDelegatee(validatorKey.Address);
var commissionPercentage = delegatee.CommissionPercentage;
var setValidatorCommission = new SetValidatorCommission(
commissionPercentage: commissionPercentage);
var actionContext = new ActionContext
{
PreviousState = world,
Signer = validatorKey.Address,
BlockIndex = height + CommissionPercentageChangeCooldown,
};

Assert.Throws<InvalidOperationException>(
() => setValidatorCommission.Execute(actionContext));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace Lib9c.Tests.Action.ValidatorDelegation;
using Nekoyume.ValidatorDelegation;
using Xunit;
using Nekoyume.Action.Guild.Migration.LegacyModels;
using Nekoyume.Delegation;

public class ValidatorDelegationTestBase
{
Expand Down Expand Up @@ -452,8 +453,7 @@ protected static IWorld EnsureCommissionChangedValidator(
BlockIndex = blockHeight,
Signer = validatorKey.Address,
};
var setValidatorCommission = new SetValidatorCommission(
validatorKey.Address, currentCommission + increment);
var setValidatorCommission = new SetValidatorCommission(currentCommission + increment);
world = setValidatorCommission.Execute(actionContext);
currentCommission += increment;
preferredHeight = blockHeight + cooldown;
Expand Down Expand Up @@ -593,7 +593,10 @@ protected static FungibleAssetValue CalculateBonusPropserReward(
}

protected static FungibleAssetValue CalculateClaim(BigInteger share, BigInteger totalShare, FungibleAssetValue totalClaim)
=> (totalClaim * share).DivRem(totalShare).Quotient;
{
var multiplier = BigInteger.Pow(10, (int)Math.Floor(BigInteger.Log10(totalShare)) + RewardBase.Margin);
return ((totalClaim * multiplier).DivRem(totalShare).Quotient * share).DivRem(multiplier).Quotient;
}

protected static FungibleAssetValue CalculateCommunityFund(ImmutableArray<Vote> votes, FungibleAssetValue reward)
{
Expand Down
6 changes: 6 additions & 0 deletions .Lib9c.Tests/Delegation/DelegationFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,18 @@ public DelegationFixture()
new Address("0x67A44E11506b8f0Bb625fEECccb205b33265Bb48"), TestRepository.DelegateeAccountAddress, TestRepository);
TestDelegatee2 = new TestDelegatee(
new Address("0xea1C4eedEfC99691DEfc6eF2753FAfa8C17F4584"), TestRepository.DelegateeAccountAddress, TestRepository);
TestRepository.SetDelegator(TestDelegator1);
TestRepository.SetDelegator(TestDelegator2);
TestRepository.SetDelegatee(TestDelegatee1);
TestRepository.SetDelegatee(TestDelegatee2);

DummyRepository = new DummyRepository(world, context);
DummyDelegatee1 = new DummyDelegatee(
new Address("0x67A44E11506b8f0Bb625fEECccb205b33265Bb48"), DummyRepository.DelegateeAccountAddress, DummyRepository);
DummyDelegator1 = new DummyDelegator(
new Address("0x0054E98312C47E7Fa0ABed45C23Fa187e31C373a"), DummyRepository.DelegateeAccountAddress, DummyRepository);
DummyRepository.SetDelegator(DummyDelegator1);
DummyRepository.SetDelegatee(DummyDelegatee1);
}

public TestRepository TestRepository { get; }
Expand Down
Loading
Loading