From 7102012ea4cbf43676f6ee3fc9de80a0016455e5 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 8 Dec 2023 17:07:50 +0100 Subject: [PATCH] Factor out decay end epoch into dedicated function --- .../sybilprotectionv1/performance/rewards.go | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/pkg/protocol/sybilprotection/sybilprotectionv1/performance/rewards.go b/pkg/protocol/sybilprotection/sybilprotectionv1/performance/rewards.go index 1f3d10e4a..61b344e69 100644 --- a/pkg/protocol/sybilprotection/sybilprotectionv1/performance/rewards.go +++ b/pkg/protocol/sybilprotection/sybilprotectionv1/performance/rewards.go @@ -4,6 +4,7 @@ import ( "github.com/iotaledger/hive.go/ads" "github.com/iotaledger/hive.go/core/safemath" "github.com/iotaledger/hive.go/ierrors" + "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/iota-core/pkg/model" iotago "github.com/iotaledger/iota.go/v4" ) @@ -29,19 +30,13 @@ func (t *Tracker) ValidatorReward(validatorID iotago.AccountID, stakingFeature * firstRewardEpoch = stakingFeature.StartEpoch lastRewardEpoch = stakingFeature.EndEpoch - // When claiming rewards in epoch X for epoch X-1, decay of X-(X-1) = 1 would be applied. Since epoch X is the - // very first epoch in which one can claim those rewards, decaying by 1 is odd, as one could never claim the full reward then. - // Hence, deduct one epoch worth of decay. - claimingEpoch, err = safemath.SafeSub(claimingEpoch, 1) - if err != nil { - return 0, 0, 0, ierrors.Wrapf(err, "claimingEpoch must be set to at least 1") - } - // Limit reward fetching only to committed epochs. if lastRewardEpoch > t.latestAppliedEpoch { lastRewardEpoch = t.latestAppliedEpoch } + decayEndEpoch := t.decayEndEpoch(claimingEpoch, lastRewardEpoch) + for epoch := firstRewardEpoch; epoch <= lastRewardEpoch; epoch++ { rewardsForAccountInEpoch, exists, err := t.rewardsForAccount(validatorID, epoch) if err != nil { @@ -106,7 +101,7 @@ func (t *Tracker) ValidatorReward(validatorID iotago.AccountID, stakingFeature * } decayProvider := t.apiProvider.APIForEpoch(epoch).ManaDecayProvider() - decayedEpochRewards, err := decayProvider.DecayManaByEpochs(iotago.Mana(undecayedEpochRewards), epoch, claimingEpoch) + decayedEpochRewards, err := decayProvider.DecayManaByEpochs(iotago.Mana(undecayedEpochRewards), epoch, decayEndEpoch) if err != nil { return 0, 0, 0, ierrors.Wrapf(err, "failed to calculate rewards with decay for epoch %d and validator accountID %s", epoch, validatorID) } @@ -129,19 +124,13 @@ func (t *Tracker) DelegatorReward(validatorID iotago.AccountID, delegatedAmount firstRewardEpoch = epochStart lastRewardEpoch = epochEnd - // When claiming rewards in epoch X for epoch X-1, decay of X-(X-1) = 1 would be applied. Since epoch X is the - // very first epoch in which one can claim those rewards, decaying by 1 is odd, as one could never claim the full reward then. - // Hence, deduct one epoch worth of decay. - claimingEpoch, err = safemath.SafeSub(claimingEpoch, 1) - if err != nil { - return 0, 0, 0, ierrors.Wrapf(err, "claimingEpoch must be set to at least 1") - } - // limit looping to committed epochs if lastRewardEpoch > t.latestAppliedEpoch { lastRewardEpoch = t.latestAppliedEpoch } + decayEndEpoch := t.decayEndEpoch(claimingEpoch, lastRewardEpoch) + for epoch := firstRewardEpoch; epoch <= lastRewardEpoch; epoch++ { rewardsForAccountInEpoch, exists, err := t.rewardsForAccount(validatorID, epoch) if err != nil { @@ -194,7 +183,7 @@ func (t *Tracker) DelegatorReward(validatorID iotago.AccountID, delegatedAmount } decayProvider := t.apiProvider.APIForEpoch(epoch).ManaDecayProvider() - decayedEpochRewards, err := decayProvider.DecayManaByEpochs(iotago.Mana(undecayedEpochRewards), epoch, claimingEpoch) + decayedEpochRewards, err := decayProvider.DecayManaByEpochs(iotago.Mana(undecayedEpochRewards), epoch, decayEndEpoch) if err != nil { return 0, 0, 0, ierrors.Wrapf(err, "failed to calculate rewards with decay for epoch %d and validator accountID %s", epoch, validatorID) } @@ -205,6 +194,23 @@ func (t *Tracker) DelegatorReward(validatorID iotago.AccountID, delegatedAmount return delegatorsReward, firstRewardEpoch, lastRewardEpoch, nil } +// Returns the epoch until which rewards are decayed. +// +// When claiming rewards in epoch X for epoch X-1, decay of X-(X-1) = 1 would be applied. Since epoch X is the +// very first epoch in which one can claim those rewards, decaying by 1 is odd, as one could never claim the full reward then. +// Hence, one epoch worth of decay is deducted in general. +// +// The decay end epoch must however be greater or equal than the last epoch for which rewards are claimed, otherwise +// the decay operation would fail since the amount of epochs to decay would be negative. +// Hence, the smallest returned decay end epoch will be the lastRewardEpoch. +func (t *Tracker) decayEndEpoch(claimingEpoch iotago.EpochIndex, lastRewardEpoch iotago.EpochIndex) iotago.EpochIndex { + if claimingEpoch >= 1 { + claimingEpoch = claimingEpoch - 1 + } + + return lo.Max(claimingEpoch, lastRewardEpoch) +} + func (t *Tracker) rewardsMap(epoch iotago.EpochIndex) (ads.Map[iotago.Identifier, iotago.AccountID, *model.PoolRewards], error) { kv, err := t.rewardsStorePerEpochFunc(epoch) if err != nil {