diff --git a/tests/integration/distribution/keeper/allocation_test.go b/tests/integration/distribution/keeper/allocation_test.go deleted file mode 100644 index 7ad05a0ffd..0000000000 --- a/tests/integration/distribution/keeper/allocation_test.go +++ /dev/null @@ -1,248 +0,0 @@ -package keeper_test - -import ( - "testing" - - "cosmossdk.io/math" - abci "github.com/cometbft/cometbft/abci/types" - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - "gotest.tools/v3/assert" - - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - "github.com/cosmos/cosmos-sdk/x/auth/types" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" - "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - "github.com/cosmos/cosmos-sdk/x/distribution/testutil" - disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - stakingtestutil "github.com/cosmos/cosmos-sdk/x/staking/testutil" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -func TestAllocateTokensToValidatorWithCommission(t *testing.T) { - var ( - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - addrs := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 3, sdk.NewInt(1234)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addrs) - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - - // create validator with 50% commission - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - tstaking.CreateValidator(sdk.ValAddress(addrs[0]), valConsPk0, sdk.NewInt(100), true) - val := stakingKeeper.Validator(ctx, valAddrs[0]) - - // allocate tokens - tokens := sdk.DecCoins{ - {Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(10)}, - } - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // check commission - expected := sdk.DecCoins{ - {Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(5)}, - } - assert.DeepEqual(t, expected, distrKeeper.GetValidatorAccumulatedCommission(ctx, val.GetOperator()).Commission) - - // check current rewards - assert.DeepEqual(t, expected, distrKeeper.GetValidatorCurrentRewards(ctx, val.GetOperator()).Rewards) -} - -func TestAllocateTokensToManyValidators(t *testing.T) { - var ( - accountKeeper authkeeper.AccountKeeper - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &accountKeeper, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - // reset fee pool - distrKeeper.SetFeePool(ctx, disttypes.InitialFeePool()) - - addrs := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(1234)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addrs) - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - - // create validator with 50% commission - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - tstaking.CreateValidator(valAddrs[0], valConsPk0, sdk.NewInt(100), true) - - // create second validator with 0% commission - tstaking.Commission = stakingtypes.NewCommissionRates(math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0)) - tstaking.CreateValidator(valAddrs[1], valConsPk1, sdk.NewInt(100), true) - - abciValA := abci.Validator{ - Address: valConsPk0.Address(), - Power: 100, - } - abciValB := abci.Validator{ - Address: valConsPk1.Address(), - Power: 100, - } - - // assert initial state: zero outstanding rewards, zero community pool, zero commission, zero current rewards - assert.Assert(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsZero()) - assert.Assert(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero()) - assert.Assert(t, distrKeeper.GetFeePool(ctx).CommunityPool.IsZero()) - assert.Assert(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero()) - assert.Assert(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero()) - assert.Assert(t, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards.IsZero()) - assert.Assert(t, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards.IsZero()) - - // allocate tokens as if both had voted and second was proposer - fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) - feeCollector := accountKeeper.GetModuleAccount(ctx, types.FeeCollectorName) - assert.Assert(t, feeCollector != nil) - - // fund fee collector - assert.NilError(t, banktestutil.FundModuleAccount(bankKeeper, ctx, feeCollector.GetName(), fees)) - - accountKeeper.SetAccount(ctx, feeCollector) - - votes := []abci.VoteInfo{ - { - Validator: abciValA, - SignedLastBlock: true, - }, - { - Validator: abciValB, - SignedLastBlock: true, - }, - } - distrKeeper.AllocateTokens(ctx, 200, votes) - - // 98 outstanding rewards (100 less 2 to community pool) - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(490, 1)}}, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards) - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(490, 1)}}, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards) - - // 2 community pool coins - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(2)}}, distrKeeper.GetFeePool(ctx).CommunityPool) - - // 50% commission for first proposer, (0.5 * 98%) * 100 / 2 = 23.25 - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2450, 2)}}, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) - - // zero commission for second proposer - assert.Assert(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero()) - - // just staking.proportional for first proposer less commission = (0.5 * 98%) * 100 / 2 = 24.50 - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2450, 2)}}, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards) - - // proposer reward + staking.proportional for second proposer = (0.5 * (98%)) * 100 = 49 - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(490, 1)}}, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards) -} - -func TestAllocateTokensTruncation(t *testing.T) { - var ( - accountKeeper authkeeper.AccountKeeper - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &accountKeeper, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - // reset fee pool - distrKeeper.SetFeePool(ctx, disttypes.InitialFeePool()) - - addrs := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 3, sdk.NewInt(1234)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addrs) - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - - // create validator with 10% commission - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), math.LegacyNewDec(0)) - tstaking.CreateValidator(valAddrs[0], valConsPk0, sdk.NewInt(110), true) - - // create second validator with 10% commission - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), math.LegacyNewDec(0)) - tstaking.CreateValidator(valAddrs[1], valConsPk1, sdk.NewInt(100), true) - - // create third validator with 10% commission - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), math.LegacyNewDec(0)) - tstaking.CreateValidator(valAddrs[2], valConsPk2, sdk.NewInt(100), true) - - abciValA := abci.Validator{ - Address: valConsPk0.Address(), - Power: 11, - } - abciValB := abci.Validator{ - Address: valConsPk1.Address(), - Power: 10, - } - abciValC := abci.Validator{ - Address: valConsPk2.Address(), - Power: 10, - } - - // assert initial state: zero outstanding rewards, zero community pool, zero commission, zero current rewards - assert.Assert(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsZero()) - assert.Assert(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero()) - assert.Assert(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero()) - assert.Assert(t, distrKeeper.GetFeePool(ctx).CommunityPool.IsZero()) - assert.Assert(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero()) - assert.Assert(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero()) - assert.Assert(t, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards.IsZero()) - assert.Assert(t, distrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards.IsZero()) - - // allocate tokens as if both had voted and second was proposer - fees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(634195840))) - - feeCollector := accountKeeper.GetModuleAccount(ctx, types.FeeCollectorName) - assert.Assert(t, feeCollector != nil) - - assert.NilError(t, banktestutil.FundModuleAccount(bankKeeper, ctx, feeCollector.GetName(), fees)) - - accountKeeper.SetAccount(ctx, feeCollector) - - votes := []abci.VoteInfo{ - { - Validator: abciValA, - SignedLastBlock: true, - }, - { - Validator: abciValB, - SignedLastBlock: true, - }, - { - Validator: abciValC, - SignedLastBlock: true, - }, - } - distrKeeper.AllocateTokens(ctx, 31, votes) - - assert.Assert(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsValid()) - assert.Assert(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsValid()) - assert.Assert(t, distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[2]).Rewards.IsValid()) -} diff --git a/tests/integration/distribution/keeper/common_test.go b/tests/integration/distribution/keeper/common_test.go index 4ab7cead57..783d44e2da 100644 --- a/tests/integration/distribution/keeper/common_test.go +++ b/tests/integration/distribution/keeper/common_test.go @@ -2,19 +2,10 @@ package keeper_test import ( simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/distribution/types" ) var ( - PKS = simtestutil.CreateTestPubKeys(5) + PKS = simtestutil.CreateTestPubKeys(3) valConsPk0 = PKS[0] - valConsPk1 = PKS[1] - valConsPk2 = PKS[2] - - valConsAddr0 = sdk.ConsAddress(valConsPk0.Address()) - - distrAcc = authtypes.NewEmptyModuleAccount(types.ModuleName) ) diff --git a/tests/integration/distribution/keeper/delegation_test.go b/tests/integration/distribution/keeper/delegation_test.go deleted file mode 100644 index dcb25cbf3f..0000000000 --- a/tests/integration/distribution/keeper/delegation_test.go +++ /dev/null @@ -1,820 +0,0 @@ -package keeper_test - -import ( - "testing" - - "cosmossdk.io/math" - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - "gotest.tools/v3/assert" - - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" - "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - "github.com/cosmos/cosmos-sdk/x/distribution/testutil" - "github.com/cosmos/cosmos-sdk/x/staking" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - stakingtestutil "github.com/cosmos/cosmos-sdk/x/staking/testutil" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -func TestCalculateRewardsBasic(t *testing.T) { - var ( - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - distrKeeper.DeleteAllValidatorHistoricalRewards(ctx) - - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(1000)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addr) - - // create validator with 50% commission - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - tstaking.CreateValidator(valAddrs[0], valConsPk0, sdk.NewInt(100), true) - - // end block to bond validator and start new block - staking.EndBlocker(ctx, stakingKeeper) - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - tstaking.Ctx = ctx - - // fetch validator and delegation - val := stakingKeeper.Validator(ctx, valAddrs[0]) - del := stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - - // historical count should be 2 (once for validator init, once for delegation init) - assert.Equal(t, uint64(2), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) - - // end period - endingPeriod := distrKeeper.IncrementValidatorPeriod(ctx, val) - - // historical count should be 2 still - assert.Equal(t, uint64(2), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) - - // calculate delegation rewards - rewards := distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) - - // rewards should be zero - assert.Assert(t, rewards.IsZero()) - - // allocate some rewards - initial := int64(10) - tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial)}} - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // end period - endingPeriod = distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards - rewards = distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) - - // rewards should be half the tokens - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 2)}}, rewards) - - // commission should be the other half - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 2)}}, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) -} - -func TestCalculateRewardsAfterSlash(t *testing.T) { - var ( - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(100000000)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addr) - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - - // create validator with 50% commission - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - valPower := int64(100) - tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk0, valPower, true) - - // end block to bond validator - staking.EndBlocker(ctx, stakingKeeper) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // fetch validator and delegation - val := stakingKeeper.Validator(ctx, valAddrs[0]) - del := stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - - // end period - endingPeriod := distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards - rewards := distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) - - // rewards should be zero - assert.Assert(t, rewards.IsZero()) - - // start out block height - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - - // slash the validator by 50% - stakingKeeper.Slash(ctx, valConsAddr0, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1)) - - // retrieve validator - val = stakingKeeper.Validator(ctx, valAddrs[0]) - - // increase block height - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - - // allocate some rewards - initial := stakingKeeper.TokensFromConsensusPower(ctx, 10) - tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecFromInt(initial)}} - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // end period - endingPeriod = distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards - rewards = distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) - - // rewards should be half the tokens - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecFromInt(initial.QuoRaw(2))}}, rewards) - - // commission should be the other half - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecFromInt(initial.QuoRaw(2))}}, - distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) -} - -func TestCalculateRewardsAfterManySlashes(t *testing.T) { - var ( - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(100000000)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addr) - - // create validator with 50% commission - valPower := int64(100) - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk0, valPower, true) - - // end block to bond validator - staking.EndBlocker(ctx, stakingKeeper) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // fetch validator and delegation - val := stakingKeeper.Validator(ctx, valAddrs[0]) - del := stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - - // end period - endingPeriod := distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards - rewards := distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) - - // rewards should be zero - assert.Assert(t, rewards.IsZero()) - - // start out block height - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - - // slash the validator by 50% - stakingKeeper.Slash(ctx, valConsAddr0, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1)) - - // fetch the validator again - val = stakingKeeper.Validator(ctx, valAddrs[0]) - - // increase block height - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - - // allocate some rewards - initial := stakingKeeper.TokensFromConsensusPower(ctx, 10) - tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecFromInt(initial)}} - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // slash the validator by 50% again - stakingKeeper.Slash(ctx, valConsAddr0, ctx.BlockHeight(), valPower/2, sdk.NewDecWithPrec(5, 1)) - - // fetch the validator again - val = stakingKeeper.Validator(ctx, valAddrs[0]) - - // increase block height - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - - // allocate some more rewards - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // end period - endingPeriod = distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards - rewards = distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) - - // rewards should be half the tokens - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecFromInt(initial)}}, rewards) - - // commission should be the other half - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecFromInt(initial)}}, - distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) -} - -func TestCalculateRewardsMultiDelegator(t *testing.T) { - var ( - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(100000000)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addr) - - // create validator with 50% commission - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - tstaking.CreateValidator(valAddrs[0], valConsPk0, sdk.NewInt(100), true) - - // end block to bond validator - staking.EndBlocker(ctx, stakingKeeper) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // fetch validator and delegation - val := stakingKeeper.Validator(ctx, valAddrs[0]) - del1 := stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - - // allocate some rewards - initial := int64(20) - tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial)}} - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // second delegation - tstaking.Ctx = ctx - tstaking.Delegate(sdk.AccAddress(valAddrs[1]), valAddrs[0], sdk.NewInt(100)) - del2 := stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0]) - - // fetch updated validator - val = stakingKeeper.Validator(ctx, valAddrs[0]) - - // end block - staking.EndBlocker(ctx, stakingKeeper) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // allocate some more rewards - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // end period - endingPeriod := distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards for del1 - rewards := distrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod) - - // rewards for del1 should be 3/4 initial - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial * 3 / 4)}}, rewards) - - // calculate delegation rewards for del2 - rewards = distrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) - - // rewards for del2 should be 1/4 initial - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial * 1 / 4)}}, rewards) - - // commission should be equal to initial (50% twice) - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial)}}, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) -} - -func TestWithdrawDelegationRewardsBasic(t *testing.T) { - var ( - accountKeeper authkeeper.AccountKeeper - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &accountKeeper, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - distrKeeper.DeleteAllValidatorHistoricalRewards(ctx) - - balancePower := int64(1000) - balanceTokens := stakingKeeper.TokensFromConsensusPower(ctx, balancePower) - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 1, sdk.NewInt(1000000000)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addr) - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - - // set module account coins - distrAcc := distrKeeper.GetDistributionAccount(ctx) - assert.NilError(t, banktestutil.FundModuleAccount(bankKeeper, ctx, distrAcc.GetName(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, balanceTokens)))) - accountKeeper.SetModuleAccount(ctx, distrAcc) - - // create validator with 50% commission - power := int64(100) - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - valTokens := tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk0, power, true) - - // assert correct initial balance - expTokens := balanceTokens.Sub(valTokens) - assert.DeepEqual(t, - sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, expTokens)}, - bankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])), - ) - - // end block to bond validator - staking.EndBlocker(ctx, stakingKeeper) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // fetch validator and delegation - val := stakingKeeper.Validator(ctx, valAddrs[0]) - - // allocate some rewards - initial := stakingKeeper.TokensFromConsensusPower(ctx, 10) - tokens := sdk.DecCoins{sdk.NewDecCoin(sdk.DefaultBondDenom, initial)} - - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // historical count should be 2 (initial + latest for delegation) - assert.Equal(t, uint64(2), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) - - // withdraw rewards - _, err = distrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - assert.Assert(t, err == nil) - - // historical count should still be 2 (added one record, cleared one) - assert.Equal(t, uint64(2), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) - - // assert correct balance - exp := balanceTokens.Sub(valTokens).Add(initial.QuoRaw(2)) - assert.DeepEqual(t, - sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, exp)}, - bankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])), - ) - - // withdraw commission - _, err = distrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) - assert.Assert(t, err == nil) - - // assert correct balance - exp = balanceTokens.Sub(valTokens).Add(initial) - assert.DeepEqual(t, - sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, exp)}, - bankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])), - ) -} - -func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { - var ( - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 1, sdk.NewInt(1000000000)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addr) - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - - // create validator with 50% commission - valPower := int64(100) - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk0, valPower, true) - - // end block to bond validator - staking.EndBlocker(ctx, stakingKeeper) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // fetch validator and delegation - val := stakingKeeper.Validator(ctx, valAddrs[0]) - del := stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - - // end period - endingPeriod := distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards - rewards := distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) - - // rewards should be zero - assert.Assert(t, rewards.IsZero()) - - // start out block height - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - - // allocate some rewards - initial := sdk.NewDecFromInt(stakingKeeper.TokensFromConsensusPower(ctx, 10)) - tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}} - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // slash the validator by 50% - stakingKeeper.Slash(ctx, valConsAddr0, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1)) - - // slash the validator by 50% again - stakingKeeper.Slash(ctx, valConsAddr0, ctx.BlockHeight(), valPower/2, sdk.NewDecWithPrec(5, 1)) - - // fetch the validator again - val = stakingKeeper.Validator(ctx, valAddrs[0]) - - // increase block height - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - - // allocate some more rewards - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // end period - endingPeriod = distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards - rewards = distrKeeper.CalculateDelegationRewards(ctx, val, del, endingPeriod) - - // rewards should be half the tokens - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, rewards) - - // commission should be the other half - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) -} - -func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { - var ( - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(1000000000)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addr) - - // create validator with 50% commission - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - valPower := int64(100) - tstaking.CreateValidatorWithValPower(valAddrs[0], valConsPk0, valPower, true) - - // end block to bond validator - staking.EndBlocker(ctx, stakingKeeper) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // fetch validator and delegation - val := stakingKeeper.Validator(ctx, valAddrs[0]) - del1 := stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - - // allocate some rewards - initial := sdk.NewDecFromInt(stakingKeeper.TokensFromConsensusPower(ctx, 30)) - tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}} - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // slash the validator - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - stakingKeeper.Slash(ctx, valConsAddr0, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1)) - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - - // second delegation - tstaking.DelegateWithPower(sdk.AccAddress(valAddrs[1]), valAddrs[0], 100) - - del2 := stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0]) - - // end block - staking.EndBlocker(ctx, stakingKeeper) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // allocate some more rewards - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // slash the validator again - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - stakingKeeper.Slash(ctx, valConsAddr0, ctx.BlockHeight(), valPower, sdk.NewDecWithPrec(5, 1)) - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 3) - - // fetch updated validator - val = stakingKeeper.Validator(ctx, valAddrs[0]) - - // end period - endingPeriod := distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards for del1 - rewards := distrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod) - - // rewards for del1 should be 2/3 initial (half initial first period, 1/6 initial second period) - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoInt64(2).Add(initial.QuoInt64(6))}}, rewards) - - // calculate delegation rewards for del2 - rewards = distrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) - - // rewards for del2 should be initial / 3 - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial.QuoInt64(3)}}, rewards) - - // commission should be equal to initial (twice 50% commission, unaffected by slashing) - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: initial}}, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) -} - -func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { - var ( - accountKeeper authkeeper.AccountKeeper - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &accountKeeper, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - distrKeeper.DeleteAllValidatorHistoricalRewards(ctx) - - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(1000000000)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addr) - initial := int64(20) - - // set module account coins - distrAcc := distrKeeper.GetDistributionAccount(ctx) - assert.NilError(t, banktestutil.FundModuleAccount(bankKeeper, ctx, distrAcc.GetName(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000))))) - accountKeeper.SetModuleAccount(ctx, distrAcc) - - tokens := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyNewDec(initial))} - - // create validator with 50% commission - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - tstaking.CreateValidator(valAddrs[0], valConsPk0, sdk.NewInt(100), true) - - // end block to bond validator - staking.EndBlocker(ctx, stakingKeeper) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // fetch validator and delegation - val := stakingKeeper.Validator(ctx, valAddrs[0]) - del1 := stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - - // allocate some rewards - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // historical count should be 2 (validator init, delegation init) - assert.Equal(t, uint64(2), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) - - // second delegation - tstaking.Delegate(sdk.AccAddress(valAddrs[1]), valAddrs[0], sdk.NewInt(100)) - - // historical count should be 3 (second delegation init) - assert.Equal(t, uint64(3), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) - - // fetch updated validator - val = stakingKeeper.Validator(ctx, valAddrs[0]) - del2 := stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0]) - - // end block - staking.EndBlocker(ctx, stakingKeeper) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // allocate some more rewards - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // first delegator withdraws - _, err = distrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - assert.NilError(t, err) - - // second delegator withdraws - _, err = distrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[1]), valAddrs[0]) - assert.NilError(t, err) - - // historical count should be 3 (validator init + two delegations) - assert.Equal(t, uint64(3), distrKeeper.GetValidatorHistoricalReferenceCount(ctx)) - - // validator withdraws commission - _, err = distrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) - assert.NilError(t, err) - - // end period - endingPeriod := distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards for del1 - rewards := distrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod) - - // rewards for del1 should be zero - assert.Assert(t, rewards.IsZero()) - - // calculate delegation rewards for del2 - rewards = distrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) - - // rewards for del2 should be zero - assert.Assert(t, rewards.IsZero()) - - // commission should be zero - assert.Assert(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero()) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // allocate some more rewards - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // first delegator withdraws again - _, err = distrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - assert.NilError(t, err) - - // end period - endingPeriod = distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards for del1 - rewards = distrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod) - - // rewards for del1 should be zero - assert.Assert(t, rewards.IsZero()) - - // calculate delegation rewards for del2 - rewards = distrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) - - // rewards for del2 should be 1/4 initial - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 4)}}, rewards) - - // commission should be half initial - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 2)}}, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // allocate some more rewards - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // withdraw commission - _, err = distrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) - assert.NilError(t, err) - - // end period - endingPeriod = distrKeeper.IncrementValidatorPeriod(ctx, val) - - // calculate delegation rewards for del1 - rewards = distrKeeper.CalculateDelegationRewards(ctx, val, del1, endingPeriod) - - // rewards for del1 should be 1/4 initial - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 4)}}, rewards) - - // calculate delegation rewards for del2 - rewards = distrKeeper.CalculateDelegationRewards(ctx, val, del2, endingPeriod) - - // rewards for del2 should be 1/2 initial - assert.DeepEqual(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 2)}}, rewards) - - // commission should be zero - assert.Assert(t, distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero()) -} - -func Test100PercentCommissionReward(t *testing.T) { - var ( - accountKeeper authkeeper.AccountKeeper - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &accountKeeper, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - tstaking := stakingtestutil.NewHelper(t, ctx, stakingKeeper) - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(1000000000)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addr) - initial := int64(20) - - // set module account coins - distrAcc := distrKeeper.GetDistributionAccount(ctx) - assert.NilError(t, banktestutil.FundModuleAccount(bankKeeper, ctx, distrAcc.GetName(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000))))) - accountKeeper.SetModuleAccount(ctx, distrAcc) - - tokens := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyNewDec(initial))} - - // create validator with 100% commission - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(10, 1), sdk.NewDecWithPrec(10, 1), math.LegacyNewDec(0)) - tstaking.CreateValidator(valAddrs[0], valConsPk0, sdk.NewInt(100), true) - stakingKeeper.Delegation(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - - // end block to bond validator - staking.EndBlocker(ctx, stakingKeeper) - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // fetch validator - val := stakingKeeper.Validator(ctx, valAddrs[0]) - - // allocate some rewards - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // end block - staking.EndBlocker(ctx, stakingKeeper) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // allocate some more rewards - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // next block - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // allocate some more rewards - distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - rewards, err := distrKeeper.WithdrawDelegationRewards(ctx, sdk.AccAddress(valAddrs[0]), valAddrs[0]) - assert.NilError(t, err) - - zeroRewards := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, math.ZeroInt())} - assert.Assert(t, rewards.Equal(zeroRewards)) - - events := ctx.EventManager().Events() - lastEvent := events[len(events)-1] - - var hasValue bool - for _, attr := range lastEvent.Attributes { - if attr.Key == "amount" && attr.Value == "0stake" { - hasValue = true - } - } - assert.Assert(t, hasValue) -} diff --git a/tests/integration/distribution/keeper/grpc_query_test.go b/tests/integration/distribution/keeper/grpc_query_test.go index 7ae9af27a4..1c949e8595 100644 --- a/tests/integration/distribution/keeper/grpc_query_test.go +++ b/tests/integration/distribution/keeper/grpc_query_test.go @@ -1,97 +1,49 @@ package keeper_test import ( - gocontext "context" "fmt" "testing" "cosmossdk.io/math" - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "gotest.tools/v3/assert" - "github.com/cosmos/cosmos-sdk/baseapp" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" - "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - "github.com/cosmos/cosmos-sdk/x/distribution/testutil" "github.com/cosmos/cosmos-sdk/x/distribution/types" - "github.com/cosmos/cosmos-sdk/x/staking" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtestutil "github.com/cosmos/cosmos-sdk/x/staking/testutil" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) -type fixture struct { - ctx sdk.Context - queryClient types.QueryClient - addrs []sdk.AccAddress - valAddrs []sdk.ValAddress - - interfaceRegistry codectypes.InterfaceRegistry - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - msgServer types.MsgServer -} - -func initFixture(t assert.TestingT) *fixture { - f := &fixture{} - - app, err := simtestutil.Setup( - testutil.AppConfig, - &f.interfaceRegistry, - &f.bankKeeper, - &f.distrKeeper, - &f.stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - queryHelper := baseapp.NewQueryServerTestHelper(ctx, f.interfaceRegistry) - types.RegisterQueryServer(queryHelper, keeper.NewQuerier(f.distrKeeper)) - queryClient := types.NewQueryClient(queryHelper) - - f.ctx = ctx - f.queryClient = queryClient - - f.addrs = simtestutil.AddTestAddrs(f.bankKeeper, f.stakingKeeper, ctx, 2, sdk.NewInt(1000000000)) - f.valAddrs = simtestutil.ConvertAddrsToValAddrs(f.addrs) - f.msgServer = keeper.NewMsgServerImpl(f.distrKeeper) - - return f -} - func TestGRPCParams(t *testing.T) { t.Parallel() f := initFixture(t) - ctx, queryClient := f.ctx, f.queryClient + f.distrKeeper.SetParams(f.sdkCtx, types.DefaultParams()) + + qr := f.app.QueryHelper() + queryClient := types.NewQueryClient(qr) var ( params types.Params - req *types.QueryParamsRequest expParams types.Params ) testCases := []struct { - msg string - malleate func() + name string + malleate func() + msg *types.QueryParamsRequest + expErrMsg string }{ { - "empty params request", - func() { - req = &types.QueryParamsRequest{} + name: "empty params request", + malleate: func() { expParams = types.DefaultParams() }, + msg: &types.QueryParamsRequest{}, }, { - "valid request", - func() { + name: "valid request", + malleate: func() { params = types.Params{ CommunityTax: sdk.NewDecWithPrec(3, 1), BaseProposerReward: sdk.ZeroDec(), @@ -99,23 +51,23 @@ func TestGRPCParams(t *testing.T) { WithdrawAddrEnabled: true, } - assert.NilError(t, f.distrKeeper.SetParams(ctx, params)) - req = &types.QueryParamsRequest{} + assert.NilError(t, f.distrKeeper.SetParams(f.sdkCtx, params)) expParams = params }, + msg: &types.QueryParamsRequest{}, }, } - for _, testCase := range testCases { - t.Run(fmt.Sprintf("Case %s", testCase.msg), func(t *testing.T) { - testCase.malleate() - - paramsRes, err := queryClient.Params(gocontext.Background(), req) + tc := testCase + t.Run(fmt.Sprintf("Case %s", tc.name), func(t *testing.T) { + tc.malleate() + paramsRes, err := queryClient.Params(f.sdkCtx, tc.msg) assert.NilError(t, err) assert.Assert(t, paramsRes != nil) - assert.DeepEqual(t, expParams, paramsRes.Params) + assert.DeepEqual(t, paramsRes.Params, expParams) }) + } } @@ -123,54 +75,70 @@ func TestGRPCValidatorOutstandingRewards(t *testing.T) { t.Parallel() f := initFixture(t) - ctx, queryClient, valAddrs := f.ctx, f.queryClient, f.valAddrs + // set module account coins + initTokens := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(1000)) + f.bankKeeper.MintCoins(f.sdkCtx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))) + + // Set default staking params + f.stakingKeeper.SetParams(f.sdkCtx, stakingtypes.DefaultParams()) + + qr := f.app.QueryHelper() + queryClient := types.NewQueryClient(qr) valCommission := sdk.DecCoins{ sdk.NewDecCoinFromDec("mytoken", math.LegacyNewDec(5000)), sdk.NewDecCoinFromDec("stake", math.LegacyNewDec(300)), } - // set outstanding rewards - f.distrKeeper.SetValidatorOutstandingRewards(ctx, valAddrs[0], types.ValidatorOutstandingRewards{Rewards: valCommission}) - rewards := f.distrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]) + // send funds to val addr + funds := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(1000)) + f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, types.ModuleName, sdk.AccAddress(f.valAddr), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, funds))) - var req *types.QueryValidatorOutstandingRewardsRequest + initialStake := int64(10) + tstaking := stakingtestutil.NewHelper(t, f.sdkCtx, f.stakingKeeper) + tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) + tstaking.CreateValidator(f.valAddr, valConsPk0, sdk.NewInt(initialStake), true) + + // set outstanding rewards + f.distrKeeper.SetValidatorOutstandingRewards(f.sdkCtx, f.valAddr, types.ValidatorOutstandingRewards{Rewards: valCommission}) + rewards := f.distrKeeper.GetValidatorOutstandingRewards(f.sdkCtx, f.valAddr) testCases := []struct { - msg string - malleate func() + name string + msg *types.QueryValidatorOutstandingRewardsRequest expPass bool expErrMsg string }{ { - "empty request", - func() { - req = &types.QueryValidatorOutstandingRewardsRequest{} - }, - false, - "empty validator address", - }, { - "valid request", - func() { - req = &types.QueryValidatorOutstandingRewardsRequest{ValidatorAddress: valAddrs[0].String()} - }, - true, - "", + name: "empty request", + msg: &types.QueryValidatorOutstandingRewardsRequest{}, + expPass: false, + expErrMsg: "empty validator address", + }, + { + name: "invalid address", + msg: &types.QueryValidatorOutstandingRewardsRequest{ValidatorAddress: sdk.ValAddress([]byte("addr1_______________")).String()}, + expPass: false, + expErrMsg: "validator does not exist", + }, + { + name: "valid request", + msg: &types.QueryValidatorOutstandingRewardsRequest{ValidatorAddress: f.valAddr.String()}, + expPass: true, }, } for _, testCase := range testCases { - t.Run(fmt.Sprintf("Case %s", testCase.msg), func(t *testing.T) { - testCase.malleate() + tc := testCase + t.Run(fmt.Sprintf("Case %s", tc.name), func(t *testing.T) { + validatorOutstandingRewards, err := queryClient.ValidatorOutstandingRewards(f.sdkCtx, tc.msg) - validatorOutstandingRewards, err := queryClient.ValidatorOutstandingRewards(gocontext.Background(), req) - - if testCase.expPass { + if tc.expPass { assert.NilError(t, err) assert.DeepEqual(t, rewards, validatorOutstandingRewards.Rewards) assert.DeepEqual(t, valCommission, validatorOutstandingRewards.Rewards.Rewards) } else { - assert.ErrorContains(t, err, testCase.expErrMsg) + assert.ErrorContains(t, err, tc.expErrMsg) assert.Assert(t, validatorOutstandingRewards == nil) } }) @@ -181,49 +149,64 @@ func TestGRPCValidatorCommission(t *testing.T) { t.Parallel() f := initFixture(t) - ctx, queryClient, valAddrs := f.ctx, f.queryClient, f.valAddrs + // set module account coins + initTokens := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(1000)) + f.bankKeeper.MintCoins(f.sdkCtx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))) + + // Set default staking params + f.stakingKeeper.SetParams(f.sdkCtx, stakingtypes.DefaultParams()) + + qr := f.app.QueryHelper() + queryClient := types.NewQueryClient(qr) + + // send funds to val addr + funds := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(1000)) + f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, types.ModuleName, sdk.AccAddress(f.valAddr), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, funds))) + + initialStake := int64(10) + tstaking := stakingtestutil.NewHelper(t, f.sdkCtx, f.stakingKeeper) + tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) + tstaking.CreateValidator(f.valAddr, valConsPk0, sdk.NewInt(initialStake), true) commission := sdk.DecCoins{{Denom: "token1", Amount: math.LegacyNewDec(4)}, {Denom: "token2", Amount: math.LegacyNewDec(2)}} - f.distrKeeper.SetValidatorAccumulatedCommission(ctx, valAddrs[0], types.ValidatorAccumulatedCommission{Commission: commission}) - - var req *types.QueryValidatorCommissionRequest + f.distrKeeper.SetValidatorAccumulatedCommission(f.sdkCtx, f.valAddr, types.ValidatorAccumulatedCommission{Commission: commission}) testCases := []struct { - msg string - malleate func() + name string + msg *types.QueryValidatorCommissionRequest expPass bool expErrMsg string }{ { - "empty request", - func() { - req = &types.QueryValidatorCommissionRequest{} - }, - false, - "empty validator address", + name: "empty request", + msg: &types.QueryValidatorCommissionRequest{}, + expPass: false, + expErrMsg: "empty validator address", }, { - "valid request", - func() { - req = &types.QueryValidatorCommissionRequest{ValidatorAddress: valAddrs[0].String()} - }, - true, - "", + name: "invalid validator", + msg: &types.QueryValidatorCommissionRequest{ValidatorAddress: sdk.ValAddress([]byte("addr1_______________")).String()}, + expPass: false, + expErrMsg: "validator does not exist", + }, + { + name: "valid request", + msg: &types.QueryValidatorCommissionRequest{ValidatorAddress: f.valAddr.String()}, + expPass: true, }, } for _, testCase := range testCases { - t.Run(fmt.Sprintf("Case %s", testCase.msg), func(t *testing.T) { - testCase.malleate() + tc := testCase + t.Run(fmt.Sprintf("Case %s", tc.name), func(t *testing.T) { + commissionRes, err := queryClient.ValidatorCommission(f.sdkCtx, tc.msg) - commissionRes, err := queryClient.ValidatorCommission(gocontext.Background(), req) - - if testCase.expPass { + if tc.expPass { assert.NilError(t, err) assert.Assert(t, commissionRes != nil) assert.DeepEqual(t, commissionRes.Commission.Commission, commission) } else { - assert.ErrorContains(t, err, testCase.expErrMsg) + assert.ErrorContains(t, err, tc.expErrMsg) assert.Assert(t, commissionRes == nil) } }) @@ -234,7 +217,11 @@ func TestGRPCValidatorSlashes(t *testing.T) { t.Parallel() f := initFixture(t) - ctx, queryClient, valAddrs := f.ctx, f.queryClient, f.valAddrs + qr := f.app.QueryHelper() + queryClient := types.NewQueryClient(qr) + + addr2 := sdk.AccAddress(PKS[1].Address()) + valAddr2 := sdk.ValAddress(addr2) slashes := []types.ValidatorSlashEvent{ types.NewValidatorSlashEvent(3, sdk.NewDecWithPrec(5, 1)), @@ -244,7 +231,7 @@ func TestGRPCValidatorSlashes(t *testing.T) { } for i, slash := range slashes { - f.distrKeeper.SetValidatorSlashEvent(ctx, valAddrs[0], uint64(i+2), 0, slash) + f.distrKeeper.SetValidatorSlashEvent(f.sdkCtx, f.valAddr, uint64(i+2), 0, slash) } var ( @@ -253,56 +240,55 @@ func TestGRPCValidatorSlashes(t *testing.T) { ) testCases := []struct { - msg string + name string malleate func() expPass bool expErrMsg string }{ { - "empty request", - func() { + name: "empty request", + malleate: func() { req = &types.QueryValidatorSlashesRequest{} expRes = &types.QueryValidatorSlashesResponse{} }, - false, - "empty validator address", + expPass: false, + expErrMsg: "empty validator address", }, { - "Ending height lesser than start height request", - func() { + name: "Ending height lesser than start height request", + malleate: func() { req = &types.QueryValidatorSlashesRequest{ - ValidatorAddress: valAddrs[1].String(), + ValidatorAddress: valAddr2.String(), StartingHeight: 10, EndingHeight: 1, } expRes = &types.QueryValidatorSlashesResponse{Pagination: &query.PageResponse{}} }, - false, - "starting height greater than ending height", + expPass: false, + expErrMsg: "starting height greater than ending height", }, { - "no slash event validator request", - func() { + name: "no slash event validator request", + malleate: func() { req = &types.QueryValidatorSlashesRequest{ - ValidatorAddress: valAddrs[1].String(), + ValidatorAddress: valAddr2.String(), StartingHeight: 1, EndingHeight: 10, } expRes = &types.QueryValidatorSlashesResponse{Pagination: &query.PageResponse{}} }, - true, - "", + expPass: true, }, { - "request slashes with offset 2 and limit 2", - func() { + name: "request slashes with offset 2 and limit 2", + malleate: func() { pageReq := &query.PageRequest{ Offset: 2, Limit: 2, } req = &types.QueryValidatorSlashesRequest{ - ValidatorAddress: valAddrs[0].String(), + ValidatorAddress: f.valAddr.String(), StartingHeight: 1, EndingHeight: 10, Pagination: pageReq, @@ -312,19 +298,18 @@ func TestGRPCValidatorSlashes(t *testing.T) { Slashes: slashes[2:], } }, - true, - "", + expPass: true, }, { - "request slashes with page limit 3 and count total", - func() { + name: "request slashes with page limit 3 and count total", + malleate: func() { pageReq := &query.PageRequest{ Limit: 3, CountTotal: true, } req = &types.QueryValidatorSlashesRequest{ - ValidatorAddress: valAddrs[0].String(), + ValidatorAddress: f.valAddr.String(), StartingHeight: 1, EndingHeight: 10, Pagination: pageReq, @@ -334,19 +319,18 @@ func TestGRPCValidatorSlashes(t *testing.T) { Slashes: slashes[:3], } }, - true, - "", + expPass: true, }, { - "request slashes with page limit 4 and count total", - func() { + name: "request slashes with page limit 4 and count total", + malleate: func() { pageReq := &query.PageRequest{ Limit: 4, CountTotal: true, } req = &types.QueryValidatorSlashesRequest{ - ValidatorAddress: valAddrs[0].String(), + ValidatorAddress: f.valAddr.String(), StartingHeight: 1, EndingHeight: 10, Pagination: pageReq, @@ -356,303 +340,71 @@ func TestGRPCValidatorSlashes(t *testing.T) { Slashes: slashes[:4], } }, - true, - "", + expPass: true, }, } for _, testCase := range testCases { - t.Run(fmt.Sprintf("Case %s", testCase.msg), func(t *testing.T) { - testCase.malleate() + tc := testCase + t.Run(fmt.Sprintf("Case %s", tc.name), func(t *testing.T) { + tc.malleate() - slashesRes, err := queryClient.ValidatorSlashes(gocontext.Background(), req) + slashesRes, err := queryClient.ValidatorSlashes(f.sdkCtx, req) - if testCase.expPass { + if tc.expPass { assert.NilError(t, err) assert.DeepEqual(t, expRes.GetSlashes(), slashesRes.GetSlashes()) } else { - assert.ErrorContains(t, err, testCase.expErrMsg) + assert.ErrorContains(t, err, tc.expErrMsg) assert.Assert(t, slashesRes == nil) } }) } } -func TestGRPCDelegationRewards(t *testing.T) { - t.Parallel() - f := initFixture(t) - - ctx, addrs, valAddrs := f.ctx, f.addrs, f.valAddrs - - tstaking := stakingtestutil.NewHelper(t, ctx, f.stakingKeeper) - tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - tstaking.CreateValidator(valAddrs[0], valConsPk0, sdk.NewInt(100), true) - - staking.EndBlocker(ctx, f.stakingKeeper) - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - queryHelper := baseapp.NewQueryServerTestHelper(ctx, f.interfaceRegistry) - types.RegisterQueryServer(queryHelper, keeper.NewQuerier(f.distrKeeper)) - queryClient := types.NewQueryClient(queryHelper) - - val := f.stakingKeeper.Validator(ctx, valAddrs[0]) - - initial := int64(10) - tokens := sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial)}} - f.distrKeeper.AllocateTokensToValidator(ctx, val, tokens) - - // test command delegation rewards grpc - var ( - req *types.QueryDelegationRewardsRequest - expRes *types.QueryDelegationRewardsResponse - ) - - testCases := []struct { - msg string - malleate func() - expPass bool - expErrMsg string - }{ - { - "empty request", - func() { - req = &types.QueryDelegationRewardsRequest{} - }, - false, - "empty delegator address", - }, - { - "empty delegator request", - func() { - req = &types.QueryDelegationRewardsRequest{ - DelegatorAddress: "", - ValidatorAddress: valAddrs[0].String(), - } - }, - false, - "empty delegator address", - }, - { - "empty validator request", - func() { - req = &types.QueryDelegationRewardsRequest{ - DelegatorAddress: addrs[1].String(), - ValidatorAddress: "", - } - }, - false, - "empty validator address", - }, - { - "request with wrong delegator and validator", - func() { - req = &types.QueryDelegationRewardsRequest{ - DelegatorAddress: addrs[1].String(), - ValidatorAddress: valAddrs[1].String(), - } - }, - false, - "validator does not exist", - }, - { - "valid request", - func() { - req = &types.QueryDelegationRewardsRequest{ - DelegatorAddress: addrs[0].String(), - ValidatorAddress: valAddrs[0].String(), - } - - expRes = &types.QueryDelegationRewardsResponse{ - Rewards: sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initial / 2)}}, - } - }, - true, - "", - }, - } - - for _, testCase := range testCases { - t.Run(fmt.Sprintf("Case %s", testCase.msg), func(t *testing.T) { - testCase.malleate() - - rewards, err := queryClient.DelegationRewards(gocontext.Background(), req) - - if testCase.expPass { - assert.NilError(t, err) - assert.DeepEqual(t, expRes, rewards) - } else { - assert.ErrorContains(t, err, testCase.expErrMsg) - assert.Assert(t, rewards == nil) - } - }) - } - - // test command delegator total rewards grpc - var ( - totalRewardsReq *types.QueryDelegationTotalRewardsRequest - expTotalRewardsRes *types.QueryDelegationTotalRewardsResponse - ) - - testCases = []struct { - msg string - malleate func() - expPass bool - expErrMsg string - }{ - { - "empty request", - func() { - totalRewardsReq = &types.QueryDelegationTotalRewardsRequest{} - }, - false, - "empty delegator address", - }, - { - "valid total delegation rewards", - func() { - totalRewardsReq = &types.QueryDelegationTotalRewardsRequest{ - DelegatorAddress: addrs[0].String(), - } - - expectedDelReward := types.NewDelegationDelegatorReward(valAddrs[0], - sdk.DecCoins{sdk.NewInt64DecCoin("stake", 5)}) - - expTotalRewardsRes = &types.QueryDelegationTotalRewardsResponse{ - Rewards: []types.DelegationDelegatorReward{expectedDelReward}, - Total: expectedDelReward.Reward, - } - }, - true, - "", - }, - } - - for _, testCase := range testCases { - t.Run(fmt.Sprintf("Case %s", testCase.msg), func(t *testing.T) { - testCase.malleate() - - totalRewardsRes, err := queryClient.DelegationTotalRewards(gocontext.Background(), totalRewardsReq) - - if testCase.expPass { - assert.NilError(t, err) - assert.DeepEqual(t, totalRewardsRes, expTotalRewardsRes) - } else { - assert.ErrorContains(t, err, testCase.expErrMsg) - assert.Assert(t, totalRewardsRes == nil) - } - }) - } - - // test command validator delegators grpc - var ( - delegatorValidatorsReq *types.QueryDelegatorValidatorsRequest - expDelegatorValidatorsRes *types.QueryDelegatorValidatorsResponse - ) - - testCases = []struct { - msg string - malleate func() - expPass bool - expErrMsg string - }{ - { - "empty request", - func() { - delegatorValidatorsReq = &types.QueryDelegatorValidatorsRequest{} - }, - false, - "empty delegator address", - }, - { - "request no delegations address", - func() { - delegatorValidatorsReq = &types.QueryDelegatorValidatorsRequest{ - DelegatorAddress: addrs[1].String(), - } - - expDelegatorValidatorsRes = &types.QueryDelegatorValidatorsResponse{} - }, - true, - "", - }, - { - "valid request", - func() { - delegatorValidatorsReq = &types.QueryDelegatorValidatorsRequest{ - DelegatorAddress: addrs[0].String(), - } - expDelegatorValidatorsRes = &types.QueryDelegatorValidatorsResponse{ - Validators: []string{valAddrs[0].String()}, - } - }, - true, - "", - }, - } - - for _, testCase := range testCases { - t.Run(fmt.Sprintf("Case %s", testCase.msg), func(t *testing.T) { - testCase.malleate() - - validators, err := queryClient.DelegatorValidators(gocontext.Background(), delegatorValidatorsReq) - - if testCase.expPass { - assert.NilError(t, err) - assert.DeepEqual(t, expDelegatorValidatorsRes, validators) - } else { - assert.ErrorContains(t, err, testCase.expErrMsg) - assert.Assert(t, validators == nil) - } - }) - } -} - func TestGRPCDelegatorWithdrawAddress(t *testing.T) { t.Parallel() f := initFixture(t) - ctx, queryClient, addrs := f.ctx, f.queryClient, f.addrs + f.distrKeeper.SetParams(f.sdkCtx, types.DefaultParams()) - err := f.distrKeeper.SetWithdrawAddr(ctx, addrs[0], addrs[1]) + qr := f.app.QueryHelper() + queryClient := types.NewQueryClient(qr) + + addr2 := sdk.AccAddress(PKS[1].Address()) + + err := f.distrKeeper.SetWithdrawAddr(f.sdkCtx, f.addr, addr2) assert.Assert(t, err == nil) - var req *types.QueryDelegatorWithdrawAddressRequest - testCases := []struct { - msg string - malleate func() + name string + msg *types.QueryDelegatorWithdrawAddressRequest expPass bool expErrMsg string }{ { - "empty request", - func() { - req = &types.QueryDelegatorWithdrawAddressRequest{} - }, - false, - "empty delegator address", + name: "empty request", + msg: &types.QueryDelegatorWithdrawAddressRequest{}, + expPass: false, + expErrMsg: "empty delegator address", }, { - "valid request", - func() { - req = &types.QueryDelegatorWithdrawAddressRequest{DelegatorAddress: addrs[0].String()} - }, - true, - "", + name: "valid request", + msg: &types.QueryDelegatorWithdrawAddressRequest{DelegatorAddress: f.addr.String()}, + expPass: true, }, } for _, testCase := range testCases { - t.Run(fmt.Sprintf("Case %s", testCase.msg), func(t *testing.T) { - testCase.malleate() + tc := testCase + t.Run(fmt.Sprintf("Case %s", tc.name), func(t *testing.T) { + withdrawAddress, err := queryClient.DelegatorWithdrawAddress(f.sdkCtx, tc.msg) - withdrawAddress, err := queryClient.DelegatorWithdrawAddress(gocontext.Background(), req) - - if testCase.expPass { + if tc.expPass { assert.NilError(t, err) - assert.Equal(t, withdrawAddress.WithdrawAddress, addrs[1].String()) + assert.Equal(t, withdrawAddress.WithdrawAddress, addr2.String()) } else { - assert.ErrorContains(t, err, testCase.expErrMsg) + assert.ErrorContains(t, err, tc.expErrMsg) assert.Assert(t, withdrawAddress == nil) } }) @@ -663,9 +415,12 @@ func TestGRPCCommunityPool(t *testing.T) { t.Parallel() f := initFixture(t) - ctx, queryClient, addrs := f.ctx, f.queryClient, f.addrs - // reset fee pool - f.distrKeeper.SetFeePool(ctx, types.InitialFeePool()) + f.distrKeeper.SetFeePool(f.sdkCtx, types.FeePool{ + CommunityPool: sdk.NewDecCoins(sdk.DecCoin{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(0)}), + }) + + qr := f.app.QueryHelper() + queryClient := types.NewQueryClient(qr) var ( req *types.QueryCommunityPoolRequest @@ -673,23 +428,24 @@ func TestGRPCCommunityPool(t *testing.T) { ) testCases := []struct { - msg string + name string malleate func() }{ { - "valid request empty community pool", - func() { + name: "valid request empty community pool", + malleate: func() { req = &types.QueryCommunityPoolRequest{} expPool = &types.QueryCommunityPoolResponse{} }, }, { - "valid request", - func() { - amount := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) - assert.NilError(t, banktestutil.FundAccount(f.bankKeeper, ctx, addrs[0], amount)) + name: "valid request", + malleate: func() { + amount := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 100)) + assert.NilError(t, f.bankKeeper.MintCoins(f.sdkCtx, types.ModuleName, amount)) + assert.NilError(t, f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, types.ModuleName, f.addr, amount)) - err := f.distrKeeper.FundCommunityPool(ctx, amount, addrs[0]) + err := f.distrKeeper.FundCommunityPool(f.sdkCtx, amount, f.addr) assert.Assert(t, err == nil) req = &types.QueryCommunityPoolRequest{} @@ -699,13 +455,134 @@ func TestGRPCCommunityPool(t *testing.T) { } for _, testCase := range testCases { - t.Run(fmt.Sprintf("Case %s", testCase.msg), func(t *testing.T) { + tc := testCase + t.Run(fmt.Sprintf("Case %s", tc.name), func(t *testing.T) { testCase.malleate() - pool, err := queryClient.CommunityPool(gocontext.Background(), req) + pool, err := queryClient.CommunityPool(f.sdkCtx, req) assert.NilError(t, err) assert.DeepEqual(t, expPool, pool) }) } } + +func TestGRPCDelegationRewards(t *testing.T) { + t.Parallel() + f := initFixture(t) + + f.distrKeeper.SetFeePool(f.sdkCtx, types.FeePool{ + CommunityPool: sdk.NewDecCoins(sdk.DecCoin{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(1000)}), + }) + + // set module account coins + initTokens := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(1000)) + f.bankKeeper.MintCoins(f.sdkCtx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))) + + // Set default staking params + f.stakingKeeper.SetParams(f.sdkCtx, stakingtypes.DefaultParams()) + + qr := f.app.QueryHelper() + queryClient := types.NewQueryClient(qr) + + addr2 := sdk.AccAddress(PKS[1].Address()) + valAddr2 := sdk.ValAddress(addr2) + delAddr := sdk.AccAddress(PKS[2].Address()) + + // send funds to val addr + funds := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(1000)) + f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, types.ModuleName, sdk.AccAddress(f.valAddr), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, funds))) + + initialStake := int64(10) + tstaking := stakingtestutil.NewHelper(t, f.sdkCtx, f.stakingKeeper) + tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) + tstaking.CreateValidator(f.valAddr, valConsPk0, sdk.NewInt(initialStake), true) + + val, found := f.stakingKeeper.GetValidator(f.sdkCtx, f.valAddr) + assert.Assert(t, found) + + // setup delegation + delTokens := sdk.TokensFromConsensusPower(2, sdk.DefaultPowerReduction) + validator, issuedShares := val.AddTokensFromDel(delTokens) + delegation := stakingtypes.NewDelegation(delAddr, f.valAddr, issuedShares) + f.stakingKeeper.SetDelegation(f.sdkCtx, delegation) + f.distrKeeper.SetDelegatorStartingInfo(f.sdkCtx, validator.GetOperator(), delAddr, types.NewDelegatorStartingInfo(2, math.LegacyNewDec(initialStake), 20)) + + // setup validator rewards + decCoins := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyOneDec())} + historicalRewards := types.NewValidatorHistoricalRewards(decCoins, 2) + f.distrKeeper.SetValidatorHistoricalRewards(f.sdkCtx, validator.GetOperator(), 2, historicalRewards) + // setup current rewards and outstanding rewards + currentRewards := types.NewValidatorCurrentRewards(decCoins, 3) + f.distrKeeper.SetValidatorCurrentRewards(f.sdkCtx, f.valAddr, currentRewards) + f.distrKeeper.SetValidatorOutstandingRewards(f.sdkCtx, f.valAddr, types.ValidatorOutstandingRewards{Rewards: decCoins}) + + expRes := &types.QueryDelegationRewardsResponse{ + Rewards: sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: math.LegacyNewDec(initialStake / 10)}}, + } + + // test command delegation rewards grpc + testCases := []struct { + name string + msg *types.QueryDelegationRewardsRequest + expPass bool + expErrMsg string + }{ + { + name: "empty request", + msg: &types.QueryDelegationRewardsRequest{}, + expPass: false, + expErrMsg: "empty delegator address", + }, + { + name: "empty delegator address", + msg: &types.QueryDelegationRewardsRequest{ + DelegatorAddress: "", + ValidatorAddress: f.valAddr.String(), + }, + expPass: false, + expErrMsg: "empty delegator address", + }, + { + name: "empty validator address", + msg: &types.QueryDelegationRewardsRequest{ + DelegatorAddress: addr2.String(), + ValidatorAddress: "", + }, + expPass: false, + expErrMsg: "empty validator address", + }, + { + name: "request with wrong delegator and validator", + msg: &types.QueryDelegationRewardsRequest{ + DelegatorAddress: addr2.String(), + ValidatorAddress: valAddr2.String(), + }, + expPass: false, + expErrMsg: "validator does not exist", + }, + { + name: "valid request", + msg: &types.QueryDelegationRewardsRequest{ + DelegatorAddress: delAddr.String(), + ValidatorAddress: f.valAddr.String(), + }, + expPass: true, + }, + } + + for _, testCase := range testCases { + tc := testCase + t.Run(fmt.Sprintf("Case %s", tc.name), func(t *testing.T) { + rewards, err := queryClient.DelegationRewards(f.sdkCtx, tc.msg) + + if tc.expPass { + assert.NilError(t, err) + assert.DeepEqual(t, expRes, rewards) + } else { + assert.ErrorContains(t, err, tc.expErrMsg) + assert.Assert(t, rewards == nil) + } + }) + } +} diff --git a/tests/integration/distribution/keeper/keeper_test.go b/tests/integration/distribution/keeper/keeper_test.go deleted file mode 100644 index 3db593890a..0000000000 --- a/tests/integration/distribution/keeper/keeper_test.go +++ /dev/null @@ -1,185 +0,0 @@ -package keeper_test - -import ( - "fmt" - "testing" - - "cosmossdk.io/math" - cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - "gotest.tools/v3/assert" - - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" - "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - "github.com/cosmos/cosmos-sdk/x/distribution/testutil" - "github.com/cosmos/cosmos-sdk/x/distribution/types" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" -) - -func TestSetWithdrawAddr(t *testing.T) { - var ( - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(1000000000)) - - params := distrKeeper.GetParams(ctx) - params.WithdrawAddrEnabled = false - assert.NilError(t, distrKeeper.SetParams(ctx, params)) - - err = distrKeeper.SetWithdrawAddr(ctx, addr[0], addr[1]) - assert.Assert(t, err != nil) - - params.WithdrawAddrEnabled = true - assert.NilError(t, distrKeeper.SetParams(ctx, params)) - - err = distrKeeper.SetWithdrawAddr(ctx, addr[0], addr[1]) - assert.NilError(t, err) - - assert.ErrorContains(t, distrKeeper.SetWithdrawAddr(ctx, addr[0], distrAcc.GetAddress()), fmt.Sprintf("%s is not allowed to receive external funds: unauthorized", distrAcc.GetAddress())) -} - -func TestWithdrawValidatorCommission(t *testing.T) { - var ( - accountKeeper authkeeper.AccountKeeper - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &accountKeeper, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - valCommission := sdk.DecCoins{ - sdk.NewDecCoinFromDec("mytoken", math.LegacyNewDec(5).Quo(math.LegacyNewDec(4))), - sdk.NewDecCoinFromDec("stake", math.LegacyNewDec(3).Quo(math.LegacyNewDec(2))), - } - - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 1, sdk.NewInt(1000000000)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addr) - - // set module account coins - distrAcc := distrKeeper.GetDistributionAccount(ctx) - coins := sdk.NewCoins(sdk.NewCoin("mytoken", sdk.NewInt(2)), sdk.NewCoin("stake", sdk.NewInt(2))) - assert.NilError(t, banktestutil.FundModuleAccount(bankKeeper, ctx, distrAcc.GetName(), coins)) - - accountKeeper.SetModuleAccount(ctx, distrAcc) - - // check initial balance - balance := bankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])) - expTokens := stakingKeeper.TokensFromConsensusPower(ctx, 1000) - expCoins := sdk.NewCoins(sdk.NewCoin("stake", expTokens)) - assert.DeepEqual(t, expCoins, balance) - - // set outstanding rewards - distrKeeper.SetValidatorOutstandingRewards(ctx, valAddrs[0], types.ValidatorOutstandingRewards{Rewards: valCommission}) - - // set commission - distrKeeper.SetValidatorAccumulatedCommission(ctx, valAddrs[0], types.ValidatorAccumulatedCommission{Commission: valCommission}) - - // withdraw commission - _, err = distrKeeper.WithdrawValidatorCommission(ctx, valAddrs[0]) - assert.NilError(t, err) - - // check balance increase - balance = bankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddrs[0])) - assert.DeepEqual(t, sdk.NewCoins( - sdk.NewCoin("mytoken", sdk.NewInt(1)), - sdk.NewCoin("stake", expTokens.AddRaw(1)), - ), balance) - - // check remainder - remainder := distrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission - assert.DeepEqual(t, sdk.DecCoins{ - sdk.NewDecCoinFromDec("mytoken", math.LegacyNewDec(1).Quo(math.LegacyNewDec(4))), - sdk.NewDecCoinFromDec("stake", math.LegacyNewDec(1).Quo(math.LegacyNewDec(2))), - }, remainder) -} - -func TestGetTotalRewards(t *testing.T) { - var ( - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - valCommission := sdk.DecCoins{ - sdk.NewDecCoinFromDec("mytoken", math.LegacyNewDec(5).Quo(math.LegacyNewDec(4))), - sdk.NewDecCoinFromDec("stake", math.LegacyNewDec(3).Quo(math.LegacyNewDec(2))), - } - - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(1000000000)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addr) - - distrKeeper.SetValidatorOutstandingRewards(ctx, valAddrs[0], types.ValidatorOutstandingRewards{Rewards: valCommission}) - distrKeeper.SetValidatorOutstandingRewards(ctx, valAddrs[1], types.ValidatorOutstandingRewards{Rewards: valCommission}) - - expectedRewards := valCommission.MulDec(math.LegacyNewDec(2)) - totalRewards := distrKeeper.GetTotalRewards(ctx) - - assert.DeepEqual(t, expectedRewards, totalRewards) -} - -func TestFundCommunityPool(t *testing.T) { - var ( - bankKeeper bankkeeper.Keeper - distrKeeper keeper.Keeper - stakingKeeper *stakingkeeper.Keeper - ) - - app, err := simtestutil.Setup(testutil.AppConfig, - &bankKeeper, - &distrKeeper, - &stakingKeeper, - ) - assert.NilError(t, err) - - ctx := app.BaseApp.NewContext(false, cmtproto.Header{}) - - // reset fee pool - distrKeeper.SetFeePool(ctx, types.InitialFeePool()) - - addr := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 2, math.ZeroInt()) - - amount := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) - assert.NilError(t, banktestutil.FundAccount(bankKeeper, ctx, addr[0], amount)) - - initPool := distrKeeper.GetFeePool(ctx) - assert.Assert(t, initPool.CommunityPool.Empty()) - - err = distrKeeper.FundCommunityPool(ctx, amount, addr[0]) - assert.NilError(t, err) - - assert.DeepEqual(t, initPool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...), distrKeeper.GetFeePool(ctx).CommunityPool) - assert.Assert(t, bankKeeper.GetAllBalances(ctx, addr[0]).Empty()) -} diff --git a/tests/integration/distribution/keeper/msg_server_test.go b/tests/integration/distribution/keeper/msg_server_test.go index 2e30a936ff..65bd57837b 100644 --- a/tests/integration/distribution/keeper/msg_server_test.go +++ b/tests/integration/distribution/keeper/msg_server_test.go @@ -1,17 +1,37 @@ package keeper_test import ( + "fmt" "testing" + "cosmossdk.io/log" "cosmossdk.io/math" + storetypes "cosmossdk.io/store/types" + + cmtabcitypes "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/proto/tendermint/types" + "github.com/stretchr/testify/require" "gotest.tools/v3/assert" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/testutil/integration" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/distribution/types" - minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/auth" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/bank" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/distribution" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtestutil "github.com/cosmos/cosmos-sdk/x/staking/testutil" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/stretchr/testify/require" ) var ( @@ -19,63 +39,106 @@ var ( emptyValAddr sdk.ValAddress ) -func TestMsgSetWithdrawAddress(t *testing.T) { - t.Parallel() - f := initFixture(t) +type fixture struct { + app *integration.App - tests := []struct { - name string - delegatorAddr sdk.AccAddress - withdrawAddr sdk.AccAddress - expErr bool - expErrMsg string - }{ - { - name: "valid case", - delegatorAddr: f.addrs[0], - withdrawAddr: f.addrs[1], - expErr: false, - }, - { - name: "valid case, same delegator and withdraw address", - delegatorAddr: f.addrs[0], - withdrawAddr: f.addrs[0], - expErr: false, - }, - { - name: "empty delegator address", - delegatorAddr: emptyDelAddr, - withdrawAddr: f.addrs[0], - expErr: true, - expErrMsg: "invalid delegator address", - }, - { - name: "empty withdraw address", - delegatorAddr: f.addrs[0], - withdrawAddr: emptyDelAddr, - expErr: true, - expErrMsg: "invalid withdraw address", - }, - { - name: "both empty addresses", - delegatorAddr: emptyDelAddr, - withdrawAddr: emptyDelAddr, - expErr: true, - expErrMsg: "invalid delegator address", - }, + sdkCtx sdk.Context + cdc codec.Codec + keys map[string]*storetypes.KVStoreKey + + accountKeeper authkeeper.AccountKeeper + bankKeeper bankkeeper.Keeper + distrKeeper distrkeeper.Keeper + stakingKeeper *stakingkeeper.Keeper + + addr sdk.AccAddress + valAddr sdk.ValAddress +} + +func initFixture(t testing.TB) *fixture { + keys := storetypes.NewKVStoreKeys( + authtypes.StoreKey, banktypes.StoreKey, distrtypes.StoreKey, stakingtypes.StoreKey, + ) + cdc := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, distribution.AppModuleBasic{}).Codec + + logger := log.NewTestLogger(t) + cms := integration.CreateMultiStore(keys, logger) + + newCtx := sdk.NewContext(cms, types.Header{}, true, logger) + + authority := authtypes.NewModuleAddress("gov") + + maccPerms := map[string][]string{ + distrtypes.ModuleName: {authtypes.Minter}, + stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, + stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, } - for _, tc := range tests { - tc := tc - t.Run(tc.name, func(t *testing.T) { - msg := types.NewMsgSetWithdrawAddress(tc.delegatorAddr, tc.withdrawAddr) - _, err := f.msgServer.SetWithdrawAddress(f.ctx, msg) - if tc.expErr { - require.ErrorContains(t, err, tc.expErrMsg) - } else { - require.Nil(t, err) - } - }) + accountKeeper := authkeeper.NewAccountKeeper( + cdc, + runtime.NewKVStoreService(keys[authtypes.StoreKey]), + authtypes.ProtoBaseAccount, + maccPerms, + sdk.Bech32MainPrefix, + authority.String(), + ) + + blockedAddresses := map[string]bool{ + accountKeeper.GetAuthority(): false, + } + bankKeeper := bankkeeper.NewBaseKeeper( + cdc, + keys[banktypes.StoreKey], + accountKeeper, + blockedAddresses, + authority.String(), + ) + + stakingKeeper := stakingkeeper.NewKeeper(cdc, keys[stakingtypes.StoreKey], accountKeeper, bankKeeper, authority.String()) + + distrKeeper := distrkeeper.NewKeeper( + cdc, keys[distrtypes.StoreKey], accountKeeper, bankKeeper, stakingKeeper, distrtypes.ModuleName, authority.String(), + ) + + authModule := auth.NewAppModule(cdc, accountKeeper, authsims.RandomGenesisAccounts, nil) + bankModule := bank.NewAppModule(cdc, bankKeeper, accountKeeper, nil) + stakingModule := staking.NewAppModule(cdc, stakingKeeper, accountKeeper, bankKeeper, nil) + distrModule := distribution.NewAppModule(cdc, distrKeeper, accountKeeper, bankKeeper, stakingKeeper, nil) + + addr := sdk.AccAddress(PKS[0].Address()) + valAddr := sdk.ValAddress(addr) + valConsAddr := sdk.ConsAddress(valConsPk0.Address()) + + // set proposer and vote infos + ctx := newCtx.WithProposer(valConsAddr).WithVoteInfos([]cmtabcitypes.VoteInfo{ + { + Validator: cmtabcitypes.Validator{ + Address: valAddr, + Power: 100, + }, + SignedLastBlock: true, + }, + }) + + integrationApp := integration.NewIntegrationApp(ctx, logger, keys, cdc, authModule, bankModule, stakingModule, distrModule) + + sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context()) + + // Register MsgServer and QueryServer + distrtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), distrkeeper.NewMsgServerImpl(distrKeeper)) + distrtypes.RegisterQueryServer(integrationApp.QueryHelper(), distrkeeper.NewQuerier(distrKeeper)) + + return &fixture{ + app: integrationApp, + sdkCtx: sdkCtx, + cdc: cdc, + keys: keys, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + distrKeeper: distrKeeper, + stakingKeeper: stakingKeeper, + addr: addr, + valAddr: valAddr, } } @@ -83,44 +146,294 @@ func TestMsgWithdrawDelegatorReward(t *testing.T) { t.Parallel() f := initFixture(t) - tests := []struct { - name string - delegatorAddr sdk.AccAddress - validatorAddr sdk.ValAddress - expErr bool - expErrMsg string + f.distrKeeper.SetFeePool(f.sdkCtx, distrtypes.FeePool{ + CommunityPool: sdk.NewDecCoins(sdk.DecCoin{Denom: "stake", Amount: math.LegacyNewDec(10000)}), + }) + f.distrKeeper.SetParams(f.sdkCtx, distrtypes.DefaultParams()) + initFeePool := f.distrKeeper.GetFeePool(f.sdkCtx) + + delAddr := sdk.AccAddress(PKS[1].Address()) + valConsAddr := sdk.ConsAddress(valConsPk0.Address()) + + valCommission := sdk.DecCoins{ + sdk.NewDecCoinFromDec("mytoken", math.LegacyNewDec(5).Quo(math.LegacyNewDec(4))), + sdk.NewDecCoinFromDec("stake", math.LegacyNewDec(3).Quo(math.LegacyNewDec(2))), + } + + // setup staking validator + validator, err := stakingtypes.NewValidator(f.valAddr, PKS[0], stakingtypes.Description{}) + assert.NilError(t, err) + commission := stakingtypes.NewCommission(math.LegacyZeroDec(), math.LegacyOneDec(), math.LegacyOneDec()) + validator, err = validator.SetInitialCommission(commission) + assert.NilError(t, err) + validator.DelegatorShares = math.LegacyNewDec(100) + validator.Tokens = sdk.NewInt(1000000) + f.stakingKeeper.SetValidator(f.sdkCtx, validator) + + // set module account coins + initTokens := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(1000)) + f.bankKeeper.MintCoins(f.sdkCtx, distrtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))) + + // send funds to val addr + f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, distrtypes.ModuleName, sdk.AccAddress(f.valAddr), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))) + + initBalance := f.bankKeeper.GetAllBalances(f.sdkCtx, delAddr) + + // setup delegation + delTokens := sdk.TokensFromConsensusPower(2, sdk.DefaultPowerReduction) + validator, issuedShares := validator.AddTokensFromDel(delTokens) + delegation := stakingtypes.NewDelegation(delAddr, validator.GetOperator(), issuedShares) + f.stakingKeeper.SetDelegation(f.sdkCtx, delegation) + f.distrKeeper.SetDelegatorStartingInfo(f.sdkCtx, validator.GetOperator(), delAddr, distrtypes.NewDelegatorStartingInfo(2, math.LegacyOneDec(), 20)) + + // setup validator rewards + decCoins := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyOneDec())} + historicalRewards := distrtypes.NewValidatorHistoricalRewards(decCoins, 2) + f.distrKeeper.SetValidatorHistoricalRewards(f.sdkCtx, validator.GetOperator(), 2, historicalRewards) + // setup current rewards and outstanding rewards + currentRewards := distrtypes.NewValidatorCurrentRewards(decCoins, 3) + f.distrKeeper.SetValidatorCurrentRewards(f.sdkCtx, f.valAddr, currentRewards) + f.distrKeeper.SetValidatorOutstandingRewards(f.sdkCtx, f.valAddr, distrtypes.ValidatorOutstandingRewards{Rewards: valCommission}) + initOutstandingRewards := f.distrKeeper.GetValidatorOutstandingRewardsCoins(f.sdkCtx, f.valAddr) + + testCases := []struct { + name string + msg *distrtypes.MsgWithdrawDelegatorReward + expErr bool + expErrMsg string }{ { - name: "empty delegator address", - delegatorAddr: emptyDelAddr, - validatorAddr: f.valAddrs[0], - expErr: true, - expErrMsg: "invalid delegator address", + name: "empty delegator address", + msg: &distrtypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: emptyDelAddr.String(), + ValidatorAddress: f.valAddr.String(), + }, + expErr: true, + expErrMsg: "invalid delegator address", }, { - name: "empty validator address", - delegatorAddr: f.addrs[0], - validatorAddr: emptyValAddr, - expErr: true, - expErrMsg: "invalid validator address", + name: "empty validator address", + msg: &distrtypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: delAddr.String(), + ValidatorAddress: emptyValAddr.String(), + }, + expErr: true, + expErrMsg: "invalid validator address", }, { - name: "both empty addresses", - delegatorAddr: emptyDelAddr, - validatorAddr: emptyValAddr, - expErr: true, - expErrMsg: "invalid validator address", + name: "both empty addresses", + msg: &distrtypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: emptyDelAddr.String(), + ValidatorAddress: emptyValAddr.String(), + }, + expErr: true, + expErrMsg: "invalid validator address", + }, + { + name: "delegator with no delegations", + msg: &distrtypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: sdk.AccAddress([]byte("invalid")).String(), + ValidatorAddress: f.valAddr.String(), + }, + expErr: true, + expErrMsg: "no delegation distribution info", + }, + { + name: "validator with no delegations", + msg: &distrtypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: delAddr.String(), + ValidatorAddress: sdk.ValAddress(sdk.AccAddress(PKS[2].Address())).String(), + }, + expErr: true, + expErrMsg: "no validator distribution info", + }, + { + name: "valid msg", + msg: &distrtypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: delAddr.String(), + ValidatorAddress: f.valAddr.String(), + }, + expErr: false, }, } - for _, tc := range tests { + height := f.app.LastBlockHeight() + require.Panics(t, func() { + f.distrKeeper.GetPreviousProposerConsAddr(f.sdkCtx) + }) + for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - msg := types.NewMsgWithdrawDelegatorReward(tc.delegatorAddr, tc.validatorAddr) - _, err := f.msgServer.WithdrawDelegatorReward(f.ctx, msg) + res, err := f.app.RunMsg( + tc.msg, + integration.WithAutomaticBeginEndBlock(), + integration.WithAutomaticCommit(), + ) + + height++ + if f.app.LastBlockHeight() != height { + panic(fmt.Errorf("expected block height to be %d, got %d", height, f.app.LastBlockHeight())) + } + + prevProposerConsAddr := f.distrKeeper.GetPreviousProposerConsAddr(f.sdkCtx) + assert.Assert(t, prevProposerConsAddr.Empty() == false) + assert.DeepEqual(t, prevProposerConsAddr, valConsAddr) + var previousTotalPower int64 + for _, voteInfo := range f.sdkCtx.VoteInfos() { + previousTotalPower += voteInfo.Validator.Power + } + assert.Equal(t, previousTotalPower, int64(100)) + if tc.expErr { - require.ErrorContains(t, err, tc.expErrMsg) + assert.ErrorContains(t, err, tc.expErrMsg) } else { - require.Nil(t, err) + assert.NilError(t, err) + assert.Assert(t, res != nil) + + // check the result + result := distrtypes.MsgWithdrawDelegatorRewardResponse{} + err := f.cdc.Unmarshal(res.Value, &result) + assert.NilError(t, err) + + // check current balance is greater than initial balance + curBalance := f.bankKeeper.GetAllBalances(f.sdkCtx, sdk.AccAddress(f.valAddr)) + assert.Assert(t, initBalance.IsAllLTE(curBalance)) + + // check rewards + curFeePool := f.distrKeeper.GetFeePool(f.sdkCtx) + rewards := curFeePool.GetCommunityPool().Sub(initFeePool.CommunityPool) + curOutstandingRewards := f.distrKeeper.GetValidatorOutstandingRewards(f.sdkCtx, f.valAddr) + assert.DeepEqual(t, rewards, initOutstandingRewards.Sub(curOutstandingRewards.Rewards)) + } + }) + } +} + +func TestMsgSetWithdrawAddress(t *testing.T) { + t.Parallel() + f := initFixture(t) + + f.distrKeeper.SetParams(f.sdkCtx, distrtypes.DefaultParams()) + + delAddr := sdk.AccAddress(PKS[0].Address()) + withdrawAddr := sdk.AccAddress(PKS[1].Address()) + + testCases := []struct { + name string + preRun func() + msg *distrtypes.MsgSetWithdrawAddress + expErr bool + expErrMsg string + }{ + { + name: "empty delegator address", + preRun: func() { + params := f.distrKeeper.GetParams(f.sdkCtx) + params.WithdrawAddrEnabled = true + assert.NilError(t, f.distrKeeper.SetParams(f.sdkCtx, params)) + }, + msg: &distrtypes.MsgSetWithdrawAddress{ + DelegatorAddress: emptyDelAddr.String(), + WithdrawAddress: withdrawAddr.String(), + }, + expErr: true, + expErrMsg: "invalid delegator address", + }, + { + name: "empty withdraw address", + preRun: func() { + params := f.distrKeeper.GetParams(f.sdkCtx) + params.WithdrawAddrEnabled = true + assert.NilError(t, f.distrKeeper.SetParams(f.sdkCtx, params)) + }, + msg: &distrtypes.MsgSetWithdrawAddress{ + DelegatorAddress: delAddr.String(), + WithdrawAddress: emptyDelAddr.String(), + }, + expErr: true, + expErrMsg: "invalid withdraw address", + }, + { + name: "both empty addresses", + preRun: func() { + params := f.distrKeeper.GetParams(f.sdkCtx) + params.WithdrawAddrEnabled = true + assert.NilError(t, f.distrKeeper.SetParams(f.sdkCtx, params)) + }, + msg: &distrtypes.MsgSetWithdrawAddress{ + DelegatorAddress: emptyDelAddr.String(), + WithdrawAddress: emptyDelAddr.String(), + }, + expErr: true, + expErrMsg: "invalid delegator address", + }, + { + name: "withdraw address disabled", + preRun: func() { + params := f.distrKeeper.GetParams(f.sdkCtx) + params.WithdrawAddrEnabled = false + assert.NilError(t, f.distrKeeper.SetParams(f.sdkCtx, params)) + }, + msg: &distrtypes.MsgSetWithdrawAddress{ + DelegatorAddress: delAddr.String(), + WithdrawAddress: withdrawAddr.String(), + }, + expErr: true, + expErrMsg: "set withdraw address disabled", + }, + { + name: "valid msg with same delegator and withdraw address", + preRun: func() { + params := f.distrKeeper.GetParams(f.sdkCtx) + params.WithdrawAddrEnabled = true + assert.NilError(t, f.distrKeeper.SetParams(f.sdkCtx, params)) + }, + msg: &distrtypes.MsgSetWithdrawAddress{ + DelegatorAddress: delAddr.String(), + WithdrawAddress: delAddr.String(), + }, + expErr: false, + }, + { + name: "valid msg", + preRun: func() { + params := f.distrKeeper.GetParams(f.sdkCtx) + params.WithdrawAddrEnabled = true + assert.NilError(t, f.distrKeeper.SetParams(f.sdkCtx, params)) + }, + msg: &distrtypes.MsgSetWithdrawAddress{ + DelegatorAddress: delAddr.String(), + WithdrawAddress: withdrawAddr.String(), + }, + expErr: false, + }, + } + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + tc.preRun() + res, err := f.app.RunMsg( + tc.msg, + integration.WithAutomaticBeginEndBlock(), + integration.WithAutomaticCommit(), + ) + if tc.expErr { + assert.ErrorContains(t, err, tc.expErrMsg) + + // query the delegator withdraw address + addr := f.distrKeeper.GetDelegatorWithdrawAddr(f.sdkCtx, delAddr) + assert.DeepEqual(t, addr, delAddr) + } else { + assert.NilError(t, err) + assert.Assert(t, res != nil) + + // check the result + result := distrtypes.MsgSetWithdrawAddressResponse{} + err = f.cdc.Unmarshal(res.Value, &result) + assert.NilError(t, err) + + // query the delegator withdraw address + addr := f.distrKeeper.GetDelegatorWithdrawAddr(f.sdkCtx, delAddr) + assert.DeepEqual(t, addr.String(), tc.msg.WithdrawAddress) } }) } @@ -130,36 +443,99 @@ func TestMsgWithdrawValidatorCommission(t *testing.T) { t.Parallel() f := initFixture(t) - tests := []struct { - name string - validatorAddr sdk.ValAddress - expErr bool - expErrMsg string + valCommission := sdk.DecCoins{ + sdk.NewDecCoinFromDec("mytoken", math.LegacyNewDec(5).Quo(math.LegacyNewDec(4))), + sdk.NewDecCoinFromDec("stake", math.LegacyNewDec(3).Quo(math.LegacyNewDec(2))), + } + + // set module account coins + initTokens := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(1000)) + f.bankKeeper.MintCoins(f.sdkCtx, distrtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))) + + // send funds to val addr + f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, distrtypes.ModuleName, sdk.AccAddress(f.valAddr), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))) + + coins := sdk.NewCoins(sdk.NewCoin("mytoken", sdk.NewInt(2)), sdk.NewCoin("stake", sdk.NewInt(2))) + f.bankKeeper.MintCoins(f.sdkCtx, distrtypes.ModuleName, coins) + + // check initial balance + balance := f.bankKeeper.GetAllBalances(f.sdkCtx, sdk.AccAddress(f.valAddr)) + expTokens := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, 1000) + expCoins := sdk.NewCoins(sdk.NewCoin("stake", expTokens)) + assert.DeepEqual(t, expCoins, balance) + + // set outstanding rewards + f.distrKeeper.SetValidatorOutstandingRewards(f.sdkCtx, f.valAddr, distrtypes.ValidatorOutstandingRewards{Rewards: valCommission}) + + // set commission + f.distrKeeper.SetValidatorAccumulatedCommission(f.sdkCtx, f.valAddr, distrtypes.ValidatorAccumulatedCommission{Commission: valCommission}) + + testCases := []struct { + name string + msg *distrtypes.MsgWithdrawValidatorCommission + expErr bool + expErrMsg string }{ { - name: "valid withdraw (but validator has no commission)", - validatorAddr: f.valAddrs[0], - expErr: true, - expErrMsg: "no validator commission to withdraw", + name: "empty validator address", + msg: &distrtypes.MsgWithdrawValidatorCommission{ + ValidatorAddress: emptyValAddr.String(), + }, + expErr: true, + expErrMsg: "invalid validator address", }, { - name: "empty validator address", - validatorAddr: emptyValAddr, - expErr: true, - expErrMsg: "invalid validator address", + name: "validator with no commission", + msg: &distrtypes.MsgWithdrawValidatorCommission{ + ValidatorAddress: sdk.ValAddress([]byte("addr1_______________")).String(), + }, + expErr: true, + expErrMsg: "no validator commission to withdraw", + }, + { + name: "valid msg", + msg: &distrtypes.MsgWithdrawValidatorCommission{ + ValidatorAddress: f.valAddr.String(), + }, + expErr: false, }, } - for _, tc := range tests { + + for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - msg := types.NewMsgWithdrawValidatorCommission(tc.validatorAddr) - _, err := f.msgServer.WithdrawValidatorCommission(f.ctx, msg) + res, err := f.app.RunMsg( + tc.msg, + integration.WithAutomaticBeginEndBlock(), + integration.WithAutomaticCommit(), + ) if tc.expErr { - require.ErrorContains(t, err, tc.expErrMsg) + assert.ErrorContains(t, err, tc.expErrMsg) } else { - require.Nil(t, err) + assert.NilError(t, err) + assert.Assert(t, res != nil) + + // check the result + result := distrtypes.MsgWithdrawValidatorCommissionResponse{} + err = f.cdc.Unmarshal(res.Value, &result) + assert.NilError(t, err) + + // check balance increase + balance = f.bankKeeper.GetAllBalances(f.sdkCtx, sdk.AccAddress(f.valAddr)) + assert.DeepEqual(t, sdk.NewCoins( + sdk.NewCoin("mytoken", sdk.NewInt(1)), + sdk.NewCoin("stake", expTokens.AddRaw(1)), + ), balance) + + // check remainder + remainder := f.distrKeeper.GetValidatorAccumulatedCommission(f.sdkCtx, f.valAddr).Commission + assert.DeepEqual(t, sdk.DecCoins{ + sdk.NewDecCoinFromDec("mytoken", math.LegacyNewDec(1).Quo(math.LegacyNewDec(4))), + sdk.NewDecCoinFromDec("stake", math.LegacyNewDec(1).Quo(math.LegacyNewDec(2))), + }, remainder) } }) + } } @@ -167,43 +543,88 @@ func TestMsgFundCommunityPool(t *testing.T) { t.Parallel() f := initFixture(t) - tests := []struct { + // reset fee pool + f.distrKeeper.SetFeePool(f.sdkCtx, distrtypes.InitialFeePool()) + initPool := f.distrKeeper.GetFeePool(f.sdkCtx) + assert.Assert(t, initPool.CommunityPool.Empty()) + + initTokens := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(100)) + f.bankKeeper.MintCoins(f.sdkCtx, distrtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))) + + addr := sdk.AccAddress(PKS[0].Address()) + addr2 := sdk.AccAddress(PKS[1].Address()) + amount := sdk.NewCoins(sdk.NewInt64Coin("stake", 100)) + + // fund the account by minting and sending amount from distribution module to addr + err := f.bankKeeper.MintCoins(f.sdkCtx, distrtypes.ModuleName, amount) + assert.NilError(t, err) + err = f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, distrtypes.ModuleName, addr, amount) + assert.NilError(t, err) + + testCases := []struct { name string - amount sdk.Coins - depositor sdk.AccAddress + msg *distrtypes.MsgFundCommunityPool expErr bool expErrMsg string }{ { - name: "no depositor", - amount: sdk.NewCoins(sdk.NewInt64Coin("stake", 10000)), - depositor: sdk.AccAddress{}, + name: "no depositor address", + msg: &distrtypes.MsgFundCommunityPool{ + Amount: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))), + Depositor: emptyDelAddr.String(), + }, expErr: true, expErrMsg: "invalid depositor address", }, { - name: "invalid coin", - amount: sdk.Coins{sdk.NewInt64Coin("stake", 10), sdk.NewInt64Coin("stake", 10)}, - depositor: f.addrs[0], + name: "invalid coin", + msg: &distrtypes.MsgFundCommunityPool{ + Amount: sdk.Coins{sdk.NewInt64Coin("stake", 10), sdk.NewInt64Coin("stake", 10)}, + Depositor: addr.String(), + }, expErr: true, expErrMsg: "10stake,10stake: invalid coins", }, { - name: "valid deposit", - amount: sdk.NewCoins(sdk.NewInt64Coin("stake", 1000)), - depositor: f.addrs[0], - expErr: false, + name: "depositor address with no funds", + msg: &distrtypes.MsgFundCommunityPool{ + Amount: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))), + Depositor: addr2.String(), + }, + expErr: true, + expErrMsg: "insufficient funds", + }, + { + name: "valid message", + msg: &distrtypes.MsgFundCommunityPool{ + Amount: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))), + Depositor: addr.String(), + }, + expErr: false, }, } - for _, tc := range tests { + for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - msg := types.NewMsgFundCommunityPool(tc.amount, tc.depositor) - _, err := f.msgServer.FundCommunityPool(f.ctx, msg) + res, err := f.app.RunMsg( + tc.msg, + integration.WithAutomaticBeginEndBlock(), + integration.WithAutomaticCommit(), + ) if tc.expErr { - require.ErrorContains(t, err, tc.expErrMsg) + assert.ErrorContains(t, err, tc.expErrMsg) } else { - require.Nil(t, err) + assert.NilError(t, err) + assert.Assert(t, res != nil) + + // check the result + result := distrtypes.MsgFundCommunityPool{} + err = f.cdc.Unmarshal(res.Value, &result) + assert.NilError(t, err) + + // query the community pool funds + assert.DeepEqual(t, initPool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...), f.distrKeeper.GetFeePool(f.sdkCtx).CommunityPool) + assert.Assert(t, f.bankKeeper.GetAllBalances(f.sdkCtx, addr).Empty()) } }) } @@ -219,15 +640,15 @@ func TestMsgUpdateParams(t *testing.T) { testCases := []struct { name string - input *types.MsgUpdateParams + msg *distrtypes.MsgUpdateParams expErr bool expErrMsg string }{ { name: "invalid authority", - input: &types.MsgUpdateParams{ + msg: &distrtypes.MsgUpdateParams{ Authority: "invalid", - Params: types.Params{ + Params: distrtypes.Params{ CommunityTax: sdk.NewDecWithPrec(2, 0), WithdrawAddrEnabled: withdrawAddrEnabled, BaseProposerReward: sdk.ZeroDec(), @@ -239,9 +660,9 @@ func TestMsgUpdateParams(t *testing.T) { }, { name: "community tax > 1", - input: &types.MsgUpdateParams{ + msg: &distrtypes.MsgUpdateParams{ Authority: f.distrKeeper.GetAuthority(), - Params: types.Params{ + Params: distrtypes.Params{ CommunityTax: sdk.NewDecWithPrec(2, 0), WithdrawAddrEnabled: withdrawAddrEnabled, BaseProposerReward: sdk.ZeroDec(), @@ -253,9 +674,9 @@ func TestMsgUpdateParams(t *testing.T) { }, { name: "negative community tax", - input: &types.MsgUpdateParams{ + msg: &distrtypes.MsgUpdateParams{ Authority: f.distrKeeper.GetAuthority(), - Params: types.Params{ + Params: distrtypes.Params{ CommunityTax: sdk.NewDecWithPrec(-2, 1), WithdrawAddrEnabled: withdrawAddrEnabled, BaseProposerReward: sdk.ZeroDec(), @@ -267,9 +688,9 @@ func TestMsgUpdateParams(t *testing.T) { }, { name: "base proposer reward set", - input: &types.MsgUpdateParams{ + msg: &distrtypes.MsgUpdateParams{ Authority: f.distrKeeper.GetAuthority(), - Params: types.Params{ + Params: distrtypes.Params{ CommunityTax: communityTax, BaseProposerReward: sdk.NewDecWithPrec(1, 2), BonusProposerReward: sdk.ZeroDec(), @@ -277,13 +698,13 @@ func TestMsgUpdateParams(t *testing.T) { }, }, expErr: true, - expErrMsg: "cannot update base or bonus proposer reward because these are deprecated fields: invalid request", + expErrMsg: "cannot update base or bonus proposer reward because these are deprecated fields", }, { name: "bonus proposer reward set", - input: &types.MsgUpdateParams{ + msg: &distrtypes.MsgUpdateParams{ Authority: f.distrKeeper.GetAuthority(), - Params: types.Params{ + Params: distrtypes.Params{ CommunityTax: communityTax, BaseProposerReward: sdk.ZeroDec(), BonusProposerReward: sdk.NewDecWithPrec(1, 2), @@ -291,13 +712,13 @@ func TestMsgUpdateParams(t *testing.T) { }, }, expErr: true, - expErrMsg: "cannot update base or bonus proposer reward because these are deprecated fields: invalid request", + expErrMsg: "cannot update base or bonus proposer reward because these are deprecated fields", }, { name: "all good", - input: &types.MsgUpdateParams{ + msg: &distrtypes.MsgUpdateParams{ Authority: f.distrKeeper.GetAuthority(), - Params: types.Params{ + Params: distrtypes.Params{ CommunityTax: communityTax, BaseProposerReward: sdk.ZeroDec(), BonusProposerReward: sdk.ZeroDec(), @@ -311,31 +732,54 @@ func TestMsgUpdateParams(t *testing.T) { for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - _, err := f.msgServer.UpdateParams(f.ctx, tc.input) + res, err := f.app.RunMsg( + tc.msg, + integration.WithAutomaticBeginEndBlock(), + integration.WithAutomaticCommit(), + ) if tc.expErr { assert.ErrorContains(t, err, tc.expErrMsg) } else { assert.NilError(t, err) + assert.Assert(t, res != nil) + + // check the result + result := distrtypes.MsgUpdateParams{} + err = f.cdc.Unmarshal(res.Value, &result) + assert.NilError(t, err) + + // query the params and verify it has been updated + params := f.distrKeeper.GetParams(f.sdkCtx) + assert.DeepEqual(t, distrtypes.DefaultParams(), params) } }) } } -func TestCommunityPoolSpend(t *testing.T) { +func TestMsgCommunityPoolSpend(t *testing.T) { t.Parallel() f := initFixture(t) - recipient := sdk.AccAddress([]byte("addr1_______________")) + f.distrKeeper.SetParams(f.sdkCtx, distrtypes.DefaultParams()) + f.distrKeeper.SetFeePool(f.sdkCtx, distrtypes.FeePool{ + CommunityPool: sdk.NewDecCoins(sdk.DecCoin{Denom: "stake", Amount: math.LegacyNewDec(10000)}), + }) + initialFeePool := f.distrKeeper.GetFeePool(f.sdkCtx) + + initTokens := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(100)) + f.bankKeeper.MintCoins(f.sdkCtx, distrtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))) + + recipient := sdk.AccAddress([]byte("addr1")) testCases := []struct { name string - input *types.MsgCommunityPoolSpend + msg *distrtypes.MsgCommunityPoolSpend expErr bool expErrMsg string }{ { name: "invalid authority", - input: &types.MsgCommunityPoolSpend{ + msg: &distrtypes.MsgCommunityPoolSpend{ Authority: "invalid", Recipient: recipient.String(), Amount: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))), @@ -345,7 +789,7 @@ func TestCommunityPoolSpend(t *testing.T) { }, { name: "invalid recipient", - input: &types.MsgCommunityPoolSpend{ + msg: &distrtypes.MsgCommunityPoolSpend{ Authority: f.distrKeeper.GetAuthority(), Recipient: "invalid", Amount: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))), @@ -355,7 +799,7 @@ func TestCommunityPoolSpend(t *testing.T) { }, { name: "valid message", - input: &types.MsgCommunityPoolSpend{ + msg: &distrtypes.MsgCommunityPoolSpend{ Authority: f.distrKeeper.GetAuthority(), Recipient: recipient.String(), Amount: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))), @@ -363,22 +807,30 @@ func TestCommunityPoolSpend(t *testing.T) { expErr: false, }, } - for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - _, err := f.msgServer.CommunityPoolSpend(f.ctx, tc.input) - + res, err := f.app.RunMsg( + tc.msg, + integration.WithAutomaticBeginEndBlock(), + integration.WithAutomaticCommit(), + ) if tc.expErr { assert.ErrorContains(t, err, tc.expErrMsg) } else { assert.NilError(t, err) - r, err := sdk.AccAddressFromBech32(tc.input.Recipient) + assert.Assert(t, res != nil) + + // check the result + result := distrtypes.MsgCommunityPoolSpend{} + err = f.cdc.Unmarshal(res.Value, &result) assert.NilError(t, err) - b := f.bankKeeper.GetAllBalances(f.ctx, r) - - assert.Assert(t, b.IsZero() == false) + // query the community pool to verify it has been updated + communityPool := f.distrKeeper.GetFeePoolCommunityCoins(f.sdkCtx) + newPool, negative := initialFeePool.CommunityPool.SafeSub(sdk.NewDecCoinsFromCoins(tc.msg.Amount...)) + assert.Assert(t, negative == false) + assert.DeepEqual(t, communityPool, newPool) } }) } @@ -388,43 +840,64 @@ func TestMsgDepositValidatorRewardsPool(t *testing.T) { t.Parallel() f := initFixture(t) - tstaking := stakingtestutil.NewHelper(t, f.ctx, f.stakingKeeper) + f.distrKeeper.SetParams(f.sdkCtx, distrtypes.DefaultParams()) + f.distrKeeper.SetFeePool(f.sdkCtx, distrtypes.FeePool{ + CommunityPool: sdk.NewDecCoins(sdk.DecCoin{Denom: "stake", Amount: math.LegacyNewDec(100)}), + }) + initTokens := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(10000)) + f.bankKeeper.MintCoins(f.sdkCtx, distrtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initTokens))) + + // Set default staking params + f.stakingKeeper.SetParams(f.sdkCtx, stakingtypes.DefaultParams()) + + addr := sdk.AccAddress([]byte("addr")) + addr1 := sdk.AccAddress(PKS[0].Address()) + valAddr1 := sdk.ValAddress(addr1) + + // send funds to val addr + tokens := f.stakingKeeper.TokensFromConsensusPower(f.sdkCtx, int64(1000)) + f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, distrtypes.ModuleName, sdk.AccAddress(valAddr1), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, tokens))) + + // send funds from module to addr to perform DepositValidatorRewardsPool + f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, distrtypes.ModuleName, addr, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, tokens))) + + tstaking := stakingtestutil.NewHelper(t, f.sdkCtx, f.stakingKeeper) tstaking.Commission = stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), math.LegacyNewDec(0)) - tstaking.CreateValidator(f.valAddrs[1], valConsPk0, sdk.NewInt(100), true) + tstaking.CreateValidator(valAddr1, valConsPk0, sdk.NewInt(100), true) // mint a non-staking token and send to an account amt := sdk.NewCoins(sdk.NewInt64Coin("foo", 500)) - f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, amt) - f.bankKeeper.SendCoinsFromModuleToAccount(f.ctx, minttypes.ModuleName, f.addrs[0], amt) + f.bankKeeper.MintCoins(f.sdkCtx, distrtypes.ModuleName, amt) + f.bankKeeper.SendCoinsFromModuleToAccount(f.sdkCtx, distrtypes.ModuleName, addr, amt) testCases := []struct { name string - input *types.MsgDepositValidatorRewardsPool + msg *distrtypes.MsgDepositValidatorRewardsPool expErr bool expErrMsg string }{ { name: "happy path (staking token)", - input: &types.MsgDepositValidatorRewardsPool{ - Depositor: f.addrs[0].String(), - ValidatorAddress: f.valAddrs[1].String(), - Amount: sdk.NewCoins(sdk.NewCoin(f.stakingKeeper.BondDenom(f.ctx), sdk.NewInt(100))), + msg: &distrtypes.MsgDepositValidatorRewardsPool{ + Depositor: addr.String(), + ValidatorAddress: valAddr1.String(), + Amount: sdk.NewCoins(sdk.NewCoin(f.stakingKeeper.BondDenom(f.sdkCtx), sdk.NewInt(100))), }, }, { name: "happy path (non-staking token)", - input: &types.MsgDepositValidatorRewardsPool{ - Depositor: f.addrs[0].String(), - ValidatorAddress: f.valAddrs[1].String(), + msg: &distrtypes.MsgDepositValidatorRewardsPool{ + Depositor: addr.String(), + ValidatorAddress: valAddr1.String(), Amount: amt, }, }, { name: "invalid validator", - input: &types.MsgDepositValidatorRewardsPool{ - Depositor: f.addrs[0].String(), + msg: &distrtypes.MsgDepositValidatorRewardsPool{ + Depositor: addr.String(), ValidatorAddress: sdk.ValAddress([]byte("addr1_______________")).String(), - Amount: sdk.NewCoins(sdk.NewCoin(f.stakingKeeper.BondDenom(f.ctx), sdk.NewInt(100))), + Amount: sdk.NewCoins(sdk.NewCoin(f.stakingKeeper.BondDenom(f.sdkCtx), sdk.NewInt(100))), }, expErr: true, expErrMsg: "validator does not exist", @@ -434,22 +907,32 @@ func TestMsgDepositValidatorRewardsPool(t *testing.T) { for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { - _, err := f.msgServer.DepositValidatorRewardsPool(f.ctx, tc.input) - + res, err := f.app.RunMsg( + tc.msg, + integration.WithAutomaticBeginEndBlock(), + integration.WithAutomaticCommit(), + ) if tc.expErr { assert.ErrorContains(t, err, tc.expErrMsg) } else { assert.NilError(t, err) + assert.Assert(t, res != nil) - valAddr, err := sdk.ValAddressFromBech32(tc.input.ValidatorAddress) + // check the result + result := distrtypes.MsgDepositValidatorRewardsPoolResponse{} + err = f.cdc.Unmarshal(res.Value, &result) + assert.NilError(t, err) + + val, err := sdk.ValAddressFromBech32(tc.msg.ValidatorAddress) assert.NilError(t, err) // check validator outstanding rewards - outstandingRewards := f.distrKeeper.GetValidatorOutstandingRewards(f.ctx, valAddr) - for _, c := range tc.input.Amount { + outstandingRewards := f.distrKeeper.GetValidatorOutstandingRewards(f.sdkCtx, val) + for _, c := range tc.msg.Amount { x := outstandingRewards.Rewards.AmountOf(c.Denom) assert.DeepEqual(t, x, sdk.NewDecFromInt(c.Amount)) } + } }) } diff --git a/testutil/integration/example_test.go b/testutil/integration/example_test.go index 1286cda0ce..02c888d415 100644 --- a/testutil/integration/example_test.go +++ b/testutil/integration/example_test.go @@ -6,6 +6,7 @@ import ( "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/google/go-cmp/cmp" @@ -33,7 +34,7 @@ func Example() { authority := authtypes.NewModuleAddress("gov").String() // replace the logger by testing values in a real test case (e.g. log.NewTestLogger(t)) - logger := log.NewLogger(io.Discard, log.OutputJSONOption()) + logger := log.NewNopLogger() cms := integration.CreateMultiStore(keys, logger) newCtx := sdk.NewContext(cms, cmtproto.Header{}, true, logger) diff --git a/testutil/integration/router.go b/testutil/integration/router.go index 8326436675..efae2d5cc9 100644 --- a/testutil/integration/router.go +++ b/testutil/integration/router.go @@ -56,11 +56,11 @@ func NewIntegrationApp(sdkCtx sdk.Context, logger log.Logger, keys map[string]*s }) moduleManager := module.NewManager(modules...) - bApp.SetBeginBlocker(func(ctx sdk.Context, req cmtabcitypes.RequestBeginBlock) (cmtabcitypes.ResponseBeginBlock, error) { - return moduleManager.BeginBlock(ctx, req) + bApp.SetBeginBlocker(func(_ sdk.Context, req cmtabcitypes.RequestBeginBlock) (cmtabcitypes.ResponseBeginBlock, error) { + return moduleManager.BeginBlock(sdkCtx, req) }) - bApp.SetEndBlocker(func(ctx sdk.Context, req cmtabcitypes.RequestEndBlock) (cmtabcitypes.ResponseEndBlock, error) { - return moduleManager.EndBlock(ctx, req) + bApp.SetEndBlocker(func(_ sdk.Context, req cmtabcitypes.RequestEndBlock) (cmtabcitypes.ResponseEndBlock, error) { + return moduleManager.EndBlock(sdkCtx, req) }) router := baseapp.NewMsgServiceRouter() diff --git a/x/distribution/keeper/grpc_query.go b/x/distribution/keeper/grpc_query.go index 024d102655..99bc45a410 100644 --- a/x/distribution/keeper/grpc_query.go +++ b/x/distribution/keeper/grpc_query.go @@ -6,9 +6,8 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "cosmossdk.io/store/prefix" - "cosmossdk.io/errors" + "cosmossdk.io/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" @@ -93,6 +92,11 @@ func (k Querier) ValidatorOutstandingRewards(c context.Context, req *types.Query if err != nil { return nil, err } + + validator := k.stakingKeeper.Validator(ctx, valAdr) + if validator == nil { + return nil, errors.Wrapf(types.ErrNoValidatorExists, valAdr.String()) + } rewards := k.GetValidatorOutstandingRewards(ctx, valAdr) return &types.QueryValidatorOutstandingRewardsResponse{Rewards: rewards}, nil @@ -114,6 +118,11 @@ func (k Querier) ValidatorCommission(c context.Context, req *types.QueryValidato if err != nil { return nil, err } + + validator := k.stakingKeeper.Validator(ctx, valAdr) + if validator == nil { + return nil, errors.Wrapf(types.ErrNoValidatorExists, valAdr.String()) + } commission := k.GetValidatorAccumulatedCommission(ctx, valAdr) return &types.QueryValidatorCommissionResponse{Commission: commission}, nil