Skip to content

Commit

Permalink
test: improve emissions module coverage (#1955)
Browse files Browse the repository at this point in the history
  • Loading branch information
skosito authored Apr 2, 2024
1 parent f0dfb6c commit 62999f6
Show file tree
Hide file tree
Showing 13 changed files with 495 additions and 3 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
* [1879](https://github.com/zeta-chain/node/pull/1879) - full coverage for messages in types packages
* [1899](https://github.com/zeta-chain/node/pull/1899) - add empty test files so packages are included in coverage
* [1903](https://github.com/zeta-chain/node/pull/1903) - common package tests
* [1955](https://github.com/zeta-chain/node/pull/1955) - improve emissions module coverage

### Fixes

Expand Down
6 changes: 6 additions & 0 deletions testutil/keeper/emissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,9 @@ func GetEmissionsParamStoreMock(t testing.TB, keeper *keeper.Keeper) *emissionsm
require.True(t, ok)
return m
}

func GetEmissionsStakingMock(t testing.TB, keeper *keeper.Keeper) *emissionsmocks.EmissionStakingKeeper {
cbk, ok := keeper.GetStakingKeeper().(*emissionsmocks.EmissionStakingKeeper)
require.True(t, ok)
return cbk
}
2 changes: 1 addition & 1 deletion x/emissions/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func BeginBlocker(ctx sdk.Context, keeper keeper.Keeper) {
// This function uses the distribution module of cosmos-sdk , by directly sending funds to the feecollector.
func DistributeValidatorRewards(ctx sdk.Context, amount sdkmath.Int, bankKeeper types.BankKeeper, feeCollector string) error {
coin := sdk.NewCoins(sdk.NewCoin(config.BaseDenom, amount))
ctx.Logger().Info(fmt.Sprintf(fmt.Sprintf("Distributing Validator Rewards Total:%s To FeeCollector : %s", amount.String(), feeCollector)))
ctx.Logger().Info(fmt.Sprintf("Distributing Validator Rewards Total:%s To FeeCollector : %s", amount.String(), feeCollector))
return bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, feeCollector, coin)
}

Expand Down
85 changes: 85 additions & 0 deletions x/emissions/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/zetacore/cmd/zetacored/config"
"github.com/zeta-chain/zetacore/pkg/coin"
Expand Down Expand Up @@ -69,6 +70,90 @@ func TestBeginBlocker(t *testing.T) {
require.True(t, sk.BankKeeper.GetBalance(ctx, feeCollectorAddress, config.BaseDenom).Amount.IsZero())
require.True(t, sk.BankKeeper.GetBalance(ctx, emissionstypes.EmissionsModuleAddress, config.BaseDenom).Amount.Equal(sdk.NewInt(1000000000000)))
})
t.Run("begin blocker returns early if validator distribution fails", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionKeeperWithMockOptions(t, keepertest.EmissionMockOptions{
UseBankMock: true,
})
// Total block rewards is the fixed amount of rewards that are distributed
totalBlockRewards, err := coin.GetAzetaDecFromAmountInZeta(emissionstypes.BlockRewardsInZeta)
totalRewardCoins := sdk.NewCoins(sdk.NewCoin(config.BaseDenom, totalBlockRewards.TruncateInt()))
require.NoError(t, err)

bankMock := keepertest.GetEmissionsBankMock(t, k)
bankMock.On("GetBalance",
ctx, mock.Anything, config.BaseDenom).
Return(totalRewardCoins[0], nil).Once()

// fail first distribution
bankMock.On("SendCoinsFromModuleToModule",
mock.Anything, emissionstypes.ModuleName, k.GetFeeCollector(), mock.Anything).
Return(emissionstypes.ErrUnableToWithdrawEmissions).Once()
emissionsModule.BeginBlocker(ctx, *k)

bankMock.AssertNumberOfCalls(t, "SendCoinsFromModuleToModule", 1)
})

t.Run("begin blocker returns early if observer distribution fails", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionKeeperWithMockOptions(t, keepertest.EmissionMockOptions{
UseBankMock: true,
})
// Total block rewards is the fixed amount of rewards that are distributed
totalBlockRewards, err := coin.GetAzetaDecFromAmountInZeta(emissionstypes.BlockRewardsInZeta)
totalRewardCoins := sdk.NewCoins(sdk.NewCoin(config.BaseDenom, totalBlockRewards.TruncateInt()))
require.NoError(t, err)

bankMock := keepertest.GetEmissionsBankMock(t, k)
bankMock.On("GetBalance",
ctx, mock.Anything, config.BaseDenom).
Return(totalRewardCoins[0], nil).Once()

// allow first distribution
bankMock.On("SendCoinsFromModuleToModule",
mock.Anything, emissionstypes.ModuleName, k.GetFeeCollector(), mock.Anything).
Return(nil).Once()

// fail second distribution
bankMock.On("SendCoinsFromModuleToModule",
mock.Anything, emissionstypes.ModuleName, emissionstypes.UndistributedObserverRewardsPool, mock.Anything).
Return(emissionstypes.ErrUnableToWithdrawEmissions).Once()
emissionsModule.BeginBlocker(ctx, *k)

bankMock.AssertNumberOfCalls(t, "SendCoinsFromModuleToModule", 2)
})

t.Run("begin blocker returns early if tss distribution fails", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionKeeperWithMockOptions(t, keepertest.EmissionMockOptions{
UseBankMock: true,
})
// Total block rewards is the fixed amount of rewards that are distributed
totalBlockRewards, err := coin.GetAzetaDecFromAmountInZeta(emissionstypes.BlockRewardsInZeta)
totalRewardCoins := sdk.NewCoins(sdk.NewCoin(config.BaseDenom, totalBlockRewards.TruncateInt()))
require.NoError(t, err)

bankMock := keepertest.GetEmissionsBankMock(t, k)
bankMock.On("GetBalance",
ctx, mock.Anything, config.BaseDenom).
Return(totalRewardCoins[0], nil).Once()

// allow first distribution
bankMock.On("SendCoinsFromModuleToModule",
mock.Anything, emissionstypes.ModuleName, k.GetFeeCollector(), mock.Anything).
Return(nil).Once()

// allow second distribution
bankMock.On("SendCoinsFromModuleToModule",
mock.Anything, emissionstypes.ModuleName, emissionstypes.UndistributedObserverRewardsPool, mock.Anything).
Return(nil).Once()

// fail third distribution
bankMock.On("SendCoinsFromModuleToModule",
mock.Anything, emissionstypes.ModuleName, emissionstypes.UndistributedTssRewardsPool, mock.Anything).
Return(emissionstypes.ErrUnableToWithdrawEmissions).Once()
emissionsModule.BeginBlocker(ctx, *k)

bankMock.AssertNumberOfCalls(t, "SendCoinsFromModuleToModule", 3)
})

