diff --git a/x/farming/keeper/reward.go b/x/farming/keeper/reward.go index 41c00784..a5b6f0a9 100644 --- a/x/farming/keeper/reward.go +++ b/x/farming/keeper/reward.go @@ -10,10 +10,14 @@ import ( "github.com/tendermint/farming/x/farming/types" ) -func (k Keeper) GetHistoricalRewards(ctx sdk.Context, stakingCoinDenom string, epoch uint64) (rewards types.HistoricalRewards) { +func (k Keeper) GetHistoricalRewards(ctx sdk.Context, stakingCoinDenom string, epoch uint64) (rewards types.HistoricalRewards, found bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(types.GetHistoricalRewardsKey(stakingCoinDenom, epoch)) + if bz == nil { + return + } k.cdc.MustUnmarshal(bz, &rewards) + found = true return } @@ -132,8 +136,8 @@ func (k Keeper) CalculateRewards(ctx sdk.Context, farmerAcc sdk.AccAddress, stak return sdk.NewDecCoins() } - starting := k.GetHistoricalRewards(ctx, stakingCoinDenom, staking.StartingEpoch-1) - ending := k.GetHistoricalRewards(ctx, stakingCoinDenom, endingEpoch) + starting, _ := k.GetHistoricalRewards(ctx, stakingCoinDenom, staking.StartingEpoch-1) + ending, _ := k.GetHistoricalRewards(ctx, stakingCoinDenom, endingEpoch) diff := ending.CumulativeUnitRewards.Sub(starting.CumulativeUnitRewards) rewards = diff.MulDecTruncate(staking.Amount.ToDec()) return @@ -335,7 +339,7 @@ func (k Keeper) AllocateRewards(ctx sdk.Context) error { for stakingCoinDenom, unitRewards := range unitRewardsByDenom { currentEpoch := k.GetCurrentEpoch(ctx, stakingCoinDenom) - historical := k.GetHistoricalRewards(ctx, stakingCoinDenom, currentEpoch-1) + historical, _ := k.GetHistoricalRewards(ctx, stakingCoinDenom, currentEpoch-1) k.SetHistoricalRewards(ctx, stakingCoinDenom, currentEpoch, types.HistoricalRewards{ CumulativeUnitRewards: historical.CumulativeUnitRewards.Add(unitRewards...), }) diff --git a/x/farming/keeper/reward_test.go b/x/farming/keeper/reward_test.go index fbc7754c..27e1eb83 100644 --- a/x/farming/keeper/reward_test.go +++ b/x/farming/keeper/reward_test.go @@ -310,3 +310,46 @@ func (suite *KeeperTestSuite) TestHarvest() { func (suite *KeeperTestSuite) TestMultipleHarvest() { // TODO: implement } + +func (suite *KeeperTestSuite) TestHistoricalRewards() { + suite.ctx = suite.ctx.WithBlockTime(types.ParseTime("2021-08-06T00:00:00Z")) + + // Create two plans that share same staking coin denom in their staking coin weights. + suite.SetFixedAmountPlan(1, suite.addrs[4], map[string]string{denom1: "1"}, map[string]int64{denom3: 1000000}) + suite.SetFixedAmountPlan(2, suite.addrs[4], map[string]string{denom1: "1"}, map[string]int64{denom3: 1000000}) + + // Advancing epoch(s) before any staking is made doesn't create any historical rewards records. + suite.AdvanceEpoch() + suite.AdvanceEpoch() + count := 0 + suite.keeper.IterateHistoricalRewards(suite.ctx, func(stakingCoinDenom string, epoch uint64, rewards types.HistoricalRewards) (stop bool) { + count++ + return false + }) + suite.Equal(count, 0) + + suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) + // Advancing epoch here marks queued staking coins as staked. + suite.AdvanceEpoch() + + // After a farmer has staked(not queued) coins, historical rewards records will be created for each epoch. + // Here we advance epoch three times, and this will create 3 historical rewards records. + suite.AdvanceEpoch() + suite.AdvanceEpoch() + suite.AdvanceEpoch() + + // First, ensure that we have only 3 entries in the store. + count = 0 + suite.keeper.IterateHistoricalRewards(suite.ctx, func(stakingCoinDenom string, epoch uint64, rewards types.HistoricalRewards) (stop bool) { + count++ + return false + }) + suite.Require().Equal(count, 3) + + // Next, check if cumulative unit rewards is correct. + for i := uint64(0); i < 3; i++ { + historical, found := suite.keeper.GetHistoricalRewards(suite.ctx, denom1, i) + suite.Require().True(found) + suite.Require().True(decCoinsEq(sdk.NewDecCoins(sdk.NewInt64DecCoin(denom3, int64((i+1)*2))), historical.CumulativeUnitRewards)) + } +}