diff --git a/Lib9c/Delegation/Delegatee.cs b/Lib9c/Delegation/Delegatee.cs index 1aa75e5211..6590f68b8e 100644 --- a/Lib9c/Delegation/Delegatee.cs +++ b/Lib9c/Delegation/Delegatee.cs @@ -285,7 +285,7 @@ public void CollectRewards(long height) var rewards = RewardCurrencies.Select(c => Repository.GetBalance(RewardPoolAddress, c)); if (Repository.GetCurrentRewardBase(this) is RewardBase rewardBase) { - rewardBase = rewardBase.AddRewards(rewards); + rewardBase = rewardBase.AddRewards(rewards, TotalShares); foreach (var rewardsEach in rewards) { @@ -411,7 +411,7 @@ public void StartNewRewardPeriod(long height) RewardBase newRewardBase; if (Repository.GetCurrentRewardBase(this) is RewardBase rewardBase) { - newRewardBase = rewardBase.UpdateTotalShares(TotalShares); + newRewardBase = rewardBase.UpdateSigFig(TotalShares); if (Repository.GetRewardBase(this, height) is not null) { Repository.SetRewardBase(newRewardBase); @@ -542,7 +542,6 @@ record = Repository.GetLumpSumRewardsRecord(this, lastStartHeight) } RewardBase? rewardBase = null; - RewardBase? newRewardBase = null; for (var i = records.Count - 1; i >= 0; i--) { var recordEach = records[i]; @@ -556,7 +555,7 @@ record = Repository.GetLumpSumRewardsRecord(this, lastStartHeight) } else { - newRewardBase = rewardBase.UpdateTotalShares(recordEach.TotalShares); + var newRewardBase = rewardBase.UpdateSigFig(recordEach.TotalShares); if (Repository.GetRewardBase(this, recordEach.StartHeight) is not null) { Repository.SetRewardBase(newRewardBase); @@ -571,7 +570,7 @@ record = Repository.GetLumpSumRewardsRecord(this, lastStartHeight) rewardBase = newRewardBase; } - rewardBase = rewardBase.AddRewards(recordEach.LumpSumRewards.Values); + rewardBase = rewardBase.AddRewards(recordEach.LumpSumRewards.Values, recordEach.TotalShares); foreach (var r in recordEach.LumpSumRewards) { var toTransfer = Repository.GetBalance(recordEach.Address, r.Key); diff --git a/Lib9c/Delegation/RewardBase.cs b/Lib9c/Delegation/RewardBase.cs index 18102d0c26..7b1eb491ac 100644 --- a/Lib9c/Delegation/RewardBase.cs +++ b/Lib9c/Delegation/RewardBase.cs @@ -48,7 +48,6 @@ public RewardBase( IEnumerable currencies) : this( address, - totalShares, currencies.Select(c => (c, BigInteger.Zero)), RecommendedSigFig(totalShares), null) @@ -99,8 +98,7 @@ public RewardBase(Address address, List bencoded) } Address = address; - TotalShares = (Integer)bencoded[2]; - var bencodedRewardPortion = ((List)bencoded[3]).Select(v => (List)v); + var bencodedRewardPortion = ((List)bencoded[2]).Select(v => (List)v); var rewardPortion = bencodedRewardPortion.Select( p => (Currency: new Currency(p[0]), Portion: (BigInteger)(Integer)p[1])); @@ -110,11 +108,11 @@ public RewardBase(Address address, List bencoded) } RewardPortion = rewardPortion.ToImmutableSortedDictionary(f => f.Currency, f => f.Portion, _currencyComparer); - SigFig = (Integer)bencoded[4]; + SigFig = (Integer)bencoded[3]; try { - StartHeight = (Integer)bencoded[5]; + StartHeight = (Integer)bencoded[4]; } catch (IndexOutOfRangeException) { @@ -124,12 +122,34 @@ public RewardBase(Address address, List bencoded) /// /// Constructor for new . + /// This constructor is used only for the initial reward base creation. /// /// /// of . /// - /// - /// of 's creation height. + /// + /// of 's creation height. + /// It initializes the reward portion with 0. + /// + /// Significant figure of . + /// + private RewardBase( + Address address, + IEnumerable currencies, + int sigFig) + : this( + address, + currencies.Select(c => (c, BigInteger.Zero)), + sigFig, + null) + { + } + + /// + /// Constructor for new . + /// + /// + /// of . /// /// /// Cumulative reward portion of 's creation height. @@ -148,20 +168,12 @@ public RewardBase(Address address, List bencoded) /// private RewardBase( Address address, - BigInteger totalShares, IEnumerable<(Currency, BigInteger)> rewardPortion, int sigFig, long? startHeight = null) { Address = address; - if (totalShares.Sign <= 0) - { - throw new ArgumentOutOfRangeException(nameof(totalShares)); - } - - TotalShares = totalShares; - if (!rewardPortion.Select(f => f.Item1).All(new HashSet().Add)) { throw new ArgumentException("Duplicated currency in reward base."); @@ -178,9 +190,6 @@ private RewardBase( /// /// of . /// - /// - /// of 's creation height. - /// /// /// Cumulative reward portion of 's creation height. /// @@ -192,13 +201,11 @@ private RewardBase( /// private RewardBase( Address address, - BigInteger totalShares, ImmutableSortedDictionary rewardPortion, int sigFig, long? startHeight = null) { Address = address; - TotalShares = totalShares; RewardPortion = rewardPortion; SigFig = sigFig; StartHeight = startHeight; @@ -209,11 +216,6 @@ private RewardBase( /// public Address Address { get; } - /// - /// of 's creation height. - /// - public BigInteger TotalShares { get; } - /// /// Cumulative reward portion of . /// When it's multiplied by the number of shares, it will be the reward for the period. @@ -237,7 +239,6 @@ public List Bencoded var bencoded = List.Empty .Add(StateTypeName) .Add(StateVersion) - .Add(TotalShares) .Add(new List(RewardPortion .OrderBy(r => r.Key, _currencyComparer) .Select(r => new List(r.Key.Serialize(), new Integer(r.Value))))) @@ -257,11 +258,13 @@ public List Bencoded /// /// Rewards to add. /// + /// + /// used as denominator of the portion. /// /// New with added rewards. /// - public RewardBase AddRewards(IEnumerable rewards) - => rewards.Aggregate(this, (accum, next) => AddReward(accum, next)); + public RewardBase AddRewards(IEnumerable rewards, BigInteger totalShares) + => rewards.Aggregate(this, (accum, next) => AddReward(accum, next, totalShares)); /// /// Add reward to the . @@ -269,23 +272,26 @@ public RewardBase AddRewards(IEnumerable rewards) /// /// Reward to add. /// + /// + /// used as denominator of the portion. + /// /// /// New with added reward. /// - public RewardBase AddReward(FungibleAssetValue reward) - => AddReward(this, reward); + public RewardBase AddReward(FungibleAssetValue reward, BigInteger totalShares) + => AddReward(this, reward, totalShares); /// /// Update the total shares of the . /// /// - /// New of the height that created. + /// used as denominator of the portion. /// /// /// New with updated total shares. /// - public RewardBase UpdateTotalShares(BigInteger totalShares) - => UpdateTotalShares(this, totalShares); + public RewardBase UpdateSigFig(BigInteger totalShares) + => UpdateSigFig(this, totalShares); /// /// Attach the start height to the to be archived. @@ -306,7 +312,6 @@ public RewardBase AttachHeight(Address address, long startHeight) => StartHeight is null ? new RewardBase( address, - TotalShares, RewardPortion, SigFig, startHeight) @@ -345,7 +350,7 @@ public FungibleAssetValue CumulativeRewardDuringPeriod(BigInteger share, Currenc ? FungibleAssetValue.FromRawValue(currency, (portion * share) / (Multiplier(SigFig))) : throw new ArgumentException($"Invalid reward currency: {currency}"); - private static RewardBase AddReward(RewardBase rewardBase, FungibleAssetValue reward) + private static RewardBase AddReward(RewardBase rewardBase, FungibleAssetValue reward, BigInteger totalShares) { if (!rewardBase.RewardPortion.TryGetValue(reward.Currency, out var portion)) { @@ -354,17 +359,16 @@ private static RewardBase AddReward(RewardBase rewardBase, FungibleAssetValue re } var portionNumerator = reward.RawValue * Multiplier(rewardBase.SigFig); - var updatedPortion = portion + (portionNumerator / rewardBase.TotalShares); + var updatedPortion = portion + (portionNumerator / totalShares); return new RewardBase( rewardBase.Address, - rewardBase.TotalShares, rewardBase.RewardPortion.SetItem(reward.Currency, updatedPortion), rewardBase.SigFig, rewardBase.StartHeight); } - private static RewardBase UpdateTotalShares(RewardBase rewardBase, BigInteger totalShares) + private static RewardBase UpdateSigFig(RewardBase rewardBase, BigInteger totalShares) { var newSigFig = Math.Max(rewardBase.SigFig, RecommendedSigFig(totalShares)); var multiplier = Multiplier(newSigFig - rewardBase.SigFig); @@ -375,12 +379,11 @@ private static RewardBase UpdateTotalShares(RewardBase rewardBase, BigInteger to return new RewardBase( rewardBase.Address, - totalShares, newPortion, newSigFig); } - private static int RecommendedSigFig(BigInteger totalShares) + public static int RecommendedSigFig(BigInteger totalShares) => (int)Math.Floor(BigInteger.Log10(totalShares)) + Margin; private static BigInteger Multiplier(int sigFig) @@ -393,7 +396,6 @@ public bool Equals(RewardBase? other) => ReferenceEquals(this, other) || (other is RewardBase rewardBase && Address == rewardBase.Address - && TotalShares == rewardBase.TotalShares && RewardPortion.SequenceEqual(rewardBase.RewardPortion) && SigFig == rewardBase.SigFig && StartHeight == rewardBase.StartHeight);