t.Run("successfully distribute rewards", func(t *testing.T) {
numberOfTestBlocks := 100
k, ctx, sk, zk := keepertest.EmissionsKeeper(t)
Expand Down
1 change: 1 addition & 0 deletions x/emissions/keeper/block_rewards_components.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func (k Keeper) GetBlockRewardComponents(ctx sdk.Context) (sdk.Dec, sdk.Dec, sdk
durationFactor := k.GetDurationFactor(ctx)
return reservesFactor, bondFactor, durationFactor
}

func (k Keeper) GetBondFactor(ctx sdk.Context, stakingKeeper types.StakingKeeper) sdk.Dec {
targetBondRatio := sdk.MustNewDecFromStr(k.GetParamsIfExists(ctx).TargetBondRatio)
maxBondFactor := sdk.MustNewDecFromStr(k.GetParamsIfExists(ctx).MaxBondFactor)
Expand Down
137 changes: 137 additions & 0 deletions x/emissions/keeper/block_rewards_components_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,28 @@ package keeper_test
import (
"testing"

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/zetacore/cmd/zetacored/config"
keepertest "github.com/zeta-chain/zetacore/testutil/keeper"
emissionskeeper "github.com/zeta-chain/zetacore/x/emissions/keeper"
emissionstypes "github.com/zeta-chain/zetacore/x/emissions/types"
)

func TestKeeper_CalculateFixedValidatorRewards(t *testing.T) {
tt := []struct {
name string
blockTimeInSecs string
expectedBlockRewards sdk.Dec
wantErr bool
}{
{
name: "Invalid block time",
blockTimeInSecs: "",
wantErr: true,
},
{
name: "Block Time 5.7",
blockTimeInSecs: "5.7",
Expand Down Expand Up @@ -43,8 +54,134 @@ func TestKeeper_CalculateFixedValidatorRewards(t *testing.T) {
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
blockRewards, err := emissionskeeper.CalculateFixedValidatorRewards(tc.blockTimeInSecs)
if tc.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, tc.expectedBlockRewards, blockRewards)
})
}
}

func TestKeeper_GetFixedBlockRewards(t *testing.T) {
k, _, _, _ := keepertest.EmissionsKeeper(t)
fixedBlockRewards, err := k.GetFixedBlockRewards()
require.NoError(t, err)
require.Equal(t, emissionstypes.BlockReward, fixedBlockRewards)
}

func TestKeeper_GetBlockRewardComponent(t *testing.T) {
t.Run("should return all 0s if reserves factor is 0", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionKeeperWithMockOptions(t, keepertest.EmissionMockOptions{
UseBankMock: true,
})

bankMock := keepertest.GetEmissionsBankMock(t, k)
bankMock.On("GetBalance",
ctx, mock.Anything, config.BaseDenom).
Return(sdk.NewCoin(config.BaseDenom, math.NewInt(0)), nil).Once()

reservesFactor, bondFactor, durationFactor := k.GetBlockRewardComponents(ctx)
require.Equal(t, sdk.ZeroDec(), reservesFactor)
require.Equal(t, sdk.ZeroDec(), bondFactor)
require.Equal(t, sdk.ZeroDec(), durationFactor)
})

t.Run("should return if reserves factor is not 0", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionKeeperWithMockOptions(t, keepertest.EmissionMockOptions{
UseBankMock: true,
})

bankMock := keepertest.GetEmissionsBankMock(t, k)
bankMock.On("GetBalance",
ctx, mock.Anything, config.BaseDenom).
Return(sdk.NewCoin(config.BaseDenom, math.NewInt(1)), nil).Once()

reservesFactor, bondFactor, durationFactor := k.GetBlockRewardComponents(ctx)
require.Equal(t, sdk.OneDec(), reservesFactor)
// bonded ratio is 0
require.Equal(t, sdk.ZeroDec(), bondFactor)
// non 0 value returned
require.NotEqual(t, sdk.ZeroDec(), durationFactor)
require.Positive(t, durationFactor.BigInt().Int64())
})
}

