diff --git a/.Lib9c.Tests/Action/Guild/ClaimRewardTest.cs b/.Lib9c.Tests/Action/Guild/ClaimRewardTest.cs index ce71229d70..8a9e537bb8 100644 --- a/.Lib9c.Tests/Action/Guild/ClaimRewardTest.cs +++ b/.Lib9c.Tests/Action/Guild/ClaimRewardTest.cs @@ -376,7 +376,6 @@ var expectedProposerReward AllocateRewardCurrency)) .ToArray(); - Assert.Equal(expectedRemainGuildReward, actualRemainGuildReward); Assert.Equal(expectedValidatorBalance, actualValidatorBalance); Assert.Equal(expectedDelegatorBalances, actualDelegatorBalances); Assert.Equal(expectedValidatorGuildReward, actualValidatorGuildReward); @@ -384,8 +383,9 @@ var expectedProposerReward Assert.Equal(expectedValidatorClaim, actualValidatorReward); Assert.Equal(expectedGuildClaims, actualGuildRewards); Assert.Equal(expectedGuildParticipantClaims, actualGuildParticipantRewards); - Assert.Equal(expectedRemainReward, actualRemainReward); - + // Flushing to remainder pool is now inactive. + // Assert.Equal(expectedRemainGuildReward, actualRemainGuildReward); + // Assert.Equal(expectedRemainReward, actualRemainReward); foreach (var key in guildParticipantKeys) { Assert.Throws( diff --git a/.Lib9c.Tests/Action/ItemEnhancementTest.cs b/.Lib9c.Tests/Action/ItemEnhancementTest.cs index d69271af8b..4e23dedd97 100644 --- a/.Lib9c.Tests/Action/ItemEnhancementTest.cs +++ b/.Lib9c.Tests/Action/ItemEnhancementTest.cs @@ -544,5 +544,46 @@ public void Execute_With_Hammer(bool oldStart) Assert.Equal(preItemUsable.ItemId, resultEquipment.ItemId); Assert.Equal(expectedCost, slotResult.gold); } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Execute_Throw_InvalidItemTypeException(bool withMaterials) + { + var types = ItemEnhancement.HammerBannedTypes; + foreach (var itemSubType in types) + { + var row = + _tableSheets.EquipmentItemSheet.Values.First(r => r.ItemSubType == itemSubType); + var equipment = ItemFactory.CreateItemUsable(row, Guid.NewGuid(), 0); + _avatarState.inventory.AddItem(equipment); + _initialState = _initialState.SetAvatarState(_avatarAddress, _avatarState); + var materialIds = new List(); + if (withMaterials) + { + materialIds.Add(Guid.NewGuid()); + materialIds.Add(Guid.NewGuid()); + } + + var action = new ItemEnhancement + { + itemId = equipment.ItemId, + materialIds = materialIds, + avatarAddress = _avatarAddress, + slotIndex = 0, + hammers = new Dictionary + { + [600301] = 3, + }, + }; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = 1, + PreviousState = _initialState, + RandomSeed = 0, + Signer = _agentAddress, + })); + } + } } } diff --git a/.Lib9c.Tests/Action/ValidatorDelegation/PromoteValidatorTest.cs b/.Lib9c.Tests/Action/ValidatorDelegation/PromoteValidatorTest.cs index 9c99515b23..81b7d0e1bf 100644 --- a/.Lib9c.Tests/Action/ValidatorDelegation/PromoteValidatorTest.cs +++ b/.Lib9c.Tests/Action/ValidatorDelegation/PromoteValidatorTest.cs @@ -49,7 +49,6 @@ public void Execute() var bond = repository.GetBond(validator, validatorKey.Address); var validatorList = repository.GetValidatorList(); - Assert.Equal(validatorKey.Address, Assert.Single(validator.Delegators)); Assert.Equal(gold.RawValue, bond.Share); Assert.Equal(validator.Validator, Assert.Single(validatorList.Validators)); Assert.Equal(validator.Validator, Assert.Single(validatorList.ActiveSet())); diff --git a/.Lib9c.Tests/Action/ValidatorDelegation/UndelegateValidatorTest.cs b/.Lib9c.Tests/Action/ValidatorDelegation/UndelegateValidatorTest.cs index 24dc21628d..c6638b28ee 100644 --- a/.Lib9c.Tests/Action/ValidatorDelegation/UndelegateValidatorTest.cs +++ b/.Lib9c.Tests/Action/ValidatorDelegation/UndelegateValidatorTest.cs @@ -70,7 +70,6 @@ public void Execute() var actualValidatorList = actualRepository.GetValidatorList(); var actualBond = actualRepository.GetBond(actualDelegatee, validatorKey.Address); - Assert.NotEqual(expectedDelegatee.Delegators, actualDelegatee.Delegators); Assert.NotEqual(expectedDelegatee.Validator.Power, actualDelegatee.Validator.Power); Assert.Equal(BigInteger.Zero, actualDelegatee.Validator.Power); Assert.Empty(actualValidatorList.Validators); diff --git a/.Lib9c.Tests/Delegation/DelegateeTest.cs b/.Lib9c.Tests/Delegation/DelegateeTest.cs index 10dae9b102..f706495280 100644 --- a/.Lib9c.Tests/Delegation/DelegateeTest.cs +++ b/.Lib9c.Tests/Delegation/DelegateeTest.cs @@ -4,6 +4,7 @@ namespace Lib9c.Tests.Delegation using System.Numerics; using Libplanet.Crypto; using Libplanet.Types.Assets; + using Nekoyume; using Nekoyume.Delegation; using Xunit; @@ -38,7 +39,6 @@ public void GetSet() delegatee.Bond(delegator, delegatee.DelegationCurrency * 10, 10L); var delegateeRecon = repo.GetDelegatee(delegatee.Address); Assert.Equal(delegatee.Address, delegateeRecon.Address); - Assert.Equal(delegator.Address, Assert.Single(delegateeRecon.Delegators)); Assert.Equal(delegatee.TotalDelegated, delegateeRecon.TotalDelegated); Assert.Equal(delegatee.TotalShares, delegateeRecon.TotalShares); } @@ -70,7 +70,6 @@ public void Bond() var bondedShare = testDelegatee.Bond(testDelegator1, bonding, 10L); var bondedShare1 = _fixture.TestRepository.GetBond(testDelegatee, testDelegator1.Address).Share; - Assert.Equal(testDelegator1.Address, Assert.Single(testDelegatee.Delegators)); Assert.Equal(share, bondedShare); Assert.Equal(share1, bondedShare1); Assert.Equal(totalShare, testDelegatee.TotalShares); @@ -83,7 +82,6 @@ public void Bond() totalBonding += bonding; bondedShare = testDelegatee.Bond(testDelegator1, bonding, 20L); bondedShare1 = _fixture.TestRepository.GetBond(testDelegatee, testDelegator1.Address).Share; - Assert.Equal(testDelegator1.Address, Assert.Single(testDelegatee.Delegators)); Assert.Equal(share, bondedShare); Assert.Equal(share1, bondedShare1); Assert.Equal(totalShare, testDelegatee.TotalShares); @@ -96,9 +94,6 @@ public void Bond() totalBonding += bonding; bondedShare = testDelegatee.Bond(testDelegator2, bonding, 30L); var bondedShare2 = _fixture.TestRepository.GetBond(testDelegatee, testDelegator2.Address).Share; - Assert.Equal(2, testDelegatee.Delegators.Count); - Assert.Contains(testDelegator1.Address, testDelegatee.Delegators); - Assert.Contains(testDelegator2.Address, testDelegatee.Delegators); Assert.Equal(share, bondedShare); Assert.Equal(share2, bondedShare2); Assert.Equal(totalShare, testDelegatee.TotalShares); @@ -163,9 +158,6 @@ public void Unbond() totalDelegated -= unbondingFAV; var unbondedFAV = testDelegatee.Unbond(testDelegator1, unbonding, 3L); var shareAfterUnbond = _fixture.TestRepository.GetBond(testDelegatee, testDelegator1.Address).Share; - Assert.Equal(2, testDelegatee.Delegators.Count); - Assert.Contains(testDelegator1.Address, testDelegatee.Delegators); - Assert.Contains(testDelegator2.Address, testDelegatee.Delegators); Assert.Equal(unbondingFAV, unbondedFAV); Assert.Equal(share1, shareAfterUnbond); Assert.Equal(totalShares, testDelegatee.TotalShares); @@ -178,9 +170,6 @@ public void Unbond() totalDelegated -= unbondingFAV; unbondedFAV = testDelegatee.Unbond(testDelegator2, unbonding, 4L); shareAfterUnbond = _fixture.TestRepository.GetBond(testDelegatee, testDelegator2.Address).Share; - Assert.Equal(2, testDelegatee.Delegators.Count); - Assert.Contains(testDelegator1.Address, testDelegatee.Delegators); - Assert.Contains(testDelegator2.Address, testDelegatee.Delegators); Assert.Equal(unbondingFAV, unbondedFAV); Assert.Equal(share2, shareAfterUnbond); Assert.Equal(totalShares, testDelegatee.TotalShares); @@ -191,7 +180,6 @@ public void Unbond() totalDelegated -= unbondingFAV; unbondedFAV = testDelegatee.Unbond(testDelegator1, share1, 5L); shareAfterUnbond = _fixture.TestRepository.GetBond(testDelegatee, testDelegator1.Address).Share; - Assert.Equal(testDelegator2.Address, Assert.Single(testDelegatee.Delegators)); Assert.Equal(unbondingFAV, unbondedFAV); Assert.Equal(BigInteger.Zero, shareAfterUnbond); Assert.Equal(totalShares, testDelegatee.TotalShares); @@ -207,7 +195,7 @@ public void CannotUnbondInvalidDelegator() _fixture.DummyDelegator1, BigInteger.One, 10L)); } - [Fact] + [Fact(Skip = "Flushing to remainder pool is now inactive.")] public void ClearRemainderRewards() { var repo = _fixture.TestRepository; diff --git a/.Lib9c.Tests/Delegation/DelegatorTest.cs b/.Lib9c.Tests/Delegation/DelegatorTest.cs index e230a91fec..8533601a90 100644 --- a/.Lib9c.Tests/Delegation/DelegatorTest.cs +++ b/.Lib9c.Tests/Delegation/DelegatorTest.cs @@ -57,7 +57,6 @@ public void Delegate() Assert.Equal(delegateShare, share); Assert.Equal(delegateFAV, delegatee1.TotalDelegated); Assert.Equal(delegateShare, delegatee1.TotalShares); - Assert.Equal(delegator.Address, Assert.Single(delegatee1.Delegators)); Assert.Equal(delegatee1.Address, Assert.Single(delegator.Delegatees)); var delegateFAV2 = delegatee1.DelegationCurrency * 20; @@ -71,7 +70,6 @@ public void Delegate() Assert.Equal(delegateShare + delegateShare2, share); Assert.Equal(delegateFAV + delegateFAV2, delegatee1.TotalDelegated); Assert.Equal(delegateShare + delegateShare2, delegatee1.TotalShares); - Assert.Equal(delegator.Address, Assert.Single(delegatee1.Delegators)); Assert.Equal(delegatee1.Address, Assert.Single(delegator.Delegatees)); delegator.Delegate(delegatee2, delegateFAV, 3L); @@ -112,7 +110,6 @@ public void Undelegate() Assert.Equal(initialShare - undelegatingShare, share1); Assert.Equal(delegatingFAV - undelegatingFAV, delegatee.TotalDelegated); Assert.Equal(initialShare - undelegatingShare, delegatee.TotalShares); - Assert.Equal(delegator.Address, Assert.Single(delegatee.Delegators)); Assert.Equal(delegatee.Address, Assert.Single(delegator.Delegatees)); Assert.Equal(unbondLockIn.Address, Assert.Single(unbondingSet.FlattenedUnbondingRefs).Address); var entriesByExpireHeight = Assert.Single(unbondLockIn.Entries); @@ -137,7 +134,6 @@ public void Undelegate() Assert.Equal(delegatee.DelegationCurrency * 0, delegatee.TotalDelegated); Assert.Equal(System.Numerics.BigInteger.Zero, delegatee.TotalShares); Assert.Empty(delegator.Delegatees); - Assert.Empty(delegatee.Delegators); Assert.Equal(unbondLockIn.Address, Assert.Single(unbondingSet.FlattenedUnbondingRefs).Address); Assert.Equal(2, unbondLockIn.Entries.Count); @@ -215,8 +211,6 @@ public void Redelegate() Assert.Equal(redelegatedDstShare, delegatee2.TotalShares); Assert.Equal(delegatingFAV - redelegatingFAV, delegatee1.TotalDelegated); Assert.Equal(redelegatingFAV, delegatee2.TotalDelegated); - Assert.Equal(delegator.Address, Assert.Single(delegatee1.Delegators)); - Assert.Equal(delegator.Address, Assert.Single(delegatee2.Delegators)); Assert.Equal(2, delegator.Delegatees.Count); Assert.Equal(rebondGrace.Address, Assert.Single(unbondingSet.FlattenedUnbondingRefs).Address); var entriesByExpireHeight = Assert.Single(rebondGrace.Entries); @@ -247,8 +241,6 @@ public void Redelegate() Assert.Equal(redelegatedDstShare + redelegatedDstShare2, delegatee2.TotalShares); Assert.Equal(delegatingFAV - redelegatingFAV - redelegatingFAV2, delegatee1.TotalDelegated); Assert.Equal(redelegatingFAV + redelegatingFAV2, delegatee2.TotalDelegated); - Assert.Empty(delegatee1.Delegators); - Assert.Equal(delegator.Address, Assert.Single(delegatee2.Delegators)); Assert.Equal(delegatee2.Address, Assert.Single(delegator.Delegatees)); Assert.Equal(rebondGrace.Address, Assert.Single(unbondingSet.FlattenedUnbondingRefs).Address); Assert.Equal(2, rebondGrace.Entries.Count); @@ -357,7 +349,12 @@ public void RewardOnDelegate() Assert.Equal(delegatorInitialBalance - delegatingFAV2 * 2, delegator2Balance); Assert.Equal(rewards1, delegator1RewardBalances); Assert.Equal(rewards2, delegator2RewardBalances); - Assert.Equal(delegatee.RewardCurrencies.Select(c => c * 0), collectedRewards); + + // Flushing to remainder pool is now inactive. + // Assert.Equal(delegatee.RewardCurrencies.Select(c => c * 0), collectedRewards); + Assert.Equal( + rewards.Select(r => r * 2).Zip(rewards1.Zip(rewards2, (f, s) => f + s), (f, s) => f - s).ToArray(), + collectedRewards); } [Fact] @@ -431,7 +428,12 @@ public void RewardOnUndelegate() Assert.Equal(delegatorInitialBalance - delegatingFAV2, delegator2Balance); Assert.Equal(rewards1, delegator1RewardBalances); Assert.Equal(rewards2, delegator2RewardBalances); - Assert.Equal(delegatee.RewardCurrencies.Select(c => c * 0), collectedRewards); + + // Flushing to remainder pool is now inactive. + // Assert.Equal(delegatee.RewardCurrencies.Select(c => c * 0), collectedRewards); + Assert.Equal( + rewards.Select(r => r * 2).Zip(rewards1.Zip(rewards2, (f, s) => f + s), (f, s) => f - s).ToArray(), + collectedRewards); } [Fact] @@ -506,7 +508,12 @@ public void RewardOnRedelegate() Assert.Equal(delegatorInitialBalance - delegatingFAV2, delegator2Balance); Assert.Equal(rewards1, delegator1RewardBalances); Assert.Equal(rewards2, delegator2RewardBalances); - Assert.Equal(delegatee.RewardCurrencies.Select(c => c * 0), collectedRewards); + + // Flushing to remainder pool is now inactive. + // Assert.Equal(delegatee.RewardCurrencies.Select(c => c * 0), collectedRewards); + Assert.Equal( + rewards.Select(r => r * 2).Zip(rewards1.Zip(rewards2, (f, s) => f + s), (f, s) => f - s).ToArray(), + collectedRewards); } [Fact] @@ -581,7 +588,12 @@ public void RewardOnClaim() Assert.Equal(delegatorInitialBalance - delegatingFAV2, delegator2Balance); Assert.Equal(rewards1, delegator1RewardBalances); Assert.Equal(rewards2, delegator2RewardBalances); - Assert.Equal(delegatee.RewardCurrencies.Select(c => c * 0), collectedRewards); + + // Flushing to remainder pool is now inactive. + // Assert.Equal(delegatee.RewardCurrencies.Select(c => c * 0), collectedRewards); + Assert.Equal( + rewards.Select(r => r * 2).Zip(rewards1.Zip(rewards2, (f, s) => f + s), (f, s) => f - s).ToArray(), + collectedRewards); } } } diff --git a/.Lib9c.Tests/Delegation/Migration/LegacyDelegateeMetadata.cs b/.Lib9c.Tests/Delegation/Migration/LegacyDelegateeMetadata.cs new file mode 100644 index 0000000000..0cf0b90457 --- /dev/null +++ b/.Lib9c.Tests/Delegation/Migration/LegacyDelegateeMetadata.cs @@ -0,0 +1,221 @@ +#nullable enable +namespace Lib9c.Tests.Delegation.Migration +{ + using System; + using System.Collections.Generic; + using System.Collections.Immutable; + using System.Linq; + using System.Numerics; + using Bencodex; + using Bencodex.Types; + using Libplanet.Crypto; + using Libplanet.Types.Assets; + using Nekoyume.Delegation; + + public class LegacyDelegateeMetadata : IDelegateeMetadata + { + private readonly IComparer _currencyComparer = new CurrencyComparer(); + private Address? _address; + + public LegacyDelegateeMetadata( + Address delegateeAddress, + Address delegateeAccountAddress, + Currency delegationCurrency, + IEnumerable rewardCurrencies, + Address delegationPoolAddress, + Address rewardPoolAddress, + Address rewardRemainderPoolAddress, + Address slashedPoolAddress, + long unbondingPeriod, + int maxUnbondLockInEntries, + int maxRebondGraceEntries) + : this( + delegateeAddress, + delegateeAccountAddress, + delegationCurrency, + rewardCurrencies, + delegationPoolAddress, + rewardPoolAddress, + rewardRemainderPoolAddress, + slashedPoolAddress, + unbondingPeriod, + maxUnbondLockInEntries, + maxRebondGraceEntries, + ImmutableSortedSet
.Empty, + delegationCurrency * 0, + BigInteger.Zero, + false, + -1L, + false, + ImmutableSortedSet.Empty) + { + } + + public LegacyDelegateeMetadata( + Address delegateeAddress, + Address delegateeAccountAddress, + IValue bencoded) + : this(delegateeAddress, delegateeAccountAddress, (List)bencoded) + { + } + + public LegacyDelegateeMetadata( + Address address, + Address accountAddress, + List bencoded) + : this( + address, + accountAddress, + new Currency(bencoded[0]), + ((List)bencoded[1]).Select(v => new Currency(v)), + new Address(bencoded[2]), + new Address(bencoded[3]), + new Address(bencoded[4]), + new Address(bencoded[5]), + (Integer)bencoded[6], + (Integer)bencoded[7], + (Integer)bencoded[8], + ((List)bencoded[9]).Select(item => new Address(item)), + new FungibleAssetValue(bencoded[10]), + (Integer)bencoded[11], + (Bencodex.Types.Boolean)bencoded[12], + (Integer)bencoded[13], + (Bencodex.Types.Boolean)bencoded[14], + ((List)bencoded[15]).Select(item => new UnbondingRef(item))) + { + } + + private LegacyDelegateeMetadata( + Address delegateeAddress, + Address delegateeAccountAddress, + Currency delegationCurrency, + IEnumerable rewardCurrencies, + Address delegationPoolAddress, + Address rewardPoolAddress, + Address rewardRemainderPoolAddress, + Address slashedPoolAddress, + long unbondingPeriod, + int maxUnbondLockInEntries, + int maxRebondGraceEntries, + IEnumerable
delegators, + FungibleAssetValue totalDelegated, + BigInteger totalShares, + bool jailed, + long jailedUntil, + bool tombstoned, + IEnumerable unbondingRefs) + { + if (!totalDelegated.Currency.Equals(delegationCurrency)) + { + throw new InvalidOperationException("Invalid currency."); + } + + if (totalDelegated.Sign < 0) + { + throw new ArgumentOutOfRangeException( + nameof(totalDelegated), + totalDelegated, + "Total delegated must be non-negative."); + } + + if (totalShares.Sign < 0) + { + throw new ArgumentOutOfRangeException( + nameof(totalShares), + totalShares, + "Total shares must be non-negative."); + } + + DelegateeAddress = delegateeAddress; + DelegateeAccountAddress = delegateeAccountAddress; + DelegationCurrency = delegationCurrency; + RewardCurrencies = rewardCurrencies.ToImmutableSortedSet(_currencyComparer); + DelegationPoolAddress = delegationPoolAddress; + RewardPoolAddress = rewardPoolAddress; + RewardRemainderPoolAddress = rewardRemainderPoolAddress; + SlashedPoolAddress = slashedPoolAddress; + UnbondingPeriod = unbondingPeriod; + MaxUnbondLockInEntries = maxUnbondLockInEntries; + MaxRebondGraceEntries = maxRebondGraceEntries; + Delegators = delegators.ToImmutableSortedSet(); + TotalDelegatedFAV = totalDelegated; + TotalShares = totalShares; + Jailed = jailed; + JailedUntil = jailedUntil; + Tombstoned = tombstoned; + UnbondingRefs = unbondingRefs.ToImmutableSortedSet(); + } + + public Address DelegateeAddress { get; } + + public Address DelegateeAccountAddress { get; } + + public Address Address + => _address ??= DelegationAddress.DelegateeMetadataAddress( + DelegateeAddress, + DelegateeAccountAddress); + + public Currency DelegationCurrency { get; } + + public ImmutableSortedSet RewardCurrencies { get; } + + public Address DelegationPoolAddress { get; internal set; } + + public Address RewardPoolAddress { get; } + + public Address RewardRemainderPoolAddress { get; } + + public Address SlashedPoolAddress { get; } + + public long UnbondingPeriod { get; private set; } + + public int MaxUnbondLockInEntries { get; } + + public int MaxRebondGraceEntries { get; } + + public ImmutableSortedSet
Delegators { get; private set; } + + public FungibleAssetValue TotalDelegatedFAV { get; private set; } + + public BigInteger TotalShares { get; private set; } + + public bool Jailed { get; internal set; } + + public long JailedUntil { get; internal set; } + + public bool Tombstoned { get; internal set; } + + public ImmutableSortedSet UnbondingRefs { get; private set; } + + // TODO : Better serialization + public List Bencoded => List.Empty + .Add(DelegationCurrency.Serialize()) + .Add(new List(RewardCurrencies.Select(c => c.Serialize()))) + .Add(DelegationPoolAddress.Bencoded) + .Add(RewardPoolAddress.Bencoded) + .Add(RewardRemainderPoolAddress.Bencoded) + .Add(SlashedPoolAddress.Bencoded) + .Add(UnbondingPeriod) + .Add(MaxUnbondLockInEntries) + .Add(MaxRebondGraceEntries) + .Add(new List(Delegators.Select(delegator => delegator.Bencoded))) + .Add(TotalDelegatedFAV.Serialize()) + .Add(TotalShares) + .Add(Jailed) + .Add(JailedUntil) + .Add(Tombstoned) + .Add(new List(UnbondingRefs.Select(unbondingRef => unbondingRef.Bencoded))); + + IValue IBencodable.Bencoded => Bencoded; + + public BigInteger ShareFromFAV(FungibleAssetValue fav) + => TotalShares.IsZero + ? fav.RawValue + : TotalShares * fav.RawValue / TotalDelegatedFAV.RawValue; + + public FungibleAssetValue FAVFromShare(BigInteger share) + => TotalShares == share + ? TotalDelegatedFAV + : (TotalDelegatedFAV * share).DivRem(TotalShares).Quotient; + } +} diff --git a/.Lib9c.Tests/Delegation/Migration/LegacyLumpSumRewardsRecord.cs b/.Lib9c.Tests/Delegation/Migration/LegacyLumpSumRewardsRecord.cs new file mode 100644 index 0000000000..abb6be9f37 --- /dev/null +++ b/.Lib9c.Tests/Delegation/Migration/LegacyLumpSumRewardsRecord.cs @@ -0,0 +1,138 @@ +#nullable enable +namespace Lib9c.Tests.Delegation.Migration +{ + using System; + using System.Collections.Generic; + using System.Collections.Immutable; + using System.Linq; + using System.Numerics; + using Bencodex; + using Bencodex.Types; + using Libplanet.Crypto; + using Libplanet.Types.Assets; + using Nekoyume.Delegation; + + public class LegacyLumpSumRewardsRecord : IBencodable + { + private readonly IComparer _currencyComparer = new CurrencyComparer(); + + public LegacyLumpSumRewardsRecord( + Address address, + long startHeight, + BigInteger totalShares, + ImmutableSortedSet
delegators, + IEnumerable currencies) + : this( + address, + startHeight, + totalShares, + delegators, + currencies, + null) + { + } + + public LegacyLumpSumRewardsRecord( + Address address, + long startHeight, + BigInteger totalShares, + ImmutableSortedSet
delegators, + IEnumerable currencies, + long? lastStartHeight) + : this( + address, + startHeight, + totalShares, + delegators, + currencies.Select(c => c * 0), + lastStartHeight) + { + } + + public LegacyLumpSumRewardsRecord( + Address address, + long startHeight, + BigInteger totalShares, + ImmutableSortedSet
delegators, + IEnumerable lumpSumRewards, + long? lastStartHeight) + { + Address = address; + StartHeight = startHeight; + TotalShares = totalShares; + Delegators = delegators; + + if (!lumpSumRewards.Select(f => f.Currency).All(new HashSet().Add)) + { + throw new ArgumentException("Duplicated currency in lump sum rewards."); + } + + LumpSumRewards = lumpSumRewards.ToImmutableDictionary(f => f.Currency, f => f); + LastStartHeight = lastStartHeight; + } + + public LegacyLumpSumRewardsRecord(Address address, IValue bencoded) + : this(address, (List)bencoded) + { + } + + public LegacyLumpSumRewardsRecord(Address address, List bencoded) + : this( + address, + (Integer)bencoded[0], + (Integer)bencoded[1], + ((List)bencoded[2]).Select(a => new Address(a)).ToImmutableSortedSet(), + ((List)bencoded[3]).Select(v => new FungibleAssetValue(v)), + (Integer?)bencoded.ElementAtOrDefault(4)) + { + } + + private LegacyLumpSumRewardsRecord( + Address address, + long startHeight, + BigInteger totalShares, + ImmutableSortedSet
delegators, + ImmutableDictionary lumpSumRewards, + long? lastStartHeight) + { + Address = address; + StartHeight = startHeight; + TotalShares = totalShares; + Delegators = delegators; + LumpSumRewards = lumpSumRewards; + LastStartHeight = lastStartHeight; + } + + public Address Address { get; } + + public long StartHeight { get; } + + public BigInteger TotalShares { get; } + + public ImmutableDictionary LumpSumRewards { get; } + + public ImmutableSortedSet
Delegators { get; } + + public long? LastStartHeight { get; } + + public List Bencoded + { + get + { + var bencoded = List.Empty + .Add(StartHeight) + .Add(TotalShares) + .Add(new List(Delegators.Select(a => a.Bencoded))) + .Add(new List(LumpSumRewards + .OrderBy(r => r.Key, _currencyComparer) + .Select(r => r.Value.Serialize()))); + + return LastStartHeight is long lastStartHeight + ? bencoded.Add(lastStartHeight) + : bencoded; + } + } + + IValue IBencodable.Bencoded => Bencoded; + } +} diff --git a/.Lib9c.Tests/Delegation/Migration/MigrateLegacyStateTest.cs b/.Lib9c.Tests/Delegation/Migration/MigrateLegacyStateTest.cs new file mode 100644 index 0000000000..4ed115b985 --- /dev/null +++ b/.Lib9c.Tests/Delegation/Migration/MigrateLegacyStateTest.cs @@ -0,0 +1,81 @@ +namespace Lib9c.Tests.Delegation.Migration +{ + using System.Collections.Immutable; + using System.Linq; + using Libplanet.Crypto; + using Libplanet.Types.Assets; + using Nekoyume.Delegation; + using Xunit; + + public class MigrateLegacyStateTest + { + [Fact] + public void ParseLegacyDelegateeMetadata() + { + var address = new PrivateKey().Address; + var accountAddress = new PrivateKey().Address; + var delegationCurrency = Currency.Uncapped("del", 5, null); + var rewardCurrencies = new Currency[] { Currency.Uncapped("rew", 5, null), }; + var delegationPoolAddress = new PrivateKey().Address; + var rewardPoolAddress = new PrivateKey().Address; + var rewardRemainderPoolAddress = new PrivateKey().Address; + var slashedPoolAddress = new PrivateKey().Address; + var unbondingPeriod = 1L; + var maxUnbondLockInEntries = 2; + var maxRebondGraceEntries = 3; + + var legacyDelegateeMetadataBencoded = new LegacyDelegateeMetadata( + address, + accountAddress, + delegationCurrency, + rewardCurrencies, + delegationPoolAddress, + rewardPoolAddress, + rewardRemainderPoolAddress, + slashedPoolAddress, + unbondingPeriod, + maxUnbondLockInEntries, + maxRebondGraceEntries).Bencoded; + + var delegateeMetadata = new DelegateeMetadata(address, accountAddress, legacyDelegateeMetadataBencoded); + + Assert.Equal(address, delegateeMetadata.DelegateeAddress); + Assert.Equal(accountAddress, delegateeMetadata.DelegateeAccountAddress); + Assert.Equal(delegationCurrency, delegateeMetadata.DelegationCurrency); + Assert.Equal(rewardCurrencies, delegateeMetadata.RewardCurrencies); + Assert.Equal(delegationPoolAddress, delegateeMetadata.DelegationPoolAddress); + Assert.Equal(rewardPoolAddress, delegateeMetadata.RewardPoolAddress); + Assert.Equal(rewardRemainderPoolAddress, delegateeMetadata.RewardRemainderPoolAddress); + Assert.Equal(slashedPoolAddress, delegateeMetadata.SlashedPoolAddress); + Assert.Equal(unbondingPeriod, delegateeMetadata.UnbondingPeriod); + Assert.Equal(maxUnbondLockInEntries, delegateeMetadata.MaxUnbondLockInEntries); + Assert.Equal(maxRebondGraceEntries, delegateeMetadata.MaxRebondGraceEntries); + } + + [Fact] + public void ParseLegacyLumpSumRewardsRecord() + { + var address = new PrivateKey().Address; + var startHeight = 1L; + var totalShares = 2; + var delegators = ImmutableSortedSet.Create
(new PrivateKey().Address); + var currencies = new Currency[] { Currency.Uncapped("cur", 5, null), }; + var lastStartHeight = 3L; + + var legacyLumpSumRewardsRecordBencoded = new LegacyLumpSumRewardsRecord( + address, + startHeight, + totalShares, + delegators, + currencies, + lastStartHeight).Bencoded; + + var lumpSumRewardsRecord = new LumpSumRewardsRecord(address, legacyLumpSumRewardsRecordBencoded); + + Assert.Equal(address, lumpSumRewardsRecord.Address); + Assert.Equal(startHeight, lumpSumRewardsRecord.StartHeight); + Assert.Equal(totalShares, lumpSumRewardsRecord.TotalShares); + Assert.Equal(currencies, lumpSumRewardsRecord.LumpSumRewards.Select(c => c.Key)); + } + } +} diff --git a/Lib9c.Abstractions/Lib9c.Abstractions.csproj b/Lib9c.Abstractions/Lib9c.Abstractions.csproj index d1eeb2b29a..657ddb7b89 100644 --- a/Lib9c.Abstractions/Lib9c.Abstractions.csproj +++ b/Lib9c.Abstractions/Lib9c.Abstractions.csproj @@ -8,7 +8,7 @@ .obj 9 ..\Lib9c.Common.ruleset - 1.20.0 + 1.20.1 diff --git a/Lib9c.MessagePack/Lib9c.MessagePack.csproj b/Lib9c.MessagePack/Lib9c.MessagePack.csproj index f588c9d3ff..c610847a9a 100644 --- a/Lib9c.MessagePack/Lib9c.MessagePack.csproj +++ b/Lib9c.MessagePack/Lib9c.MessagePack.csproj @@ -8,7 +8,7 @@ AnyCPU .bin .obj - 1.20.0 + 1.20.1 diff --git a/Lib9c.Renderers/Lib9c.Renderers.csproj b/Lib9c.Renderers/Lib9c.Renderers.csproj index 0b6e08a83f..957394c92d 100644 --- a/Lib9c.Renderers/Lib9c.Renderers.csproj +++ b/Lib9c.Renderers/Lib9c.Renderers.csproj @@ -6,7 +6,7 @@ enable .bin .obj - 1.20.0 + 1.20.1 Lib9c diff --git a/Lib9c/Action/ItemEnhancement.cs b/Lib9c/Action/ItemEnhancement.cs index a757d58560..773c4b3783 100644 --- a/Lib9c/Action/ItemEnhancement.cs +++ b/Lib9c/Action/ItemEnhancement.cs @@ -220,7 +220,8 @@ public override IWorld Execute(IActionContext context) // Validate enhancement materials var uniqueMaterialIds = materialIds.Distinct().ToList(); - if (!uniqueMaterialIds.Any()) + // Validate hammer without materials count + if (hammers.Any()) { if (HammerBannedTypes.Contains(enhancementEquipment.ItemSubType)) { diff --git a/Lib9c/Delegation/Delegatee.cs b/Lib9c/Delegation/Delegatee.cs index 52db964657..fbf1f40991 100644 --- a/Lib9c/Delegation/Delegatee.cs +++ b/Lib9c/Delegation/Delegatee.cs @@ -91,8 +91,6 @@ private Delegatee(DelegateeMetadata metadata, IDelegationRepository repository) public int MaxRebondGraceEntries => Metadata.MaxRebondGraceEntries; - public ImmutableSortedSet
Delegators => Metadata.Delegators; - public FungibleAssetValue TotalDelegated => Metadata.TotalDelegatedFAV; public BigInteger TotalShares => Metadata.TotalShares; @@ -192,7 +190,6 @@ public virtual BigInteger Bond(T delegator, FungibleAssetValue fav, long height) Bond bond = Repository.GetBond(this, delegator.Address); BigInteger share = ShareFromFAV(fav); bond = bond.AddShare(share); - Metadata.AddDelegator(delegator.Address); Metadata.AddShare(share); Metadata.AddDelegatedFAV(fav); Repository.SetBond(bond); @@ -221,7 +218,6 @@ public FungibleAssetValue Unbond(T delegator, BigInteger share, long height) if (bond.Share.IsZero) { bond = bond.ClearLastDistributeHeight(); - Metadata.RemoveDelegator(delegator.Address); } Metadata.RemoveShare(share); @@ -249,15 +245,9 @@ IEnumerable lumpSumRewardsRecords foreach (LumpSumRewardsRecord record in lumpSumRewardsRecords) { - if (!record.Delegators.Contains(delegator.Address)) - { - continue; - } - TransferReward(delegator, share, record); - LumpSumRewardsRecord newRecord = record.RemoveDelegator(delegator.Address); - TransferRemainders(newRecord); - Repository.SetLumpSumRewardsRecord(newRecord); + // TransferRemainders(newRecord); + Repository.SetLumpSumRewardsRecord(record); } } @@ -280,7 +270,6 @@ public void CollectRewards(long height) CurrentLumpSumRewardsRecordAddress(), height, TotalShares, - Delegators, RewardCurrencies); record = record.AddLumpSumRewards(rewards); @@ -393,7 +382,6 @@ private void StartNewRewardPeriod(long height) currentRecord.Address, currentRecord.StartHeight, TotalShares, - Delegators, RewardCurrencies, currentRecord.LastStartHeight); @@ -420,7 +408,6 @@ private void StartNewRewardPeriod(long height) CurrentLumpSumRewardsRecordAddress(), height, TotalShares, - Delegators, RewardCurrencies, lastStartHeight); @@ -467,11 +454,6 @@ private void TransferReward(T delegator, BigInteger share, LumpSumRewardsRecord private void TransferRemainders(LumpSumRewardsRecord record) { - if (!record.Delegators.IsEmpty) - { - return; - } - foreach (var rewardCurrency in RewardCurrencies) { FungibleAssetValue remainder = Repository.GetBalance(record.Address, rewardCurrency); diff --git a/Lib9c/Delegation/DelegateeMetadata.cs b/Lib9c/Delegation/DelegateeMetadata.cs index d61a9f0354..3f9121a9cd 100644 --- a/Lib9c/Delegation/DelegateeMetadata.cs +++ b/Lib9c/Delegation/DelegateeMetadata.cs @@ -3,6 +3,7 @@ using Bencodex.Types; using Libplanet.Crypto; using Libplanet.Types.Assets; +using Nekoyume.Action; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -13,6 +14,9 @@ namespace Nekoyume.Delegation { public class DelegateeMetadata : IDelegateeMetadata { + private const string StateTypeName = "delegatee_metadata"; + private const long StateVersion = 1; + private Address? _address; private readonly IComparer _currencyComparer = new CurrencyComparer(); @@ -40,7 +44,6 @@ public DelegateeMetadata( unbondingPeriod, maxUnbondLockInEntries, maxRebondGraceEntries, - ImmutableSortedSet
.Empty, delegationCurrency * 0, BigInteger.Zero, false, @@ -62,26 +65,110 @@ public DelegateeMetadata( Address address, Address accountAddress, List bencoded) - : this( - address, - accountAddress, - new Currency(bencoded[0]), - ((List)bencoded[1]).Select(v => new Currency(v)), - new Address(bencoded[2]), - new Address(bencoded[3]), - new Address(bencoded[4]), - new Address(bencoded[5]), - (Integer)bencoded[6], - (Integer)bencoded[7], - (Integer)bencoded[8], - ((List)bencoded[9]).Select(item => new Address(item)), - new FungibleAssetValue(bencoded[10]), - (Integer)bencoded[11], - (Bencodex.Types.Boolean)bencoded[12], - (Integer)bencoded[13], - (Bencodex.Types.Boolean)bencoded[14], - ((List)bencoded[15]).Select(item => new UnbondingRef(item))) { + Currency delegationCurrency; + IEnumerable< Currency > rewardCurrencies; + Address delegationPoolAddress; + Address rewardPoolAddress; + Address rewardRemainderPoolAddress; + Address slashedPoolAddress; + long unbondingPeriod; + int maxUnbondLockInEntries; + int maxRebondGraceEntries; + FungibleAssetValue totalDelegated; + BigInteger totalShares; + bool jailed; + long jailedUntil; + bool tombstoned; + IEnumerable unbondingRefs; + + // TODO: Remove this if block after migration to state version 1 is done. + if (bencoded[0] is not Text) + { + // Assume state version 0 + delegationCurrency = new Currency(bencoded[0]); + rewardCurrencies = ((List)bencoded[1]).Select(v => new Currency(v)); + delegationPoolAddress = new Address(bencoded[2]); + rewardPoolAddress = new Address(bencoded[3]); + rewardRemainderPoolAddress = new Address(bencoded[4]); + slashedPoolAddress = new Address(bencoded[5]); + unbondingPeriod = (Integer)bencoded[6]; + maxUnbondLockInEntries = (Integer)bencoded[7]; + maxRebondGraceEntries = (Integer)bencoded[8]; + totalDelegated = new FungibleAssetValue(bencoded[10]); + totalShares = (Integer)bencoded[11]; + jailed = (Bencodex.Types.Boolean)bencoded[12]; + jailedUntil = (Integer)bencoded[13]; + tombstoned = (Bencodex.Types.Boolean)bencoded[14]; + unbondingRefs = ((List)bencoded[15]).Select(item => new UnbondingRef(item)); + } + else + { + if (bencoded[0] is not Text text || text != StateTypeName || bencoded[1] is not Integer integer) + { + throw new InvalidCastException(); + } + + if (integer > StateVersion) + { + throw new FailedLoadStateException("Un-deserializable state."); + } + + delegationCurrency = new Currency(bencoded[2]); + rewardCurrencies = ((List)bencoded[3]).Select(v => new Currency(v)); + delegationPoolAddress = new Address(bencoded[4]); + rewardPoolAddress = new Address(bencoded[5]); + rewardRemainderPoolAddress = new Address(bencoded[6]); + slashedPoolAddress = new Address(bencoded[7]); + unbondingPeriod = (Integer)bencoded[8]; + maxUnbondLockInEntries = (Integer)bencoded[9]; + maxRebondGraceEntries = (Integer)bencoded[10]; + totalDelegated = new FungibleAssetValue(bencoded[11]); + totalShares = (Integer)bencoded[12]; + jailed = (Bencodex.Types.Boolean)bencoded[13]; + jailedUntil = (Integer)bencoded[14]; + tombstoned = (Bencodex.Types.Boolean)bencoded[15]; + unbondingRefs = ((List)bencoded[16]).Select(item => new UnbondingRef(item)); + } + + if (!totalDelegated.Currency.Equals(delegationCurrency)) + { + throw new InvalidOperationException("Invalid currency."); + } + + if (totalDelegated.Sign < 0) + { + throw new ArgumentOutOfRangeException( + nameof(totalDelegated), + totalDelegated, + "Total delegated must be non-negative."); + } + + if (totalShares.Sign < 0) + { + throw new ArgumentOutOfRangeException( + nameof(totalShares), + totalShares, + "Total shares must be non-negative."); + } + + DelegateeAddress = address; + DelegateeAccountAddress = accountAddress; + DelegationCurrency = delegationCurrency; + RewardCurrencies = rewardCurrencies.ToImmutableSortedSet(_currencyComparer); + DelegationPoolAddress = delegationPoolAddress; + RewardPoolAddress = rewardPoolAddress; + RewardRemainderPoolAddress = rewardRemainderPoolAddress; + SlashedPoolAddress = slashedPoolAddress; + UnbondingPeriod = unbondingPeriod; + MaxUnbondLockInEntries = maxUnbondLockInEntries; + MaxRebondGraceEntries = maxRebondGraceEntries; + TotalDelegatedFAV = totalDelegated; + TotalShares = totalShares; + Jailed = jailed; + JailedUntil = jailedUntil; + Tombstoned = tombstoned; + UnbondingRefs = unbondingRefs.ToImmutableSortedSet(); } private DelegateeMetadata( @@ -96,7 +183,6 @@ private DelegateeMetadata( long unbondingPeriod, int maxUnbondLockInEntries, int maxRebondGraceEntries, - IEnumerable
delegators, FungibleAssetValue totalDelegated, BigInteger totalShares, bool jailed, @@ -136,7 +222,6 @@ private DelegateeMetadata( UnbondingPeriod = unbondingPeriod; MaxUnbondLockInEntries = maxUnbondLockInEntries; MaxRebondGraceEntries = maxRebondGraceEntries; - Delegators = delegators.ToImmutableSortedSet(); TotalDelegatedFAV = totalDelegated; TotalShares = totalShares; Jailed = jailed; @@ -172,8 +257,6 @@ public Address Address public int MaxRebondGraceEntries { get; } - public ImmutableSortedSet
Delegators { get; private set; } - public FungibleAssetValue TotalDelegatedFAV { get; private set; } public BigInteger TotalShares { get; private set; } @@ -188,6 +271,8 @@ public Address Address // TODO : Better serialization public List Bencoded => List.Empty + .Add(StateTypeName) + .Add(StateVersion) .Add(DelegationCurrency.Serialize()) .Add(new List(RewardCurrencies.Select(c => c.Serialize()))) .Add(DelegationPoolAddress.Bencoded) @@ -197,7 +282,6 @@ public Address Address .Add(UnbondingPeriod) .Add(MaxUnbondLockInEntries) .Add(MaxRebondGraceEntries) - .Add(new List(Delegators.Select(delegator => delegator.Bencoded))) .Add(TotalDelegatedFAV.Serialize()) .Add(TotalShares) .Add(Jailed) @@ -217,16 +301,6 @@ public FungibleAssetValue FAVFromShare(BigInteger share) ? TotalDelegatedFAV : (TotalDelegatedFAV * share).DivRem(TotalShares).Quotient; - public void AddDelegator(Address delegatorAddress) - { - Delegators = Delegators.Add(delegatorAddress); - } - - public void RemoveDelegator(Address delegatorAddress) - { - Delegators = Delegators.Remove(delegatorAddress); - } - public void AddDelegatedFAV(FungibleAssetValue fav) { TotalDelegatedFAV += fav; @@ -289,7 +363,6 @@ public virtual bool Equals(IDelegateeMetadata? other) && SlashedPoolAddress.Equals(delegatee.SlashedPoolAddress) && UnbondingPeriod == delegatee.UnbondingPeriod && RewardPoolAddress.Equals(delegatee.RewardPoolAddress) - && Delegators.SequenceEqual(delegatee.Delegators) && TotalDelegatedFAV.Equals(delegatee.TotalDelegatedFAV) && TotalShares.Equals(delegatee.TotalShares) && Jailed == delegatee.Jailed diff --git a/Lib9c/Delegation/Delegator.cs b/Lib9c/Delegation/Delegator.cs index 92c036f850..044d6a7f91 100644 --- a/Lib9c/Delegation/Delegator.cs +++ b/Lib9c/Delegation/Delegator.cs @@ -109,7 +109,7 @@ public virtual void Undelegate( unbondLockIn = unbondLockIn.LockIn( fav, height, height + delegatee.UnbondingPeriod); - if (!delegatee.Delegators.Contains(Address)) + if (Repository.GetBond(delegatee, Address).Share.IsZero) { Metadata.RemoveDelegatee(delegatee.Address); } @@ -157,7 +157,7 @@ public virtual void Redelegate( height, height + srcDelegatee.UnbondingPeriod); - if (!srcDelegatee.Delegators.Contains(Address)) + if (Repository.GetBond(srcDelegatee, Address).Share.IsZero) { Metadata.RemoveDelegatee(srcDelegatee.Address); } diff --git a/Lib9c/Delegation/IDelegatee.cs b/Lib9c/Delegation/IDelegatee.cs index 458214a81b..9cb3503613 100644 --- a/Lib9c/Delegation/IDelegatee.cs +++ b/Lib9c/Delegation/IDelegatee.cs @@ -29,8 +29,6 @@ public interface IDelegatee Address RewardPoolAddress { get; } - ImmutableSortedSet
Delegators { get; } - FungibleAssetValue TotalDelegated { get; } BigInteger TotalShares { get; } diff --git a/Lib9c/Delegation/IDelegateeMetadata.cs b/Lib9c/Delegation/IDelegateeMetadata.cs index 8a135ef541..dcaeff072b 100644 --- a/Lib9c/Delegation/IDelegateeMetadata.cs +++ b/Lib9c/Delegation/IDelegateeMetadata.cs @@ -1,6 +1,4 @@ #nullable enable -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Numerics; using Bencodex; @@ -33,8 +31,6 @@ public interface IDelegateeMetadata : IBencodable Address RewardPoolAddress { get; } - ImmutableSortedSet
Delegators { get; } - FungibleAssetValue TotalDelegatedFAV { get; } BigInteger TotalShares { get; } diff --git a/Lib9c/Delegation/LumpSumRewardsRecord.cs b/Lib9c/Delegation/LumpSumRewardsRecord.cs index e2e79b3e4b..715bcdf511 100644 --- a/Lib9c/Delegation/LumpSumRewardsRecord.cs +++ b/Lib9c/Delegation/LumpSumRewardsRecord.cs @@ -8,24 +8,25 @@ using Bencodex; using Libplanet.Crypto; using Libplanet.Types.Assets; +using Nekoyume.Action; namespace Nekoyume.Delegation { public class LumpSumRewardsRecord : IBencodable, IEquatable { + private const string StateTypeName = "lump_sum_rewards_record"; + private const long StateVersion = 1; private readonly IComparer _currencyComparer = new CurrencyComparer(); public LumpSumRewardsRecord( Address address, long startHeight, BigInteger totalShares, - ImmutableSortedSet
delegators, IEnumerable currencies) : this( address, startHeight, totalShares, - delegators, currencies, null) { @@ -35,14 +36,12 @@ public LumpSumRewardsRecord( Address address, long startHeight, BigInteger totalShares, - ImmutableSortedSet
delegators, IEnumerable currencies, long? lastStartHeight) : this( address, startHeight, totalShares, - delegators, currencies.Select(c => c * 0), lastStartHeight) { @@ -52,14 +51,12 @@ public LumpSumRewardsRecord( Address address, long startHeight, BigInteger totalShares, - ImmutableSortedSet
delegators, IEnumerable lumpSumRewards, long? lastStartHeight) { Address = address; StartHeight = startHeight; TotalShares = totalShares; - Delegators = delegators; if (!lumpSumRewards.Select(f => f.Currency).All(new HashSet().Add)) { @@ -76,28 +73,62 @@ public LumpSumRewardsRecord(Address address, IValue bencoded) } public LumpSumRewardsRecord(Address address, List bencoded) - : this( - address, - (Integer)bencoded[0], - (Integer)bencoded[1], - ((List)bencoded[2]).Select(a => new Address(a)).ToImmutableSortedSet(), - ((List)bencoded[3]).Select(v => new FungibleAssetValue(v)), - (Integer?)bencoded.ElementAtOrDefault(4)) { + long startHeight; + BigInteger totalShares; + IEnumerable lumpSumRewards; + long? lastStartHeight; + + // TODO: Remove this if block after migration to state version 1 is done. + if (bencoded[0] is not Text) + { + // Assume state version 0 + startHeight = (Integer)bencoded[0]; + totalShares = (Integer)bencoded[1]; + lumpSumRewards = ((List)bencoded[3]).Select(v => new FungibleAssetValue(v)); + lastStartHeight = (Integer?)bencoded.ElementAtOrDefault(4); + } + else + { + if (bencoded[0] is not Text text || text != StateTypeName || bencoded[1] is not Integer integer) + { + throw new InvalidCastException(); + } + + if (integer > StateVersion) + { + throw new FailedLoadStateException("Un-deserializable state."); + } + + startHeight = (Integer)bencoded[2]; + totalShares = (Integer)bencoded[3]; + lumpSumRewards = ((List)bencoded[4]).Select(v => new FungibleAssetValue(v)); + lastStartHeight = (Integer?)bencoded.ElementAtOrDefault(5); + } + + Address = address; + StartHeight = startHeight; + TotalShares = totalShares; + + if (!lumpSumRewards.Select(f => f.Currency).All(new HashSet().Add)) + { + throw new ArgumentException("Duplicated currency in lump sum rewards."); + } + + LumpSumRewards = lumpSumRewards.ToImmutableDictionary(f => f.Currency, f => f); + LastStartHeight = lastStartHeight; } private LumpSumRewardsRecord( Address address, long startHeight, BigInteger totalShares, - ImmutableSortedSet
delegators, ImmutableDictionary lumpSumRewards, long? lastStartHeight) { Address = address; StartHeight = startHeight; TotalShares = totalShares; - Delegators = delegators; LumpSumRewards = lumpSumRewards; LastStartHeight = lastStartHeight; } @@ -110,8 +141,6 @@ private LumpSumRewardsRecord( public ImmutableDictionary LumpSumRewards { get; } - public ImmutableSortedSet
Delegators { get; } - public long? LastStartHeight { get; } public List Bencoded @@ -119,9 +148,10 @@ public List Bencoded get { var bencoded = List.Empty + .Add(StateTypeName) + .Add(StateVersion) .Add(StartHeight) .Add(TotalShares) - .Add(new List(Delegators.Select(a => a.Bencoded))) .Add(new List(LumpSumRewards .OrderBy(r => r.Key, _currencyComparer) .Select(r => r.Value.Serialize()))); @@ -139,7 +169,6 @@ public LumpSumRewardsRecord MoveAddress(Address address) address, StartHeight, TotalShares, - Delegators, LumpSumRewards, LastStartHeight); @@ -154,21 +183,11 @@ public static LumpSumRewardsRecord AddLumpSumRewards(LumpSumRewardsRecord record record.Address, record.StartHeight, record.TotalShares, - record.Delegators, record.LumpSumRewards.TryGetValue(rewards.Currency, out var cumulative) ? record.LumpSumRewards.SetItem(rewards.Currency, cumulative + rewards) : throw new ArgumentException($"Invalid reward currency: {rewards.Currency}"), record.LastStartHeight); - public LumpSumRewardsRecord RemoveDelegator(Address delegator) - => new LumpSumRewardsRecord( - Address, - StartHeight, - TotalShares, - Delegators.Remove(delegator), - LumpSumRewards, - LastStartHeight); - public ImmutableSortedDictionary RewardsDuringPeriod(BigInteger share) => LumpSumRewards.Keys.Select(k => RewardsDuringPeriod(share, k)) .ToImmutableSortedDictionary(f => f.Currency, f => f, _currencyComparer); @@ -189,8 +208,7 @@ public bool Equals(LumpSumRewardsRecord? other) && StartHeight == lumpSumRewardRecord.StartHeight && TotalShares == lumpSumRewardRecord.TotalShares && LumpSumRewards.Equals(lumpSumRewardRecord.LumpSumRewards) - && LastStartHeight == lumpSumRewardRecord.LastStartHeight - && Delegators.SequenceEqual(lumpSumRewardRecord.Delegators)); + && LastStartHeight == lumpSumRewardRecord.LastStartHeight); public override int GetHashCode() => Address.GetHashCode(); diff --git a/Lib9c/Lib9c.csproj b/Lib9c/Lib9c.csproj index 783bb66bb4..adebb3dc14 100644 --- a/Lib9c/Lib9c.csproj +++ b/Lib9c/Lib9c.csproj @@ -9,7 +9,7 @@ .obj Nekoyume 9 - 1.20.0 + 1.20.1 true Debug;Release AnyCPU