Skip to content

Commit

Permalink
Merge pull request #3086 from planetarium/fix/distribution
Browse files Browse the repository at this point in the history
Fix distribution with RewardBase
  • Loading branch information
OnedgeLee authored Dec 15, 2024
2 parents 74342ce + 2c67f64 commit 702c387
Show file tree
Hide file tree
Showing 32 changed files with 2,071 additions and 577 deletions.
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

0 comments on commit 702c387

Please sign in to comment.