func TestKeeper_GetBondFactor(t *testing.T) {
t.Run("should return 0 if current bond ratio is 0", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionsKeeper(t)

bondFactor := k.GetBondFactor(ctx, k.GetStakingKeeper())
require.Equal(t, sdk.ZeroDec(), bondFactor)
})

t.Run("should return max bond factor if bond factor exceeds max bond factor", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionKeeperWithMockOptions(t, keepertest.EmissionMockOptions{
UseStakingMock: true,
})

params := emissionstypes.DefaultParams()
params.TargetBondRatio = "0.5"
params.MaxBondFactor = "1.1"
params.MinBondFactor = "0.9"
k.SetParams(ctx, params)

stakingMock := keepertest.GetEmissionsStakingMock(t, k)
stakingMock.On("BondedRatio", ctx).Return(sdk.MustNewDecFromStr("0.25"))
bondFactor := k.GetBondFactor(ctx, k.GetStakingKeeper())
require.Equal(t, sdk.MustNewDecFromStr(params.MaxBondFactor), bondFactor)
})

t.Run("should return min bond factor if bond factor below min bond factor", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionKeeperWithMockOptions(t, keepertest.EmissionMockOptions{
UseStakingMock: true,
})

params := emissionstypes.DefaultParams()
params.TargetBondRatio = "0.5"
params.MaxBondFactor = "1.1"
params.MinBondFactor = "0.9"
k.SetParams(ctx, params)

stakingMock := keepertest.GetEmissionsStakingMock(t, k)
stakingMock.On("BondedRatio", ctx).Return(sdk.MustNewDecFromStr("0.75"))
bondFactor := k.GetBondFactor(ctx, k.GetStakingKeeper())
require.Equal(t, sdk.MustNewDecFromStr(params.MinBondFactor), bondFactor)
})

t.Run("should return calculated bond factor if bond factor in range", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionKeeperWithMockOptions(t, keepertest.EmissionMockOptions{
UseStakingMock: true,
})

params := emissionstypes.DefaultParams()
params.TargetBondRatio = "0.5"
params.MaxBondFactor = "1.1"
params.MinBondFactor = "0.9"
k.SetParams(ctx, params)

stakingMock := keepertest.GetEmissionsStakingMock(t, k)
stakingMock.On("BondedRatio", ctx).Return(sdk.MustNewDecFromStr("0.5"))
bondFactor := k.GetBondFactor(ctx, k.GetStakingKeeper())
require.Equal(t, sdk.OneDec(), bondFactor)
})
}

