Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: improve emissions module coverage #1955

Merged
merged 17 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
skosito marked this conversation as resolved.
Show resolved Hide resolved
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
Loading