Skip to content

Commit

Permalink
fix: HandleRewarding gaps of unfinalized blocks (#378)
Browse files Browse the repository at this point in the history
Prior to this fix, if we had an unfinalized block it would stuck to it
as a next block to be rewarded


By using `continue` instead of `break`, if there is any finalized block
in the interval (`nextBlockToBeRewarded` and `targetHeight`) it will
give out rewards and update the next block to be rewarded
  • Loading branch information
RafilxTenfen authored Jan 3, 2025
1 parent aaac0d4 commit 372e67b
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

- [#374](https://github.com/babylonlabs-io/babylon/pull/374) Fix non-consecutive finalization
of the block in `TallyBlocks` function
- [#378](https://github.com/babylonlabs-io/babylon/pull/378) Fix give out rewards
with gaps of unfinalized blocks

## v1.0.0-rc2

Expand Down
3 changes: 2 additions & 1 deletion x/finality/keeper/rewarding.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/babylonlabs-io/babylon/x/finality/types"
)

// HandleRewarding calls the reward to stakers if the block is finalized
func (k Keeper) HandleRewarding(ctx context.Context, targetHeight int64) {
// rewarding is executed in a range of [nextHeightToReward, heightToExamine]
// this is we don't know when a block will be finalized and we need ensure
Expand All @@ -30,7 +31,7 @@ func (k Keeper) HandleRewarding(ctx context.Context, targetHeight int64) {
panic(err)
}
if !block.Finalized {
break
continue
}
k.rewardBTCStaking(ctx, height)
nextHeightToReward = height + 1
Expand Down
63 changes: 60 additions & 3 deletions x/finality/keeper/rewarding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper_test
import (
"math/rand"
"testing"
"time"

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -57,8 +58,8 @@ func FuzzHandleRewarding(f *testing.F) {
fKeeper.HandleRewarding(ctx, int64(targetHeight))

nextHeight := fKeeper.GetNextHeightToReward(ctx)
require.Equal(t, uint64(0), nextHeight,
"next height is not updated when no blocks finalized")
require.Zero(t, nextHeight,
"next height is not updated when no blocks finalized. Act: %d", nextHeight)

// Second phase: Finalize some blocks
firstBatchFinalized := datagen.RandomInt(r, 5) + 1
Expand All @@ -81,7 +82,7 @@ func FuzzHandleRewarding(f *testing.F) {
nextHeight = fKeeper.GetNextHeightToReward(ctx)
expectedNextHeight := activatedHeight + firstBatchFinalized
require.Equal(t, expectedNextHeight, nextHeight,
"next height should be after first batch of finalized blocks")
"next height should be after first batch of finalized blocks. Exp: %d, Act: %d", expectedNextHeight, nextHeight)

// Third phase: Finalize more blocks
secondBatchFinalized := datagen.RandomInt(r, int(totalBlocks-firstBatchFinalized)) + 1
Expand All @@ -108,3 +109,59 @@ func FuzzHandleRewarding(f *testing.F) {
"next height should be after second batch of finalized blocks")
})
}

func TestHandleRewardingWithGapsOfUnfinalizedBlocks(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

r := rand.New(rand.NewSource(time.Now().Unix()))

// Setup keepers
bsKeeper := types.NewMockBTCStakingKeeper(ctrl)
iKeeper := types.NewMockIncentiveKeeper(ctrl)
cKeeper := types.NewMockCheckpointingKeeper(ctrl)
fKeeper, ctx := keepertest.FinalityKeeper(t, bsKeeper, iKeeper, cKeeper)

fpPK, err := datagen.GenRandomBIP340PubKey(r)
require.NoError(t, err)
fKeeper.SetVotingPower(ctx, fpPK.MustMarshal(), 1, 1)

// starts rewarding at block 1
fKeeper.SetNextHeightToReward(ctx, 1)

fKeeper.SetBlock(ctx, &types.IndexedBlock{
Height: 1,
AppHash: datagen.GenRandomByteArray(r, 32),
Finalized: true,
})

fKeeper.SetBlock(ctx, &types.IndexedBlock{
Height: 2,
AppHash: datagen.GenRandomByteArray(r, 32),
Finalized: false,
})

// adds the latest finalized block
fKeeper.SetBlock(ctx, &types.IndexedBlock{
Height: 3,
AppHash: datagen.GenRandomByteArray(r, 32),
Finalized: true,
})
dc := types.NewVotingPowerDistCache()
dc.AddFinalityProviderDistInfo(&types.FinalityProviderDistInfo{
BtcPk: fpPK,
TotalBondedSat: 1,
})
fKeeper.SetVotingPowerDistCache(ctx, 1, dc)
fKeeper.SetVotingPowerDistCache(ctx, 3, dc)

iKeeper.EXPECT().
RewardBTCStaking(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
Return().
Times(2) // number of finalized blocks processed

fKeeper.HandleRewarding(ctx, 3)

actNextBlockToBeRewarded := fKeeper.GetNextHeightToReward(ctx)
require.Equal(t, uint64(4), actNextBlockToBeRewarded)
}

0 comments on commit 372e67b

Please sign in to comment.