cosmos-sdk/x/staking/keeper/validator_test.go

559 lines
22 KiB
Go

package keeper_test
import (
"time"
"github.com/golang/mock/gomock"
"cosmossdk.io/collections"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/header"
"cosmossdk.io/math"
authtypes "cosmossdk.io/x/auth/types"
stakingkeeper "cosmossdk.io/x/staking/keeper"
"cosmossdk.io/x/staking/testutil"
stakingtypes "cosmossdk.io/x/staking/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func (s *KeeperTestSuite) applyValidatorSetUpdates(ctx sdk.Context, keeper *stakingkeeper.Keeper, expectedUpdatesLen int) []appmodule.ValidatorUpdate {
updates, err := keeper.ApplyAndReturnValidatorSetUpdates(ctx)
s.Require().NoError(err)
if expectedUpdatesLen >= 0 {
s.Require().Equal(expectedUpdatesLen, len(updates), "%v", updates)
}
return updates
}
func (s *KeeperTestSuite) TestValidator() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
valPubKey := PKs[0]
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
valTokens := keeper.TokensFromConsensusPower(ctx, 10)
// test how the validator is set from a purely unbonbed pool
validator := testutil.NewValidator(s.T(), valAddr, valPubKey)
validator, _ = validator.AddTokensFromDel(valTokens)
require.Equal(stakingtypes.Unbonded, validator.Status)
require.Equal(valTokens, validator.Tokens)
require.Equal(valTokens, validator.DelegatorShares.RoundInt())
require.NoError(keeper.SetValidator(ctx, validator))
require.NoError(keeper.SetValidatorByPowerIndex(ctx, validator))
require.NoError(keeper.SetValidatorByConsAddr(ctx, validator))
// ensure update
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
updates := s.applyValidatorSetUpdates(ctx, keeper, 1)
validator, err := keeper.GetValidator(ctx, valAddr)
require.NoError(err)
require.Equal(validator.ModuleValidatorUpdate(keeper.PowerReduction(ctx)), updates[0])
// after the save the validator should be bonded
require.Equal(stakingtypes.Bonded, validator.Status)
require.Equal(valTokens, validator.Tokens)
require.Equal(valTokens, validator.DelegatorShares.RoundInt())
// check each store for being saved
consAddr, err := validator.GetConsAddr()
require.NoError(err)
resVal, err := keeper.GetValidatorByConsAddr(ctx, consAddr)
require.NoError(err)
require.True(validator.MinEqual(&resVal))
resVals, err := keeper.GetLastValidators(ctx)
require.NoError(err)
require.Equal(1, len(resVals))
require.True(validator.MinEqual(&resVals[0]))
resVals, err = keeper.GetBondedValidatorsByPower(ctx)
require.NoError(err)
require.Equal(1, len(resVals))
require.True(validator.MinEqual(&resVals[0]))
allVals, err := keeper.GetAllValidators(ctx)
require.NoError(err)
require.Equal(1, len(allVals))
// check the last validator power
power := int64(100)
require.NoError(keeper.SetLastValidatorPower(ctx, valAddr, power))
resPower, err := keeper.GetLastValidatorPower(ctx, valAddr)
require.NoError(err)
require.Equal(power, resPower)
require.NoError(keeper.DeleteLastValidatorPower(ctx, valAddr))
resPower, err = keeper.GetLastValidatorPower(ctx, valAddr)
require.Error(err, collections.ErrNotFound)
require.Equal(int64(0), resPower)
}
func (s *KeeperTestSuite) TestGetLastValidators() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
params, err := keeper.Params.Get(ctx)
require.NoError(err)
params.MaxValidators = 50
require.NoError(keeper.Params.Set(ctx, params))
// construct 50 validators all with equal power of 100
var validators [50]stakingtypes.Validator
for i := 0; i < 50; i++ {
validators[i] = testutil.NewValidator(s.T(), sdk.ValAddress(PKs[i].Address().Bytes()), PKs[i])
validators[i].Status = stakingtypes.Unbonded
validators[i].Tokens = math.ZeroInt()
tokens := keeper.TokensFromConsensusPower(ctx, 100)
validators[i], _ = validators[i].AddTokensFromDel(tokens)
require.Equal(keeper.TokensFromConsensusPower(ctx, 100), validators[i].Tokens)
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validators[i] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[i], true)
require.NoError(keeper.SetValidatorByConsAddr(ctx, validators[i]))
resVal, err := keeper.GetValidator(ctx, sdk.ValAddress(PKs[i].Address().Bytes()))
require.NoError(err)
require.True(validators[i].MinEqual(&resVal))
}
res, err := keeper.GetLastValidators(ctx)
require.NoError(err)
require.Len(res, 50)
// reduce max validators to 30 and ensure we only get 30 back
params.MaxValidators = 30
require.NoError(keeper.Params.Set(ctx, params))
res, err = keeper.GetLastValidators(ctx)
require.NoError(err)
require.Len(res, 30)
}
// This function tests UpdateValidator, GetValidator, GetLastValidators, RemoveValidator
func (s *KeeperTestSuite) TestValidatorBasics() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
// construct the validators
var validators [3]stakingtypes.Validator
powers := []int64{9, 8, 7}
for i, power := range powers {
validators[i] = testutil.NewValidator(s.T(), sdk.ValAddress(PKs[i].Address().Bytes()), PKs[i])
validators[i].Status = stakingtypes.Unbonded
validators[i].Tokens = math.ZeroInt()
tokens := keeper.TokensFromConsensusPower(ctx, power)
validators[i], _ = validators[i].AddTokensFromDel(tokens)
}
require.Equal(keeper.TokensFromConsensusPower(ctx, 9), validators[0].Tokens)
require.Equal(keeper.TokensFromConsensusPower(ctx, 8), validators[1].Tokens)
require.Equal(keeper.TokensFromConsensusPower(ctx, 7), validators[2].Tokens)
// check the empty keeper first
_, err := keeper.GetValidator(ctx, sdk.ValAddress(PKs[0].Address().Bytes()))
require.ErrorIs(err, stakingtypes.ErrNoValidatorFound)
resVals, err := keeper.GetLastValidators(ctx)
require.NoError(err)
require.Zero(len(resVals))
resVals, err = keeper.GetValidators(ctx, 2)
require.NoError(err)
require.Len(resVals, 0)
// set and retrieve a record
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validators[0] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[0], true)
require.NoError(keeper.SetValidatorByConsAddr(ctx, validators[0]))
resVal, err := keeper.GetValidator(ctx, sdk.ValAddress(PKs[0].Address().Bytes()))
require.NoError(err)
require.True(validators[0].MinEqual(&resVal))
// retrieve from consensus
resVal, err = keeper.GetValidatorByConsAddr(ctx, sdk.ConsAddress(PKs[0].Address()))
require.NoError(err)
require.True(validators[0].MinEqual(&resVal))
resVal, err = keeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(PKs[0]))
require.NoError(err)
require.True(validators[0].MinEqual(&resVal))
resVals, err = keeper.GetLastValidators(ctx)
require.NoError(err)
require.Equal(1, len(resVals))
require.True(validators[0].MinEqual(&resVals[0]))
require.Equal(stakingtypes.Bonded, validators[0].Status)
require.True(keeper.TokensFromConsensusPower(ctx, 9).Equal(validators[0].BondedTokens()))
// modify a records, save, and retrieve
validators[0].Status = stakingtypes.Bonded
validators[0].Tokens = keeper.TokensFromConsensusPower(ctx, 10)
validators[0].DelegatorShares = math.LegacyNewDecFromInt(validators[0].Tokens)
validators[0] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[0], true)
resVal, err = keeper.GetValidator(ctx, sdk.ValAddress(PKs[0].Address().Bytes()))
require.NoError(err)
require.True(validators[0].MinEqual(&resVal))
resVals, err = keeper.GetLastValidators(ctx)
require.NoError(err)
require.Equal(1, len(resVals))
require.True(validators[0].MinEqual(&resVals[0]))
// add other validators
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validators[1] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[1], true)
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validators[2] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[2], true)
resVal, err = keeper.GetValidator(ctx, sdk.ValAddress(PKs[1].Address().Bytes()))
require.NoError(err)
require.True(validators[1].MinEqual(&resVal))
resVal, err = keeper.GetValidator(ctx, sdk.ValAddress(PKs[2].Address().Bytes()))
require.NoError(err)
require.True(validators[2].MinEqual(&resVal))
resVals, err = keeper.GetLastValidators(ctx)
require.NoError(err)
require.Equal(3, len(resVals))
// remove a record
bz, err := keeper.ValidatorAddressCodec().StringToBytes(validators[1].GetOperator())
require.NoError(err)
// shouldn't be able to remove if status is not unbonded
require.EqualError(keeper.RemoveValidator(ctx, bz), "cannot call RemoveValidator on bonded or unbonding validators: failed to remove validator")
// shouldn't be able to remove if there are still tokens left
validators[1].Status = stakingtypes.Unbonded
require.NoError(keeper.SetValidator(ctx, validators[1]))
require.EqualError(keeper.RemoveValidator(ctx, bz), "attempting to remove a validator which still contains tokens: failed to remove validator")
validators[1].Tokens = math.ZeroInt() // ...remove all tokens
require.NoError(keeper.SetValidator(ctx, validators[1])) // ...set the validator
require.NoError(keeper.RemoveValidator(ctx, bz)) // Now it can be removed.
_, err = keeper.GetValidator(ctx, sdk.ValAddress(PKs[1].Address().Bytes()))
require.ErrorIs(err, stakingtypes.ErrNoValidatorFound)
}
func (s *KeeperTestSuite) TestUpdateValidatorByPowerIndex() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
valPubKey := PKs[0]
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
valTokens := keeper.TokensFromConsensusPower(ctx, 100)
// add a validator
validator := testutil.NewValidator(s.T(), valAddr, PKs[0])
validator, delSharesCreated := validator.AddTokensFromDel(valTokens)
require.Equal(stakingtypes.Unbonded, validator.Status)
require.Equal(valTokens, validator.Tokens)
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true)
validator, err := keeper.GetValidator(ctx, valAddr)
require.NoError(err)
require.Equal(valTokens, validator.Tokens)
power := stakingtypes.GetValidatorsByPowerIndexKey(validator, keeper.PowerReduction(ctx), keeper.ValidatorAddressCodec())
require.True(stakingkeeper.ValidatorByPowerIndexExists(ctx, keeper, power))
// burn half the delegator shares
require.NoError(keeper.DeleteValidatorByPowerIndex(ctx, validator))
validator, burned := validator.RemoveDelShares(delSharesCreated.Quo(math.LegacyNewDec(2)))
require.Equal(keeper.TokensFromConsensusPower(ctx, 50), burned)
stakingkeeper.TestingUpdateValidator(keeper, ctx, validator, true) // update the validator, possibly kicking it out
require.False(stakingkeeper.ValidatorByPowerIndexExists(ctx, keeper, power))
validator, err = keeper.GetValidator(ctx, valAddr)
require.NoError(err)
power = stakingtypes.GetValidatorsByPowerIndexKey(validator, keeper.PowerReduction(ctx), keeper.ValidatorAddressCodec())
require.True(stakingkeeper.ValidatorByPowerIndexExists(ctx, keeper, power))
// set new validator by power index
require.NoError(keeper.DeleteValidatorByPowerIndex(ctx, validator))
require.False(stakingkeeper.ValidatorByPowerIndexExists(ctx, keeper, power))
require.NoError(keeper.SetNewValidatorByPowerIndex(ctx, validator))
require.True(stakingkeeper.ValidatorByPowerIndexExists(ctx, keeper, power))
}
func (s *KeeperTestSuite) TestApplyAndReturnValidatorSetUpdatesPowerDecrease() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
powers := []int64{100, 100}
var validators [2]stakingtypes.Validator
for i, power := range powers {
validators[i] = testutil.NewValidator(s.T(), sdk.ValAddress(PKs[i].Address().Bytes()), PKs[i])
tokens := keeper.TokensFromConsensusPower(ctx, power)
validators[i], _ = validators[i].AddTokensFromDel(tokens)
}
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validators[0] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[0], false)
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
validators[1] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[1], false)
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
s.applyValidatorSetUpdates(ctx, keeper, 2)
// check initial power
require.Equal(int64(100), validators[0].GetConsensusPower(keeper.PowerReduction(ctx)))
require.Equal(int64(100), validators[1].GetConsensusPower(keeper.PowerReduction(ctx)))
// test multiple value change
// tendermintUpdate set: {c1, c3} -> {c1', c3'}
delTokens1 := keeper.TokensFromConsensusPower(ctx, 20)
delTokens2 := keeper.TokensFromConsensusPower(ctx, 30)
validators[0], _ = validators[0].RemoveDelShares(math.LegacyNewDecFromInt(delTokens1))
validators[1], _ = validators[1].RemoveDelShares(math.LegacyNewDecFromInt(delTokens2))
validators[0] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[0], false)
validators[1] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[1], false)
// power has changed
require.Equal(int64(80), validators[0].GetConsensusPower(keeper.PowerReduction(ctx)))
require.Equal(int64(70), validators[1].GetConsensusPower(keeper.PowerReduction(ctx)))
// CometBFT updates should reflect power change
updates := s.applyValidatorSetUpdates(ctx, keeper, 2)
require.Equal(validators[0].ModuleValidatorUpdate(keeper.PowerReduction(ctx)), updates[0])
require.Equal(validators[1].ModuleValidatorUpdate(keeper.PowerReduction(ctx)), updates[1])
}
func (s *KeeperTestSuite) TestUpdateValidatorCommission() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
// Set MinCommissionRate to 0.05
params, err := keeper.Params.Get(ctx)
require.NoError(err)
params.MinCommissionRate = math.LegacyNewDecWithPrec(5, 2)
require.NoError(keeper.Params.Set(ctx, params))
commission1 := stakingtypes.NewCommissionWithTime(
math.LegacyNewDecWithPrec(1, 1), math.LegacyNewDecWithPrec(3, 1),
math.LegacyNewDecWithPrec(1, 1), time.Now().UTC().Add(time.Duration(-1)*time.Hour),
)
commission2 := stakingtypes.NewCommission(math.LegacyNewDecWithPrec(1, 1), math.LegacyNewDecWithPrec(3, 1), math.LegacyNewDecWithPrec(1, 1))
val1 := testutil.NewValidator(s.T(), sdk.ValAddress(PKs[0].Address().Bytes()), PKs[0])
val2 := testutil.NewValidator(s.T(), sdk.ValAddress(PKs[1].Address().Bytes()), PKs[1])
val1, _ = val1.SetInitialCommission(commission1)
val2, _ = val2.SetInitialCommission(commission2)
require.NoError(keeper.SetValidator(ctx, val1))
require.NoError(keeper.SetValidator(ctx, val2))
testCases := []struct {
validator stakingtypes.Validator
newRate math.LegacyDec
expectedErr bool
}{
{val1, math.LegacyZeroDec(), true},
{val2, math.LegacyNewDecWithPrec(-1, 1), true},
{val2, math.LegacyNewDecWithPrec(4, 1), true},
{val2, math.LegacyNewDecWithPrec(3, 1), true},
{val2, math.LegacyNewDecWithPrec(1, 2), true},
{val2, math.LegacyNewDecWithPrec(2, 1), false},
}
for i, tc := range testCases {
commission, err := keeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate)
if tc.expectedErr {
require.Error(err, "expected error for test case #%d with rate: %s", i, tc.newRate)
} else {
require.NoError(err,
"unexpected error for test case #%d with rate: %s", i, tc.newRate,
)
tc.validator.Commission = commission
err = keeper.SetValidator(ctx, tc.validator)
require.NoError(err)
bz, err := keeper.ValidatorAddressCodec().StringToBytes(tc.validator.GetOperator())
require.NoError(err)
val, err := keeper.GetValidator(ctx, bz)
require.NoError(err,
"expected to find validator for test case #%d with rate: %s", i, tc.newRate,
)
require.Equal(tc.newRate, val.Commission.Rate,
"expected new validator commission rate for test case #%d with rate: %s", i, tc.newRate,
)
require.Equal(ctx.HeaderInfo().Time, val.Commission.UpdateTime,
"expected new validator commission update time for test case #%d with rate: %s", i, tc.newRate,
)
}
}
}
func (s *KeeperTestSuite) TestValidatorToken() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
valPubKey := PKs[0]
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
addTokens := keeper.TokensFromConsensusPower(ctx, 10)
delTokens := keeper.TokensFromConsensusPower(ctx, 5)
validator := testutil.NewValidator(s.T(), valAddr, valPubKey)
validator, _, err := keeper.AddValidatorTokensAndShares(ctx, validator, addTokens)
require.NoError(err)
require.Equal(addTokens, validator.Tokens)
validator, _ = keeper.GetValidator(ctx, valAddr)
require.Equal(math.LegacyNewDecFromInt(addTokens), validator.DelegatorShares)
_, _, err = keeper.RemoveValidatorTokensAndShares(ctx, validator, math.LegacyNewDecFromInt(delTokens))
require.NoError(err)
validator, _ = keeper.GetValidator(ctx, valAddr)
require.Equal(delTokens, validator.Tokens)
require.True(validator.DelegatorShares.Equal(math.LegacyNewDecFromInt(delTokens)))
_, err = keeper.RemoveValidatorTokens(ctx, validator, delTokens)
require.NoError(err)
validator, _ = keeper.GetValidator(ctx, valAddr)
require.True(validator.Tokens.IsZero())
}
// TestUnbondingValidator tests the functionality of unbonding a validator.
func (s *KeeperTestSuite) TestUnbondingValidator() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()
valPubKey := PKs[0]
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
validator := testutil.NewValidator(s.T(), valAddr, valPubKey)
addTokens := keeper.TokensFromConsensusPower(ctx, 10)
// set unbonding validator
endTime := time.Now()
endHeight := ctx.HeaderInfo().Height + 10
require.NoError(keeper.SetUnbondingValidatorsQueue(ctx, endTime, endHeight, []string{s.valAddressToString(valAddr)}))
resVals, err := keeper.GetUnbondingValidators(ctx, endTime, endHeight)
require.NoError(err)
require.Equal(1, len(resVals))
require.Equal(s.valAddressToString(valAddr), resVals[0])
// add another unbonding validator
valAddr1 := sdk.ValAddress(PKs[1].Address().Bytes())
validator1 := testutil.NewValidator(s.T(), valAddr1, PKs[1])
validator1.UnbondingHeight = endHeight
validator1.UnbondingTime = endTime
require.NoError(keeper.InsertUnbondingValidatorQueue(ctx, validator1))
resVals, err = keeper.GetUnbondingValidators(ctx, endTime, endHeight)
require.NoError(err)
require.Equal(2, len(resVals))
// delete unbonding validator from the queue
require.NoError(keeper.DeleteValidatorQueue(ctx, validator1))
resVals, err = keeper.GetUnbondingValidators(ctx, endTime, endHeight)
require.NoError(err)
require.Equal(1, len(resVals))
require.Equal(s.valAddressToString(valAddr), resVals[0])
// check unbonding mature validators
ctx = ctx.WithHeaderInfo(header.Info{Height: endHeight, Time: endTime})
err = keeper.UnbondAllMatureValidators(ctx)
require.EqualError(err, "validator in the unbonding queue was not found: validator does not exist")
require.NoError(keeper.SetValidator(ctx, validator))
ctx = ctx.WithHeaderInfo(header.Info{Height: endHeight, Time: endTime})
err = keeper.UnbondAllMatureValidators(ctx)
require.EqualError(err, "unexpected validator in unbonding queue; status was not unbonding")
validator.Status = stakingtypes.Unbonding
require.NoError(keeper.SetValidator(ctx, validator))
require.NoError(keeper.UnbondAllMatureValidators(ctx))
validator, err = keeper.GetValidator(ctx, valAddr)
require.ErrorIs(err, stakingtypes.ErrNoValidatorFound)
require.NoError(keeper.SetUnbondingValidatorsQueue(ctx, endTime, endHeight, []string{s.valAddressToString(valAddr)}))
validator = testutil.NewValidator(s.T(), valAddr, valPubKey)
validator, _ = validator.AddTokensFromDel(addTokens)
validator.Status = stakingtypes.Unbonding
require.NoError(keeper.SetValidator(ctx, validator))
require.NoError(keeper.UnbondAllMatureValidators(ctx))
validator, err = keeper.GetValidator(ctx, valAddr)
require.NoError(err)
require.Equal(stakingtypes.Unbonded, validator.Status)
}
func (s *KeeperTestSuite) TestValidatorConsPubKeyUpdate() {
ctx, keeper, msgServer, bk, ak := s.ctx, s.stakingKeeper, s.msgServer, s.bankKeeper, s.accountKeeper
require := s.Require()
powers := []int64{10, 20}
var validators [2]stakingtypes.Validator
bonedPool := authtypes.NewEmptyModuleAccount(stakingtypes.BondedPoolName)
ak.EXPECT().GetModuleAccount(gomock.Any(), stakingtypes.BondedPoolName).Return(bonedPool).AnyTimes()
bk.EXPECT().GetBalance(gomock.Any(), bonedPool.GetAddress(), sdk.DefaultBondDenom).Return(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)).AnyTimes()
for i, power := range powers {
valAddr := sdk.ValAddress(PKs[i].Address().Bytes())
validators[i] = testutil.NewValidator(s.T(), valAddr, PKs[i])
tokens := keeper.TokensFromConsensusPower(ctx, power)
validators[i], _ = validators[i].AddTokensFromDel(tokens)
require.NoError(keeper.SetValidator(ctx, validators[i]))
require.NoError(keeper.SetValidatorByPowerIndex(ctx, validators[i]))
require.NoError(keeper.SetValidatorByConsAddr(ctx, validators[i]))
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, gomock.Any())
updates := s.applyValidatorSetUpdates(ctx, keeper, 1)
validator, err := keeper.GetValidator(ctx, valAddr)
require.NoError(err)
require.Equal(validator.ModuleValidatorUpdate(keeper.PowerReduction(ctx)), updates[0])
}
params, err := keeper.Params.Get(ctx)
require.NoError(err)
params.KeyRotationFee = sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000)
err = keeper.Params.Set(ctx, params)
require.NoError(err)
valAddr1 := sdk.ValAddress(PKs[0].Address().Bytes())
valStr, err := keeper.ValidatorAddressCodec().BytesToString(valAddr1)
require.NoError(err)
msg, err := stakingtypes.NewMsgRotateConsPubKey(
valStr,
PKs[499], // taking the last element from PKs
)
require.NoError(err)
bk.EXPECT().SendCoinsFromAccountToModule(ctx, sdk.AccAddress(valAddr1), gomock.Any(), gomock.Any()).AnyTimes()
_, err = msgServer.RotateConsPubKey(ctx, msg)
require.NoError(err)
updates := s.applyValidatorSetUpdates(ctx, keeper, 2)
originalPubKey, err := validators[0].ConsPubKey()
require.NoError(err)
validator, err := keeper.GetValidator(ctx, valAddr1)
require.NoError(err)
newPubKey, err := validator.ConsPubKey()
require.NoError(err)
require.Equal(int64(0), updates[0].Power)
require.Equal(originalPubKey.Bytes(), updates[0].PubKey)
require.Equal(int64(10), updates[1].Power)
require.Equal(newPubKey.Bytes(), updates[1].PubKey)
}