func TestKeeper_GetDurationFactor(t *testing.T) {
t.Run("should return duration factor 0 if duration factor constant is 0", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionsKeeper(t)
params := emissionstypes.DefaultParams()
params.DurationFactorConstant = "0"
k.SetParams(ctx, params)
duractionFactor := k.GetDurationFactor(ctx)
require.Equal(t, sdk.ZeroDec(), duractionFactor)
})

t.Run("should return duration factor for default params", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionsKeeper(t)
duractionFactor := k.GetDurationFactor(ctx)
// hardcoding actual expected value for default params, it will change if logic changes
require.Equal(t, sdk.MustNewDecFromStr("0.000000004346937374"), duractionFactor)
})
}
26 changes: 26 additions & 0 deletions x/emissions/keeper/grpc_query_get_emmisons_factors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package keeper_test

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
keepertest "github.com/zeta-chain/zetacore/testutil/keeper"
"github.com/zeta-chain/zetacore/x/emissions/types"
)

func TestKeeper_GetEmissionsFactors(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionsKeeper(t)
wctx := sdk.WrapSDKContext(ctx)

res, err := k.GetEmissionsFactors(wctx, nil)
require.NoError(t, err)

reservesFactor, bondFactor, durationFactor := k.GetBlockRewardComponents(ctx)
expectedRes := &types.QueryGetEmissionsFactorsResponse{
ReservesFactor: reservesFactor.String(),
BondFactor: bondFactor.String(),
DurationFactor: durationFactor.String(),
}
require.Equal(t, expectedRes, res)
}
1 change: 1 addition & 0 deletions x/emissions/keeper/grpc_query_list_balances.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ func (k Keeper) ListPoolAddresses(_ context.Context, req *types.QueryListPoolAdd
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}

return &types.QueryListPoolAddressesResponse{UndistributedObserverBalancesAddress: types.UndistributedObserverRewardsPoolAddress.String(),
EmissionModuleAddress: types.EmissionsModuleAddress.String(),
UndistributedTssBalancesAddress: types.UndistributedTssRewardsPoolAddress.String()}, nil
Expand Down
35 changes: 35 additions & 0 deletions x/emissions/keeper/grpc_query_list_balances_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package keeper_test

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
keepertest "github.com/zeta-chain/zetacore/testutil/keeper"
"github.com/zeta-chain/zetacore/x/emissions/types"
)

func TestKeeper_ListPoolAddresses(t *testing.T) {
t.Run("should error if req is nil", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionsKeeper(t)
wctx := sdk.WrapSDKContext(ctx)

res, err := k.ListPoolAddresses(wctx, nil)
require.Nil(t, res)
require.Error(t, err)
})

t.Run("should not error if req is not nil", func(t *testing.T) {
k, ctx, _, _ := keepertest.EmissionsKeeper(t)
wctx := sdk.WrapSDKContext(ctx)

expectedRes := &types.QueryListPoolAddressesResponse{
UndistributedObserverBalancesAddress: types.UndistributedObserverRewardsPoolAddress.String(),
EmissionModuleAddress: types.EmissionsModuleAddress.String(),
UndistributedTssBalancesAddress: types.UndistributedTssRewardsPoolAddress.String(),
}
res, err := k.ListPoolAddresses(wctx, &types.QueryListPoolAddressesRequest{})
require.NoError(t, err)
require.Equal(t, expectedRes, res)
})
}
6 changes: 6 additions & 0 deletions x/emissions/keeper/grpc_query_show_available_emissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ import (

"github.com/zeta-chain/zetacore/cmd/zetacored/config"
"github.com/zeta-chain/zetacore/x/emissions/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

sdk "github.com/cosmos/cosmos-sdk/types"
)

func (k Keeper) ShowAvailableEmissions(goCtx context.Context, req *types.QueryShowAvailableEmissionsRequest) (*types.QueryShowAvailableEmissionsResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}

ctx := sdk.UnwrapSDKContext(goCtx)
emissions, found := k.GetWithdrawableEmission(ctx, req.Address)
if !found {
Expand Down
Loading

0 comments on commit 62999f6

Please sign in to comment.