package keeper_test import ( "testing" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/staking" ) func TestAllocateTokensToValidatorWithCommission(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) addrs := simapp.AddTestAddrs(app, ctx, 3, sdk.NewInt(1234)) valAddrs := simapp.ConvertAddrsToValAddrs(addrs) sh := staking.NewHandler(app.StakingKeeper) // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator( sdk.ValAddress(addrs[0]), valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt(), ) res, err := sh(ctx, msg) require.NoError(t, err) require.NotNil(t, res) val := app.StakingKeeper.Validator(ctx, valAddrs[0]) // allocate tokens tokens := sdk.DecCoins{ {Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(10)}, } app.DistrKeeper.AllocateTokensToValidator(ctx, val, tokens) // check commission expected := sdk.DecCoins{ {Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(5)}, } require.Equal(t, expected, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, val.GetOperator()).Commission) // check current rewards require.Equal(t, expected, app.DistrKeeper.GetValidatorCurrentRewards(ctx, val.GetOperator()).Rewards) } func TestAllocateTokensToManyValidators(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) sh := staking.NewHandler(app.StakingKeeper) addrs := simapp.AddTestAddrs(app, ctx, 2, sdk.NewInt(1234)) valAddrs := simapp.ConvertAddrsToValAddrs(addrs) // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) res, err := sh(ctx, msg) require.NoError(t, err) require.NotNil(t, res) // create second validator with 0% commission commission = staking.NewCommissionRates(sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0)) msg = staking.NewMsgCreateValidator(valAddrs[1], valConsPk2, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) res, err = sh(ctx, msg) require.NoError(t, err) require.NotNil(t, res) abciValA := abci.Validator{ Address: valConsPk1.Address(), Power: 100, } abciValB := abci.Validator{ Address: valConsPk2.Address(), Power: 100, } // assert initial state: zero outstanding rewards, zero community pool, zero commission, zero current rewards require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsZero()) require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero()) require.True(t, app.DistrKeeper.GetFeePool(ctx).CommunityPool.IsZero()) require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero()) require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero()) require.True(t, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards.IsZero()) require.True(t, app.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 := app.AccountKeeper.GetModuleAccount(ctx, types.FeeCollectorName) require.NotNil(t, feeCollector) err = app.BankKeeper.SetBalances(ctx, feeCollector.GetAddress(), fees) require.NoError(t, err) app.AccountKeeper.SetAccount(ctx, feeCollector) votes := []abci.VoteInfo{ { Validator: abciValA, SignedLastBlock: true, }, { Validator: abciValB, SignedLastBlock: true, }, } app.DistrKeeper.AllocateTokens(ctx, 200, 200, valConsAddr2, votes) // 98 outstanding rewards (100 less 2 to community pool) require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(465, 1)}}, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards) require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(515, 1)}}, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards) // 2 community pool coins require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(2)}}, app.DistrKeeper.GetFeePool(ctx).CommunityPool) // 50% commission for first proposer, (0.5 * 93%) * 100 / 2 = 23.25 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2325, 2)}}, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission) // zero commission for second proposer require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero()) // just staking.proportional for first proposer less commission = (0.5 * 93%) * 100 / 2 = 23.25 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(2325, 2)}}, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards) // proposer reward + staking.proportional for second proposer = (5 % + 0.5 * (93%)) * 100 = 51.5 require.Equal(t, sdk.DecCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDecWithPrec(515, 1)}}, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[1]).Rewards) } func TestAllocateTokensTruncation(t *testing.T) { app := simapp.Setup(false) ctx := app.BaseApp.NewContext(false, abci.Header{}) addrs := simapp.AddTestAddrs(app, ctx, 3, sdk.NewInt(1234)) valAddrs := simapp.ConvertAddrsToValAddrs(addrs) sh := staking.NewHandler(app.StakingKeeper) // create validator with 10% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valAddrs[0], valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(110)), staking.Description{}, commission, sdk.OneInt()) res, err := sh(ctx, msg) require.NoError(t, err) require.NotNil(t, res) // create second validator with 10% commission commission = staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) msg = staking.NewMsgCreateValidator(valAddrs[1], valConsPk2, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) res, err = sh(ctx, msg) require.NoError(t, err) require.NotNil(t, res) // create third validator with 10% commission commission = staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) msg = staking.NewMsgCreateValidator(valAddrs[2], valConsPk3, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) res, err = sh(ctx, msg) require.NoError(t, err) require.NotNil(t, res) abciValA := abci.Validator{ Address: valConsPk1.Address(), Power: 11, } abciValB := abci.Validator{ Address: valConsPk2.Address(), Power: 10, } abciValС := abci.Validator{ Address: valConsPk3.Address(), Power: 10, } // assert initial state: zero outstanding rewards, zero community pool, zero commission, zero current rewards require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsZero()) require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero()) require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsZero()) require.True(t, app.DistrKeeper.GetFeePool(ctx).CommunityPool.IsZero()) require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[0]).Commission.IsZero()) require.True(t, app.DistrKeeper.GetValidatorAccumulatedCommission(ctx, valAddrs[1]).Commission.IsZero()) require.True(t, app.DistrKeeper.GetValidatorCurrentRewards(ctx, valAddrs[0]).Rewards.IsZero()) require.True(t, app.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 := app.AccountKeeper.GetModuleAccount(ctx, types.FeeCollectorName) require.NotNil(t, feeCollector) err = app.BankKeeper.SetBalances(ctx, feeCollector.GetAddress(), fees) require.NoError(t, err) app.AccountKeeper.SetAccount(ctx, feeCollector) votes := []abci.VoteInfo{ { Validator: abciValA, SignedLastBlock: true, }, { Validator: abciValB, SignedLastBlock: true, }, { Validator: abciValС, SignedLastBlock: true, }, } app.DistrKeeper.AllocateTokens(ctx, 31, 31, sdk.ConsAddress(valConsPk2.Address()), votes) require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[0]).Rewards.IsValid()) require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[1]).Rewards.IsValid()) require.True(t, app.DistrKeeper.GetValidatorOutstandingRewards(ctx, valAddrs[2]).Rewards.IsValid()) }