diff --git a/scripts/mockgen.sh b/scripts/mockgen.sh index dae680dff9c9..6c6be4a74fe7 100755 --- a/scripts/mockgen.sh +++ b/scripts/mockgen.sh @@ -20,3 +20,4 @@ $mockgen_cmd -source=x/auth/ante/expected_keepers.go -package testutil -destinat $mockgen_cmd -source=x/authz/expected_keepers.go -package testutil -destination x/authz/testutil/expected_keepers_mocks.go $mockgen_cmd -source=x/bank/types/expected_keepers.go -package testutil -destination x/bank/testutil/expected_keepers_mocks.go $mockgen_cmd -source=x/evidence/types/expected_keepers.go -package testutil -destination x/evidence/testutil/expected_keepers_mocks.go +$mockgen_cmd -source=x/slashing/types/expected_keepers.go -package testutil -destination x/slashing/testutil/expected_keepers_mocks.go diff --git a/tests/e2e/slashing/client/testutil/cli_test.go b/tests/e2e/slashing/client/testutil/cli_test.go index 3fe7a357e141..7d84c365f20c 100644 --- a/tests/e2e/slashing/client/testutil/cli_test.go +++ b/tests/e2e/slashing/client/testutil/cli_test.go @@ -8,13 +8,12 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/testutil/network" - clienttestutil "github.com/cosmos/cosmos-sdk/x/slashing/client/testutil" "github.com/stretchr/testify/suite" ) -func TestIntegrationTestSuite(t *testing.T) { +func TestEndToEndTestSuite(t *testing.T) { cfg := network.DefaultConfig(simapp.NewTestNetworkFixture) cfg.NumValidators = 1 - suite.Run(t, clienttestutil.NewIntegrationTestSuite(cfg)) + suite.Run(t, NewEndToEndTestSuite(cfg)) } diff --git a/x/slashing/client/testutil/grpc.go b/tests/e2e/slashing/client/testutil/grpc.go similarity index 97% rename from x/slashing/client/testutil/grpc.go rename to tests/e2e/slashing/client/testutil/grpc.go index fc41baf953aa..fe70df8182a0 100644 --- a/x/slashing/client/testutil/grpc.go +++ b/tests/e2e/slashing/client/testutil/grpc.go @@ -13,7 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing/types" ) -func (s *IntegrationTestSuite) TestGRPCQueries() { +func (s *EndToEndTestSuite) TestGRPCQueries() { val := s.network.Validators[0] baseURL := val.APIAddress diff --git a/x/slashing/client/testutil/suite.go b/tests/e2e/slashing/client/testutil/suite.go similarity index 91% rename from x/slashing/client/testutil/suite.go rename to tests/e2e/slashing/client/testutil/suite.go index 06bcdca70110..2623eb03dba8 100644 --- a/x/slashing/client/testutil/suite.go +++ b/tests/e2e/slashing/client/testutil/suite.go @@ -15,20 +15,20 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing/client/cli" ) -type IntegrationTestSuite struct { +type EndToEndTestSuite struct { suite.Suite cfg network.Config network *network.Network } -func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { - return &IntegrationTestSuite{cfg: cfg} +func NewEndToEndTestSuite(cfg network.Config) *EndToEndTestSuite { + return &EndToEndTestSuite{cfg: cfg} } // SetupSuite executes bootstrapping logic before all the tests, i.e. once before // the entire suite, start executing. -func (s *IntegrationTestSuite) SetupSuite() { +func (s *EndToEndTestSuite) SetupSuite() { s.T().Log("setting up integration test suite") var err error @@ -41,12 +41,12 @@ func (s *IntegrationTestSuite) SetupSuite() { // TearDownSuite performs cleanup logic after all the tests, i.e. once after the // entire suite, has finished executing. -func (s *IntegrationTestSuite) TearDownSuite() { +func (s *EndToEndTestSuite) TearDownSuite() { s.T().Log("tearing down integration test suite") s.network.Cleanup() } -func (s *IntegrationTestSuite) TestGetCmdQuerySigningInfo() { +func (s *EndToEndTestSuite) TestGetCmdQuerySigningInfo() { val := s.network.Validators[0] pubKeyBz, err := s.cfg.Codec.MarshalInterfaceJSON(val.PubKey) s.Require().NoError(err) @@ -104,7 +104,7 @@ tombstoned: false`, sdk.ConsAddress(val.PubKey.Address())), } } -func (s *IntegrationTestSuite) TestGetCmdQueryParams() { +func (s *EndToEndTestSuite) TestGetCmdQueryParams() { val := s.network.Validators[0] testCases := []struct { @@ -142,7 +142,7 @@ slash_fraction_downtime: "0.010000000000000000"`, } } -func (s *IntegrationTestSuite) TestNewUnjailTxCmd() { +func (s *EndToEndTestSuite) TestNewUnjailTxCmd() { val := s.network.Validators[0] testCases := []struct { name string diff --git a/tests/integration/slashing/keeper/keeper_test.go b/tests/integration/slashing/keeper/keeper_test.go new file mode 100644 index 000000000000..bbd703818aa4 --- /dev/null +++ b/tests/integration/slashing/keeper/keeper_test.go @@ -0,0 +1,353 @@ +package keeper_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cosmos/cosmos-sdk/baseapp" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/slashing/testslashing" + "github.com/cosmos/cosmos-sdk/x/slashing/testutil" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/staking/teststaking" + + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// The default power validators are initialized to have within tests +var InitTokens = sdk.TokensFromConsensusPower(200, sdk.DefaultPowerReduction) + +type KeeperTestSuite struct { + suite.Suite + + ctx sdk.Context + slashingKeeper slashingkeeper.Keeper + stakingKeeper *stakingkeeper.Keeper + bankKeeper bankkeeper.Keeper + accountKeeper authkeeper.AccountKeeper + interfaceRegistry codectypes.InterfaceRegistry + addrDels []sdk.AccAddress + queryClient slashingtypes.QueryClient + msgServer slashingtypes.MsgServer +} + +func (s *KeeperTestSuite) SetupTest() { + app, err := simtestutil.Setup( + testutil.AppConfig, + &s.bankKeeper, + &s.accountKeeper, + &s.slashingKeeper, + &s.stakingKeeper, + &s.interfaceRegistry, + ) + s.Require().NoError(err) + + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + + s.accountKeeper.SetParams(ctx, authtypes.DefaultParams()) + s.bankKeeper.SetParams(ctx, banktypes.DefaultParams()) + s.slashingKeeper.SetParams(ctx, testslashing.TestParams()) + + addrDels := simtestutil.AddTestAddrsIncremental(s.bankKeeper, s.stakingKeeper, ctx, 5, s.stakingKeeper.TokensFromConsensusPower(ctx, 200)) + + info1 := slashingtypes.NewValidatorSigningInfo(sdk.ConsAddress(addrDels[0]), int64(4), int64(3), + time.Unix(2, 0), false, int64(10)) + info2 := slashingtypes.NewValidatorSigningInfo(sdk.ConsAddress(addrDels[1]), int64(5), int64(4), + time.Unix(2, 0), false, int64(10)) + + s.slashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0]), info1) + s.slashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[1]), info2) + + queryHelper := baseapp.NewQueryServerTestHelper(ctx, s.interfaceRegistry) + slashingtypes.RegisterQueryServer(queryHelper, s.slashingKeeper) + queryClient := slashingtypes.NewQueryClient(queryHelper) + s.queryClient = queryClient + + s.addrDels = addrDels + s.ctx = ctx + s.msgServer = slashingkeeper.NewMsgServerImpl(s.slashingKeeper) +} + +func (s *KeeperTestSuite) TestUnJailNotBonded() { + ctx := s.ctx + + p := s.stakingKeeper.GetParams(ctx) + p.MaxValidators = 5 + s.stakingKeeper.SetParams(ctx, p) + + addrDels := simtestutil.AddTestAddrsIncremental(s.bankKeeper, s.stakingKeeper, ctx, 6, s.stakingKeeper.TokensFromConsensusPower(ctx, 200)) + valAddrs := simtestutil.ConvertAddrsToValAddrs(addrDels) + pks := simtestutil.CreateTestPubKeys(6) + tstaking := teststaking.NewHelper(s.T(), ctx, s.stakingKeeper) + + // create max (5) validators all with the same power + for i := uint32(0); i < p.MaxValidators; i++ { + addr, val := valAddrs[i], pks[i] + tstaking.CreateValidatorWithValPower(addr, val, 100, true) + } + + staking.EndBlocker(ctx, s.stakingKeeper) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + + // create a 6th validator with less power than the cliff validator (won't be bonded) + addr, val := valAddrs[5], pks[5] + amt := s.stakingKeeper.TokensFromConsensusPower(ctx, 50) + msg := tstaking.CreateValidatorMsg(addr, val, amt) + msg.MinSelfDelegation = amt + res, err := tstaking.CreateValidatorWithMsg(sdk.WrapSDKContext(ctx), msg) + s.Require().NoError(err) + s.Require().NotNil(res) + + staking.EndBlocker(ctx, s.stakingKeeper) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + + tstaking.CheckValidator(addr, stakingtypes.Unbonded, false) + + // unbond below minimum self-delegation + s.Require().Equal(p.BondDenom, tstaking.Denom) + tstaking.Undelegate(sdk.AccAddress(addr), addr, s.stakingKeeper.TokensFromConsensusPower(ctx, 1), true) + + staking.EndBlocker(ctx, s.stakingKeeper) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + + // verify that validator is jailed + tstaking.CheckValidator(addr, -1, true) + + // verify we cannot unjail (yet) + s.Require().Error(s.slashingKeeper.Unjail(ctx, addr)) + + staking.EndBlocker(ctx, s.stakingKeeper) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + // bond to meet minimum self-delegation + tstaking.DelegateWithPower(sdk.AccAddress(addr), addr, 1) + + staking.EndBlocker(ctx, s.stakingKeeper) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + + // verify we can immediately unjail + s.Require().NoError(s.slashingKeeper.Unjail(ctx, addr)) + + tstaking.CheckValidator(addr, -1, false) +} + +// Test a new validator entering the validator set +// Ensure that SigningInfo.StartHeight is set correctly +// and that they are not immediately jailed +func (s *KeeperTestSuite) TestHandleNewValidator() { + ctx := s.ctx + + addrDels := simtestutil.AddTestAddrsIncremental(s.bankKeeper, s.stakingKeeper, ctx, 1, s.stakingKeeper.TokensFromConsensusPower(ctx, 0)) + valAddrs := simtestutil.ConvertAddrsToValAddrs(addrDels) + pks := simtestutil.CreateTestPubKeys(1) + addr, val := valAddrs[0], pks[0] + tstaking := teststaking.NewHelper(s.T(), ctx, s.stakingKeeper) + ctx = ctx.WithBlockHeight(s.slashingKeeper.SignedBlocksWindow(ctx) + 1) + + // Validator created + amt := tstaking.CreateValidatorWithValPower(addr, val, 100, true) + + staking.EndBlocker(ctx, s.stakingKeeper) + s.Require().Equal( + s.bankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), + sdk.NewCoins(sdk.NewCoin(s.stakingKeeper.GetParams(ctx).BondDenom, InitTokens.Sub(amt))), + ) + s.Require().Equal(amt, s.stakingKeeper.Validator(ctx, addr).GetBondedTokens()) + + // Now a validator, for two blocks + s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), 100, true) + ctx = ctx.WithBlockHeight(s.slashingKeeper.SignedBlocksWindow(ctx) + 2) + s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), 100, false) + + info, found := s.slashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) + s.Require().True(found) + s.Require().Equal(s.slashingKeeper.SignedBlocksWindow(ctx)+1, info.StartHeight) + s.Require().Equal(int64(2), info.IndexOffset) + s.Require().Equal(int64(1), info.MissedBlocksCounter) + s.Require().Equal(time.Unix(0, 0).UTC(), info.JailedUntil) + + // validator should be bonded still, should not have been jailed or slashed + validator, _ := s.stakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + s.Require().Equal(stakingtypes.Bonded, validator.GetStatus()) + bondPool := s.stakingKeeper.GetBondedPool(ctx) + expTokens := s.stakingKeeper.TokensFromConsensusPower(ctx, 100) + // adding genesis validator tokens + expTokens = expTokens.Add(s.stakingKeeper.TokensFromConsensusPower(ctx, 1)) + s.Require().True(expTokens.Equal(s.bankKeeper.GetBalance(ctx, bondPool.GetAddress(), s.stakingKeeper.BondDenom(ctx)).Amount)) +} + +// Test a jailed validator being "down" twice +// Ensure that they're only slashed once +func (s *KeeperTestSuite) TestHandleAlreadyJailed() { + // initial setup + + ctx := s.ctx + + addrDels := simtestutil.AddTestAddrsIncremental(s.bankKeeper, s.stakingKeeper, ctx, 1, s.stakingKeeper.TokensFromConsensusPower(ctx, 200)) + valAddrs := simtestutil.ConvertAddrsToValAddrs(addrDels) + pks := simtestutil.CreateTestPubKeys(1) + addr, val := valAddrs[0], pks[0] + power := int64(100) + tstaking := teststaking.NewHelper(s.T(), ctx, s.stakingKeeper) + + amt := tstaking.CreateValidatorWithValPower(addr, val, power, true) + + staking.EndBlocker(ctx, s.stakingKeeper) + + // 1000 first blocks OK + height := int64(0) + for ; height < s.slashingKeeper.SignedBlocksWindow(ctx); height++ { + ctx = ctx.WithBlockHeight(height) + s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, true) + } + + // 501 blocks missed + for ; height < s.slashingKeeper.SignedBlocksWindow(ctx)+(s.slashingKeeper.SignedBlocksWindow(ctx)-s.slashingKeeper.MinSignedPerWindow(ctx))+1; height++ { + ctx = ctx.WithBlockHeight(height) + s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) + } + + // end block + staking.EndBlocker(ctx, s.stakingKeeper) + + // validator should have been jailed and slashed + validator, _ := s.stakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + s.Require().Equal(stakingtypes.Unbonding, validator.GetStatus()) + + // validator should have been slashed + resultingTokens := amt.Sub(s.stakingKeeper.TokensFromConsensusPower(ctx, 1)) + s.Require().Equal(resultingTokens, validator.GetTokens()) + + // another block missed + ctx = ctx.WithBlockHeight(height) + s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) + + // validator should not have been slashed twice + validator, _ = s.stakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) + s.Require().Equal(resultingTokens, validator.GetTokens()) +} + +// Test a validator dipping in and out of the validator set +// Ensure that missed blocks are tracked correctly and that +// the start height of the signing info is reset correctly +func (s *KeeperTestSuite) TestValidatorDippingInAndOut() { + // initial setup + // TestParams set the SignedBlocksWindow to 1000 and MaxMissedBlocksPerWindow to 500 + + ctx := s.ctx + s.slashingKeeper.SetParams(ctx, testslashing.TestParams()) + + params := s.stakingKeeper.GetParams(ctx) + params.MaxValidators = 1 + s.stakingKeeper.SetParams(ctx, params) + power := int64(100) + + pks := simtestutil.CreateTestPubKeys(3) + simtestutil.AddTestAddrsFromPubKeys(s.bankKeeper, s.stakingKeeper, ctx, pks, s.stakingKeeper.TokensFromConsensusPower(ctx, 200)) + + addr, val := pks[0].Address(), pks[0] + consAddr := sdk.ConsAddress(addr) + tstaking := teststaking.NewHelper(s.T(), ctx, s.stakingKeeper) + valAddr := sdk.ValAddress(addr) + + tstaking.CreateValidatorWithValPower(valAddr, val, power, true) + validatorUpdates := staking.EndBlocker(ctx, s.stakingKeeper) + s.Require().Equal(2, len(validatorUpdates)) + tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false) + + // 100 first blocks OK + height := int64(0) + for ; height < int64(100); height++ { + ctx = ctx.WithBlockHeight(height) + s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, true) + } + + // kick first validator out of validator set + tstaking.CreateValidatorWithValPower(sdk.ValAddress(pks[1].Address()), pks[1], power+1, true) + validatorUpdates = staking.EndBlocker(ctx, s.stakingKeeper) + s.Require().Equal(2, len(validatorUpdates)) + tstaking.CheckValidator(sdk.ValAddress(pks[1].Address()), stakingtypes.Bonded, false) + tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, false) + + // 600 more blocks happened + height = height + 600 + ctx = ctx.WithBlockHeight(height) + + // validator added back in + tstaking.DelegateWithPower(sdk.AccAddress(pks[2].Address()), valAddr, 50) + + validatorUpdates = staking.EndBlocker(ctx, s.stakingKeeper) + s.Require().Equal(2, len(validatorUpdates)) + tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false) + newPower := power + 50 + + // validator misses a block + s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) + height++ + + // shouldn't be jailed/kicked yet + tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false) + + // validator misses an additional 500 more blocks, after the cooling off period of SignedBlockWindow (here 1000 blocks). + latest := s.slashingKeeper.SignedBlocksWindow(ctx) + height + for ; height < latest+s.slashingKeeper.MinSignedPerWindow(ctx); height++ { + ctx = ctx.WithBlockHeight(height) + s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) + } + + // should now be jailed & kicked + staking.EndBlocker(ctx, s.stakingKeeper) + tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, true) + + // check all the signing information + signInfo, found := s.slashingKeeper.GetValidatorSigningInfo(ctx, consAddr) + s.Require().True(found) + s.Require().Equal(int64(700), signInfo.StartHeight) + s.Require().Equal(int64(499), signInfo.MissedBlocksCounter) + s.Require().Equal(int64(499), signInfo.IndexOffset) + + // some blocks pass + height = int64(5000) + ctx = ctx.WithBlockHeight(height) + + // validator rejoins and starts signing again + s.stakingKeeper.Unjail(ctx, consAddr) + + s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, true) + + // validator should not be kicked since we reset counter/array when it was jailed + staking.EndBlocker(ctx, s.stakingKeeper) + tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false) + + // check start height is correctly set + signInfo, found = s.slashingKeeper.GetValidatorSigningInfo(ctx, consAddr) + s.Require().True(found) + s.Require().Equal(height, signInfo.StartHeight) + + // validator misses 501 blocks after SignedBlockWindow period (1000 blocks) + latest = s.slashingKeeper.SignedBlocksWindow(ctx) + height + for ; height < latest+s.slashingKeeper.MinSignedPerWindow(ctx); height++ { + ctx = ctx.WithBlockHeight(height) + s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) + } + + // validator should now be jailed & kicked + staking.EndBlocker(ctx, s.stakingKeeper) + tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, true) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/x/slashing/keeper/common_test.go b/x/slashing/keeper/common_test.go deleted file mode 100644 index 4e4be93b91e8..000000000000 --- a/x/slashing/keeper/common_test.go +++ /dev/null @@ -1,6 +0,0 @@ -package keeper_test - -import sdk "github.com/cosmos/cosmos-sdk/types" - -// The default power validators are initialized to have within tests -var InitTokens = sdk.TokensFromConsensusPower(200, sdk.DefaultPowerReduction) diff --git a/x/slashing/keeper/genesis_test.go b/x/slashing/keeper/genesis_test.go index f4dc734dd515..2b882c1bba45 100644 --- a/x/slashing/keeper/genesis_test.go +++ b/x/slashing/keeper/genesis_test.go @@ -1,74 +1,57 @@ package keeper_test import ( - "testing" "time" - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "github.com/golang/mock/gomock" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" "github.com/cosmos/cosmos-sdk/x/slashing/testslashing" - "github.com/cosmos/cosmos-sdk/x/slashing/testutil" "github.com/cosmos/cosmos-sdk/x/slashing/types" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) -func TestExportAndInitGenesis(t *testing.T) { - var slashingKeeper slashingkeeper.Keeper - var stakingKeeper *stakingkeeper.Keeper - var bankKeeper bankkeeper.Keeper +func (s *KeeperTestSuite) TestExportAndInitGenesis() { + ctx, keeper := s.ctx, s.slashingKeeper + require := s.Require() - app, err := simtestutil.Setup( - testutil.AppConfig, - &slashingKeeper, - &stakingKeeper, - &bankKeeper, - ) - require.NoError(t, err) + keeper.SetParams(ctx, testslashing.TestParams()) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + consAddr1 := sdk.ConsAddress(sdk.AccAddress([]byte("addr1_______________"))) + consAddr2 := sdk.ConsAddress(sdk.AccAddress([]byte("addr2_______________"))) - slashingKeeper.SetParams(ctx, testslashing.TestParams()) - - addrDels := simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, ctx, 2, stakingKeeper.TokensFromConsensusPower(ctx, 200)) - - info1 := types.NewValidatorSigningInfo(sdk.ConsAddress(addrDels[0]), int64(4), int64(3), + info1 := types.NewValidatorSigningInfo(consAddr1, int64(4), int64(3), time.Now().UTC().Add(100000000000), false, int64(10)) - info2 := types.NewValidatorSigningInfo(sdk.ConsAddress(addrDels[1]), int64(5), int64(4), + info2 := types.NewValidatorSigningInfo(consAddr2, int64(5), int64(4), time.Now().UTC().Add(10000000000), false, int64(10)) - slashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0]), info1) - slashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[1]), info2) - genesisState := slashingKeeper.ExportGenesis(ctx) + keeper.SetValidatorSigningInfo(ctx, consAddr1, info1) + keeper.SetValidatorSigningInfo(ctx, consAddr2, info2) + genesisState := keeper.ExportGenesis(ctx) - require.Equal(t, genesisState.Params, testslashing.TestParams()) - require.Len(t, genesisState.SigningInfos, 2) - require.Equal(t, genesisState.SigningInfos[0].ValidatorSigningInfo, info1) + require.Equal(genesisState.Params, testslashing.TestParams()) + require.Len(genesisState.SigningInfos, 2) + require.Equal(genesisState.SigningInfos[0].ValidatorSigningInfo, info1) // Tombstone validators after genesis shouldn't effect genesis state - slashingKeeper.Tombstone(ctx, sdk.ConsAddress(addrDels[0])) - slashingKeeper.Tombstone(ctx, sdk.ConsAddress(addrDels[1])) + keeper.Tombstone(ctx, consAddr1) + keeper.Tombstone(ctx, consAddr2) - ok := slashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(addrDels[0])) - require.True(t, ok) + ok := keeper.IsTombstoned(ctx, consAddr1) + require.True(ok) - newInfo1, ok := slashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0])) - require.NotEqual(t, info1, newInfo1) - // Initialise genesis with genesis state before tombstone + newInfo1, _ := keeper.GetValidatorSigningInfo(ctx, consAddr1) + require.NotEqual(info1, newInfo1) - slashingKeeper.InitGenesis(ctx, stakingKeeper, genesisState) + // Initialise genesis with genesis state before tombstone + s.stakingKeeper.EXPECT().IterateValidators(ctx, gomock.Any()).Return() + keeper.InitGenesis(ctx, s.stakingKeeper, genesisState) // Validator isTombstoned should return false as GenesisState is initialised - ok = slashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(addrDels[0])) - require.False(t, ok) + ok = keeper.IsTombstoned(ctx, consAddr1) + require.False(ok) - newInfo1, ok = slashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0])) - newInfo2, ok := slashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[1])) - require.True(t, ok) - require.Equal(t, info1, newInfo1) - require.Equal(t, info2, newInfo2) + newInfo1, _ = keeper.GetValidatorSigningInfo(ctx, consAddr1) + newInfo2, _ := keeper.GetValidatorSigningInfo(ctx, consAddr2) + require.Equal(info1, newInfo1) + require.Equal(info2, newInfo2) } diff --git a/x/slashing/keeper/grpc_query_test.go b/x/slashing/keeper/grpc_query_test.go index 98cc4a2763f5..d11d4c9dbb01 100644 --- a/x/slashing/keeper/grpc_query_test.go +++ b/x/slashing/keeper/grpc_query_test.go @@ -2,59 +2,89 @@ package keeper_test import ( gocontext "context" + "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" "github.com/cosmos/cosmos-sdk/x/slashing/testslashing" - "github.com/cosmos/cosmos-sdk/x/slashing/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" ) -func (suite *KeeperTestSuite) TestGRPCQueryParams() { - queryClient := suite.queryClient - paramsResp, err := queryClient.Params(gocontext.Background(), &types.QueryParamsRequest{}) +func (s *KeeperTestSuite) TestGRPCQueryParams() { + queryClient := s.queryClient + require := s.Require() - suite.NoError(err) - suite.Equal(testslashing.TestParams(), paramsResp.Params) + paramsResp, err := queryClient.Params(gocontext.Background(), &slashingtypes.QueryParamsRequest{}) + + require.NoError(err) + require.Equal(testslashing.TestParams(), paramsResp.Params) } -func (suite *KeeperTestSuite) TestGRPCSigningInfo() { - queryClient := suite.queryClient +func (s *KeeperTestSuite) TestGRPCSigningInfo() { + queryClient, ctx, keeper := s.queryClient, s.ctx, s.slashingKeeper + require := s.Require() + + infoResp, err := queryClient.SigningInfo(gocontext.Background(), &slashingtypes.QuerySigningInfoRequest{ConsAddress: ""}) + require.Error(err) + require.Nil(infoResp) - infoResp, err := queryClient.SigningInfo(gocontext.Background(), &types.QuerySigningInfoRequest{ConsAddress: ""}) - suite.Error(err) - suite.Nil(infoResp) + signingInfo := slashingtypes.NewValidatorSigningInfo( + consAddr, + 0, + int64(0), + time.Unix(2, 0), + false, + int64(0), + ) - consAddr := sdk.ConsAddress(suite.addrDels[0]) - info, found := suite.slashingKeeper.GetValidatorSigningInfo(suite.ctx, consAddr) - suite.True(found) + keeper.SetValidatorSigningInfo(ctx, consAddr, signingInfo) + info, found := keeper.GetValidatorSigningInfo(ctx, consAddr) + require.True(found) infoResp, err = queryClient.SigningInfo(gocontext.Background(), - &types.QuerySigningInfoRequest{ConsAddress: consAddr.String()}) - suite.NoError(err) - suite.Equal(info, infoResp.ValSigningInfo) + &slashingtypes.QuerySigningInfoRequest{ConsAddress: consAddr.String()}) + require.NoError(err) + require.Equal(info, infoResp.ValSigningInfo) } -func (suite *KeeperTestSuite) TestGRPCSigningInfos() { - queryClient := suite.queryClient +func (s *KeeperTestSuite) TestGRPCSigningInfos() { + queryClient, ctx, keeper := s.queryClient, s.ctx, s.slashingKeeper + require := s.Require() + + // set two validator signing information + consAddr1 := sdk.ConsAddress(sdk.AccAddress([]byte("addr1_______________"))) + consAddr2 := sdk.ConsAddress(sdk.AccAddress([]byte("addr2_______________"))) + signingInfo := slashingtypes.NewValidatorSigningInfo( + consAddr1, + 0, + int64(0), + time.Unix(2, 0), + false, + int64(0), + ) + + keeper.SetValidatorSigningInfo(ctx, consAddr1, signingInfo) + signingInfo.Address = string(consAddr2) + keeper.SetValidatorSigningInfo(ctx, consAddr2, signingInfo) - var signingInfos []types.ValidatorSigningInfo + var signingInfos []slashingtypes.ValidatorSigningInfo - suite.slashingKeeper.IterateValidatorSigningInfos(suite.ctx, func(consAddr sdk.ConsAddress, info types.ValidatorSigningInfo) (stop bool) { + keeper.IterateValidatorSigningInfos(ctx, func(consAddr sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) { signingInfos = append(signingInfos, info) return false }) // verify all values are returned without pagination infoResp, err := queryClient.SigningInfos(gocontext.Background(), - &types.QuerySigningInfosRequest{Pagination: nil}) - suite.NoError(err) - suite.Equal(signingInfos, infoResp.Info) + &slashingtypes.QuerySigningInfosRequest{Pagination: nil}) + require.NoError(err) + require.Equal(signingInfos, infoResp.Info) infoResp, err = queryClient.SigningInfos(gocontext.Background(), - &types.QuerySigningInfosRequest{Pagination: &query.PageRequest{Limit: 1, CountTotal: true}}) - suite.NoError(err) - suite.Len(infoResp.Info, 1) - suite.Equal(signingInfos[0], infoResp.Info[0]) - suite.NotNil(infoResp.Pagination.NextKey) - suite.Equal(uint64(2), infoResp.Pagination.Total) + &slashingtypes.QuerySigningInfosRequest{Pagination: &query.PageRequest{Limit: 1, CountTotal: true}}) + require.NoError(err) + require.Len(infoResp.Info, 1) + require.Equal(signingInfos[0], infoResp.Info[0]) + require.NotNil(infoResp.Pagination.NextKey) + require.Equal(uint64(2), infoResp.Pagination.Total) } diff --git a/x/slashing/keeper/hooks_test.go b/x/slashing/keeper/hooks_test.go new file mode 100644 index 000000000000..d07b050632f4 --- /dev/null +++ b/x/slashing/keeper/hooks_test.go @@ -0,0 +1,43 @@ +package keeper_test + +import ( + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func (s *KeeperTestSuite) TestAfterValidatorBonded() { + ctx, keeper := s.ctx, s.slashingKeeper + require := s.Require() + + valAddr := sdk.ValAddress(consAddr.Bytes()) + keeper.AfterValidatorBonded(ctx, consAddr, valAddr) + + _, ok := keeper.GetValidatorSigningInfo(ctx, consAddr) + require.True(ok) +} + +func (s *KeeperTestSuite) TestAfterValidatorCreatedOrRemoved() { + ctx, keeper := s.ctx, s.slashingKeeper + require := s.Require() + + _, pubKey, addr := testdata.KeyTestPubAddr() + valAddr := sdk.ValAddress(addr) + + validator, err := stakingtypes.NewValidator(sdk.ValAddress(addr), pubKey, stakingtypes.Description{}) + require.NoError(err) + + s.stakingKeeper.EXPECT().Validator(ctx, valAddr).Return(validator) + err = keeper.AfterValidatorCreated(ctx, valAddr) + require.NoError(err) + + ePubKey, err := keeper.GetPubkey(ctx, addr.Bytes()) + require.NoError(err) + require.Equal(ePubKey, pubKey) + + err = keeper.AfterValidatorRemoved(ctx, sdk.ConsAddress(addr)) + require.NoError(err) + + _, err = keeper.GetPubkey(ctx, addr.Bytes()) + require.Error(err) +} diff --git a/x/slashing/keeper/keeper_test.go b/x/slashing/keeper/keeper_test.go index 622510dd690e..9285ce92eb52 100644 --- a/x/slashing/keeper/keeper_test.go +++ b/x/slashing/keeper/keeper_test.go @@ -2,346 +2,79 @@ package keeper_test import ( "testing" - "time" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/crypto" + + tmtime "github.com/tendermint/tendermint/libs/time" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/baseapp" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" "github.com/cosmos/cosmos-sdk/x/slashing/testslashing" - "github.com/cosmos/cosmos-sdk/x/slashing/testutil" - "github.com/cosmos/cosmos-sdk/x/slashing/types" + slashingtestutil "github.com/cosmos/cosmos-sdk/x/slashing/testutil" + + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - "github.com/cosmos/cosmos-sdk/x/staking" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - "github.com/cosmos/cosmos-sdk/x/staking/teststaking" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) +var consAddr = sdk.ConsAddress(sdk.AccAddress([]byte("addr1_______________"))) + type KeeperTestSuite struct { suite.Suite - ctx sdk.Context - slashingKeeper slashingkeeper.Keeper - stakingKeeper *stakingkeeper.Keeper - bankKeeper bankkeeper.Keeper - accountKeeper authkeeper.AccountKeeper - interfaceRegistry codectypes.InterfaceRegistry - addrDels []sdk.AccAddress - queryClient slashingtypes.QueryClient - msgServer types.MsgServer + ctx sdk.Context + stakingKeeper *slashingtestutil.MockStakingKeeper + slashingKeeper slashingkeeper.Keeper + queryClient slashingtypes.QueryClient + msgServer slashingtypes.MsgServer } func (s *KeeperTestSuite) SetupTest() { - app, err := simtestutil.Setup( - testutil.AppConfig, - &s.bankKeeper, - &s.accountKeeper, - &s.slashingKeeper, - &s.stakingKeeper, - &s.interfaceRegistry, - ) - s.Require().NoError(err) - - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - - s.accountKeeper.SetParams(ctx, authtypes.DefaultParams()) - s.bankKeeper.SetParams(ctx, banktypes.DefaultParams()) - s.slashingKeeper.SetParams(ctx, testslashing.TestParams()) + key := sdk.NewKVStoreKey(slashingtypes.StoreKey) + testCtx := testutil.DefaultContextWithDB(s.T(), key, sdk.NewTransientStoreKey("transient_test")) + ctx := testCtx.Ctx.WithBlockHeader(tmproto.Header{Time: tmtime.Now()}) + encCfg := moduletestutil.MakeTestEncodingConfig() - addrDels := simtestutil.AddTestAddrsIncremental(s.bankKeeper, s.stakingKeeper, ctx, 5, s.stakingKeeper.TokensFromConsensusPower(ctx, 200)) + // gomock initializations + ctrl := gomock.NewController(s.T()) + s.stakingKeeper = slashingtestutil.NewMockStakingKeeper(ctrl) - info1 := types.NewValidatorSigningInfo(sdk.ConsAddress(addrDels[0]), int64(4), int64(3), - time.Unix(2, 0), false, int64(10)) - info2 := types.NewValidatorSigningInfo(sdk.ConsAddress(addrDels[1]), int64(5), int64(4), - time.Unix(2, 0), false, int64(10)) - - s.slashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0]), info1) - s.slashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[1]), info2) - - queryHelper := baseapp.NewQueryServerTestHelper(ctx, s.interfaceRegistry) - types.RegisterQueryServer(queryHelper, s.slashingKeeper) - queryClient := types.NewQueryClient(queryHelper) - s.queryClient = queryClient - - s.addrDels = addrDels s.ctx = ctx - s.msgServer = slashingkeeper.NewMsgServerImpl(s.slashingKeeper) -} - -func (s *KeeperTestSuite) TestUnJailNotBonded() { - ctx := s.ctx - - p := s.stakingKeeper.GetParams(ctx) - p.MaxValidators = 5 - s.stakingKeeper.SetParams(ctx, p) - - addrDels := simtestutil.AddTestAddrsIncremental(s.bankKeeper, s.stakingKeeper, ctx, 6, s.stakingKeeper.TokensFromConsensusPower(ctx, 200)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addrDels) - pks := simtestutil.CreateTestPubKeys(6) - tstaking := teststaking.NewHelper(s.T(), ctx, s.stakingKeeper) - - // create max (5) validators all with the same power - for i := uint32(0); i < p.MaxValidators; i++ { - addr, val := valAddrs[i], pks[i] - tstaking.CreateValidatorWithValPower(addr, val, 100, true) - } - - staking.EndBlocker(ctx, s.stakingKeeper) - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // create a 6th validator with less power than the cliff validator (won't be bonded) - addr, val := valAddrs[5], pks[5] - amt := s.stakingKeeper.TokensFromConsensusPower(ctx, 50) - msg := tstaking.CreateValidatorMsg(addr, val, amt) - msg.MinSelfDelegation = amt - res, err := tstaking.CreateValidatorWithMsg(sdk.WrapSDKContext(ctx), msg) - s.Require().NoError(err) - s.Require().NotNil(res) - - staking.EndBlocker(ctx, s.stakingKeeper) - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - tstaking.CheckValidator(addr, stakingtypes.Unbonded, false) - - // unbond below minimum self-delegation - s.Require().Equal(p.BondDenom, tstaking.Denom) - tstaking.Undelegate(sdk.AccAddress(addr), addr, s.stakingKeeper.TokensFromConsensusPower(ctx, 1), true) - - staking.EndBlocker(ctx, s.stakingKeeper) - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // verify that validator is jailed - tstaking.CheckValidator(addr, -1, true) - - // verify we cannot unjail (yet) - s.Require().Error(s.slashingKeeper.Unjail(ctx, addr)) - - staking.EndBlocker(ctx, s.stakingKeeper) - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - // bond to meet minimum self-delegation - tstaking.DelegateWithPower(sdk.AccAddress(addr), addr, 1) - - staking.EndBlocker(ctx, s.stakingKeeper) - ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - - // verify we can immediately unjail - s.Require().NoError(s.slashingKeeper.Unjail(ctx, addr)) - - tstaking.CheckValidator(addr, -1, false) -} - -// Test a new validator entering the validator set -// Ensure that SigningInfo.StartHeight is set correctly -// and that they are not immediately jailed -func (s *KeeperTestSuite) TestHandleNewValidator() { - ctx := s.ctx - - addrDels := simtestutil.AddTestAddrsIncremental(s.bankKeeper, s.stakingKeeper, ctx, 1, s.stakingKeeper.TokensFromConsensusPower(ctx, 0)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addrDels) - pks := simtestutil.CreateTestPubKeys(1) - addr, val := valAddrs[0], pks[0] - tstaking := teststaking.NewHelper(s.T(), ctx, s.stakingKeeper) - ctx = ctx.WithBlockHeight(s.slashingKeeper.SignedBlocksWindow(ctx) + 1) - - // Validator created - amt := tstaking.CreateValidatorWithValPower(addr, val, 100, true) - - staking.EndBlocker(ctx, s.stakingKeeper) - s.Require().Equal( - s.bankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.NewCoins(sdk.NewCoin(s.stakingKeeper.GetParams(ctx).BondDenom, InitTokens.Sub(amt))), + s.slashingKeeper = slashingkeeper.NewKeeper( + encCfg.Codec, + encCfg.Amino, + key, + s.stakingKeeper, + sdk.AccAddress(crypto.AddressHash([]byte(govtypes.ModuleName))).String(), ) - s.Require().Equal(amt, s.stakingKeeper.Validator(ctx, addr).GetBondedTokens()) - - // Now a validator, for two blocks - s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), 100, true) - ctx = ctx.WithBlockHeight(s.slashingKeeper.SignedBlocksWindow(ctx) + 2) - s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), 100, false) - - info, found := s.slashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - s.Require().True(found) - s.Require().Equal(s.slashingKeeper.SignedBlocksWindow(ctx)+1, info.StartHeight) - s.Require().Equal(int64(2), info.IndexOffset) - s.Require().Equal(int64(1), info.MissedBlocksCounter) - s.Require().Equal(time.Unix(0, 0).UTC(), info.JailedUntil) - - // validator should be bonded still, should not have been jailed or slashed - validator, _ := s.stakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - s.Require().Equal(stakingtypes.Bonded, validator.GetStatus()) - bondPool := s.stakingKeeper.GetBondedPool(ctx) - expTokens := s.stakingKeeper.TokensFromConsensusPower(ctx, 100) - // adding genesis validator tokens - expTokens = expTokens.Add(s.stakingKeeper.TokensFromConsensusPower(ctx, 1)) - s.Require().True(expTokens.Equal(s.bankKeeper.GetBalance(ctx, bondPool.GetAddress(), s.stakingKeeper.BondDenom(ctx)).Amount)) -} - -// Test a jailed validator being "down" twice -// Ensure that they're only slashed once -func (s *KeeperTestSuite) TestHandleAlreadyJailed() { - // initial setup - - ctx := s.ctx - - addrDels := simtestutil.AddTestAddrsIncremental(s.bankKeeper, s.stakingKeeper, ctx, 1, s.stakingKeeper.TokensFromConsensusPower(ctx, 200)) - valAddrs := simtestutil.ConvertAddrsToValAddrs(addrDels) - pks := simtestutil.CreateTestPubKeys(1) - addr, val := valAddrs[0], pks[0] - power := int64(100) - tstaking := teststaking.NewHelper(s.T(), ctx, s.stakingKeeper) - - amt := tstaking.CreateValidatorWithValPower(addr, val, power, true) - - staking.EndBlocker(ctx, s.stakingKeeper) - - // 1000 first blocks OK - height := int64(0) - for ; height < s.slashingKeeper.SignedBlocksWindow(ctx); height++ { - ctx = ctx.WithBlockHeight(height) - s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, true) - } - - // 501 blocks missed - for ; height < s.slashingKeeper.SignedBlocksWindow(ctx)+(s.slashingKeeper.SignedBlocksWindow(ctx)-s.slashingKeeper.MinSignedPerWindow(ctx))+1; height++ { - ctx = ctx.WithBlockHeight(height) - s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - - // end block - staking.EndBlocker(ctx, s.stakingKeeper) - - // validator should have been jailed and slashed - validator, _ := s.stakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - s.Require().Equal(stakingtypes.Unbonding, validator.GetStatus()) - - // validator should have been slashed - resultingTokens := amt.Sub(s.stakingKeeper.TokensFromConsensusPower(ctx, 1)) - s.Require().Equal(resultingTokens, validator.GetTokens()) - - // another block missed - ctx = ctx.WithBlockHeight(height) - s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) - - // validator should not have been slashed twice - validator, _ = s.stakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - s.Require().Equal(resultingTokens, validator.GetTokens()) -} - -// Test a validator dipping in and out of the validator set -// Ensure that missed blocks are tracked correctly and that -// the start height of the signing info is reset correctly -func (s *KeeperTestSuite) TestValidatorDippingInAndOut() { - // initial setup - // TestParams set the SignedBlocksWindow to 1000 and MaxMissedBlocksPerWindow to 500 - - ctx := s.ctx + // set test params s.slashingKeeper.SetParams(ctx, testslashing.TestParams()) - params := s.stakingKeeper.GetParams(ctx) - params.MaxValidators = 1 - s.stakingKeeper.SetParams(ctx, params) - power := int64(100) + slashingtypes.RegisterInterfaces(encCfg.InterfaceRegistry) + queryHelper := baseapp.NewQueryServerTestHelper(ctx, encCfg.InterfaceRegistry) + slashingtypes.RegisterQueryServer(queryHelper, s.slashingKeeper) - pks := simtestutil.CreateTestPubKeys(3) - simtestutil.AddTestAddrsFromPubKeys(s.bankKeeper, s.stakingKeeper, ctx, pks, s.stakingKeeper.TokensFromConsensusPower(ctx, 200)) - - addr, val := pks[0].Address(), pks[0] - consAddr := sdk.ConsAddress(addr) - tstaking := teststaking.NewHelper(s.T(), ctx, s.stakingKeeper) - valAddr := sdk.ValAddress(addr) - - tstaking.CreateValidatorWithValPower(valAddr, val, power, true) - validatorUpdates := staking.EndBlocker(ctx, s.stakingKeeper) - s.Require().Equal(2, len(validatorUpdates)) - tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false) - - // 100 first blocks OK - height := int64(0) - for ; height < int64(100); height++ { - ctx = ctx.WithBlockHeight(height) - s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, true) - } - - // kick first validator out of validator set - tstaking.CreateValidatorWithValPower(sdk.ValAddress(pks[1].Address()), pks[1], power+1, true) - validatorUpdates = staking.EndBlocker(ctx, s.stakingKeeper) - s.Require().Equal(2, len(validatorUpdates)) - tstaking.CheckValidator(sdk.ValAddress(pks[1].Address()), stakingtypes.Bonded, false) - tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, false) - - // 600 more blocks happened - height = height + 600 - ctx = ctx.WithBlockHeight(height) - - // validator added back in - tstaking.DelegateWithPower(sdk.AccAddress(pks[2].Address()), valAddr, 50) - - validatorUpdates = staking.EndBlocker(ctx, s.stakingKeeper) - s.Require().Equal(2, len(validatorUpdates)) - tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false) - newPower := power + 50 - - // validator misses a block - s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) - height++ - - // shouldn't be jailed/kicked yet - tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false) - - // validator misses an additional 500 more blocks, after the cooling off period of SignedBlockWindow (here 1000 blocks). - latest := s.slashingKeeper.SignedBlocksWindow(ctx) + height - for ; height < latest+s.slashingKeeper.MinSignedPerWindow(ctx); height++ { - ctx = ctx.WithBlockHeight(height) - s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) - } - - // should now be jailed & kicked - staking.EndBlocker(ctx, s.stakingKeeper) - tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, true) - - // check all the signing information - signInfo, found := s.slashingKeeper.GetValidatorSigningInfo(ctx, consAddr) - s.Require().True(found) - s.Require().Equal(int64(700), signInfo.StartHeight) - s.Require().Equal(int64(499), signInfo.MissedBlocksCounter) - s.Require().Equal(int64(499), signInfo.IndexOffset) - - // some blocks pass - height = int64(5000) - ctx = ctx.WithBlockHeight(height) - - // validator rejoins and starts signing again - s.stakingKeeper.Unjail(ctx, consAddr) - - s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, true) - - // validator should not be kicked since we reset counter/array when it was jailed - staking.EndBlocker(ctx, s.stakingKeeper) - tstaking.CheckValidator(valAddr, stakingtypes.Bonded, false) + s.queryClient = slashingtypes.NewQueryClient(queryHelper) + s.msgServer = slashingkeeper.NewMsgServerImpl(s.slashingKeeper) +} - // check start height is correctly set - signInfo, found = s.slashingKeeper.GetValidatorSigningInfo(ctx, consAddr) - s.Require().True(found) - s.Require().Equal(height, signInfo.StartHeight) +func (s *KeeperTestSuite) TestPubkey() { + ctx, keeper := s.ctx, s.slashingKeeper + require := s.Require() - // validator misses 501 blocks after SignedBlockWindow period (1000 blocks) - latest = s.slashingKeeper.SignedBlocksWindow(ctx) + height - for ; height < latest+s.slashingKeeper.MinSignedPerWindow(ctx); height++ { - ctx = ctx.WithBlockHeight(height) - s.slashingKeeper.HandleValidatorSignature(ctx, val.Address(), newPower, false) - } + _, pubKey, addr := testdata.KeyTestPubAddr() + require.NoError(keeper.AddPubkey(ctx, pubKey)) - // validator should now be jailed & kicked - staking.EndBlocker(ctx, s.stakingKeeper) - tstaking.CheckValidator(valAddr, stakingtypes.Unbonding, true) + expectedPubKey, err := keeper.GetPubkey(ctx, addr.Bytes()) + require.NoError(err) + require.Equal(pubKey, expectedPubKey) } func TestKeeperTestSuite(t *testing.T) { diff --git a/x/slashing/keeper/msg_server_test.go b/x/slashing/keeper/msg_server_test.go index 926bd8c3832f..025504b922f8 100644 --- a/x/slashing/keeper/msg_server_test.go +++ b/x/slashing/keeper/msg_server_test.go @@ -3,32 +3,36 @@ package keeper_test import ( "time" + "github.com/golang/mock/gomock" + sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" ) func (s *KeeperTestSuite) TestUpdateParams() { + require := s.Require() + minSignedPerWindow, err := sdk.NewDecFromStr("0.60") - s.Require().NoError(err) + require.NoError(err) slashFractionDoubleSign, err := sdk.NewDecFromStr("0.022") - s.Require().NoError(err) + require.NoError(err) slashFractionDowntime, err := sdk.NewDecFromStr("0.0089") - s.Require().NoError(err) + require.NoError(err) invalidVal, err := sdk.NewDecFromStr("-1") - s.Require().NoError(err) + require.NoError(err) testCases := []struct { name string - request *types.MsgUpdateParams + request *slashingtypes.MsgUpdateParams expectErr bool expErrMsg string }{ { name: "set invalid authority", - request: &types.MsgUpdateParams{ + request: &slashingtypes.MsgUpdateParams{ Authority: "foo", }, expectErr: true, @@ -36,9 +40,9 @@ func (s *KeeperTestSuite) TestUpdateParams() { }, { name: "set invalid signed blocks window", - request: &types.MsgUpdateParams{ + request: &slashingtypes.MsgUpdateParams{ Authority: s.slashingKeeper.GetAuthority(), - Params: types.Params{ + Params: slashingtypes.Params{ SignedBlocksWindow: 0, MinSignedPerWindow: minSignedPerWindow, DowntimeJailDuration: time.Duration(34800000000000), @@ -51,9 +55,9 @@ func (s *KeeperTestSuite) TestUpdateParams() { }, { name: "set invalid min signed per window", - request: &types.MsgUpdateParams{ + request: &slashingtypes.MsgUpdateParams{ Authority: s.slashingKeeper.GetAuthority(), - Params: types.Params{ + Params: slashingtypes.Params{ SignedBlocksWindow: int64(750), MinSignedPerWindow: invalidVal, DowntimeJailDuration: time.Duration(34800000000000), @@ -66,9 +70,9 @@ func (s *KeeperTestSuite) TestUpdateParams() { }, { name: "set invalid downtime jail duration", - request: &types.MsgUpdateParams{ + request: &slashingtypes.MsgUpdateParams{ Authority: s.slashingKeeper.GetAuthority(), - Params: types.Params{ + Params: slashingtypes.Params{ SignedBlocksWindow: int64(750), MinSignedPerWindow: minSignedPerWindow, DowntimeJailDuration: time.Duration(0), @@ -81,9 +85,9 @@ func (s *KeeperTestSuite) TestUpdateParams() { }, { name: "set invalid slash fraction double sign", - request: &types.MsgUpdateParams{ + request: &slashingtypes.MsgUpdateParams{ Authority: s.slashingKeeper.GetAuthority(), - Params: types.Params{ + Params: slashingtypes.Params{ SignedBlocksWindow: int64(750), MinSignedPerWindow: minSignedPerWindow, DowntimeJailDuration: time.Duration(10), @@ -96,9 +100,9 @@ func (s *KeeperTestSuite) TestUpdateParams() { }, { name: "set invalid slash fraction downtime", - request: &types.MsgUpdateParams{ + request: &slashingtypes.MsgUpdateParams{ Authority: s.slashingKeeper.GetAuthority(), - Params: types.Params{ + Params: slashingtypes.Params{ SignedBlocksWindow: int64(750), MinSignedPerWindow: minSignedPerWindow, DowntimeJailDuration: time.Duration(10), @@ -111,9 +115,9 @@ func (s *KeeperTestSuite) TestUpdateParams() { }, { name: "set full valid params", - request: &types.MsgUpdateParams{ + request: &slashingtypes.MsgUpdateParams{ Authority: s.slashingKeeper.GetAuthority(), - Params: types.Params{ + Params: slashingtypes.Params{ SignedBlocksWindow: int64(750), MinSignedPerWindow: minSignedPerWindow, DowntimeJailDuration: time.Duration(34800000000000), @@ -130,11 +134,23 @@ func (s *KeeperTestSuite) TestUpdateParams() { s.Run(tc.name, func() { _, err := s.msgServer.UpdateParams(s.ctx, tc.request) if tc.expectErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) + require.Error(err) + require.Contains(err.Error(), tc.expErrMsg) } else { - s.Require().NoError(err) + require.NoError(err) } }) } } + +func (s *KeeperTestSuite) TestUnjail() { + addr := sdk.AccAddress([]byte("val1_______________")) + request := &slashingtypes.MsgUnjail{ + ValidatorAddr: sdk.ValAddress(addr).String(), + } + + s.stakingKeeper.EXPECT().Validator(gomock.Any(), gomock.Any()).Return(nil) + _, err := s.msgServer.Unjail(s.ctx, request) + s.Require().Error(err) + s.Require().Equal(err, slashingtypes.ErrNoValidatorForAddress) +} diff --git a/x/slashing/keeper/params_test.go b/x/slashing/keeper/params_test.go index 94faa023e0b1..bcf96ef136c0 100644 --- a/x/slashing/keeper/params_test.go +++ b/x/slashing/keeper/params_test.go @@ -8,17 +8,20 @@ import ( ) func (s *KeeperTestSuite) TestParams() { + ctx, keeper := s.ctx, s.slashingKeeper + require := s.Require() + minSignedPerWindow, err := sdk.NewDecFromStr("0.60") - s.Require().NoError(err) + require.NoError(err) slashFractionDoubleSign, err := sdk.NewDecFromStr("0.022") - s.Require().NoError(err) + require.NoError(err) slashFractionDowntime, err := sdk.NewDecFromStr("0.0089") - s.Require().NoError(err) + require.NoError(err) invalidVal, err := sdk.NewDecFromStr("-1") - s.Require().NoError(err) + require.NoError(err) testCases := []struct { name string @@ -101,19 +104,24 @@ func (s *KeeperTestSuite) TestParams() { for _, tc := range testCases { tc := tc s.Run(tc.name, func() { - expected := s.slashingKeeper.GetParams(s.ctx) - err := s.slashingKeeper.SetParams(s.ctx, tc.input) + expected := keeper.GetParams(ctx) + err := keeper.SetParams(ctx, tc.input) if tc.expectErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) + require.Error(err) + require.Contains(err.Error(), tc.expErrMsg) } else { expected = tc.input - s.Require().NoError(err) + require.NoError(err) } - params := s.slashingKeeper.GetParams(s.ctx) - s.Require().Equal(expected, params) + params := keeper.GetParams(ctx) + require.Equal(params, expected) + require.Equal(keeper.SignedBlocksWindow(ctx), expected.SignedBlocksWindow) + require.Equal(keeper.MinSignedPerWindow(ctx), expected.MinSignedPerWindow.MulInt64(expected.SignedBlocksWindow).RoundInt64()) + require.Equal(keeper.DowntimeJailDuration(ctx), expected.DowntimeJailDuration) + require.Equal(keeper.SlashFractionDoubleSign(ctx), expected.SlashFractionDoubleSign) + require.Equal(keeper.SlashFractionDowntime(ctx), expected.SlashFractionDowntime) }) } } diff --git a/x/slashing/keeper/signing_info_test.go b/x/slashing/keeper/signing_info_test.go index 67c34467ec11..cfef7104b825 100644 --- a/x/slashing/keeper/signing_info_test.go +++ b/x/slashing/keeper/signing_info_test.go @@ -3,86 +3,91 @@ package keeper_test import ( "time" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing/types" + + "github.com/cosmos/cosmos-sdk/x/slashing/testslashing" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" ) -func (suite *KeeperTestSuite) TestGetSetValidatorSigningInfo() { - ctx := suite.ctx +func (s *KeeperTestSuite) TestValidatorSigningInfo() { + ctx, keeper := s.ctx, s.slashingKeeper + require := s.Require() - addrDels := suite.addrDels - info, found := suite.slashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[2])) - suite.Require().False(found) - newInfo := types.NewValidatorSigningInfo( - sdk.ConsAddress(addrDels[2]), - int64(4), + signingInfo := slashingtypes.NewValidatorSigningInfo( + consAddr, + ctx.BlockHeight(), int64(3), time.Unix(2, 0), false, int64(10), ) - suite.slashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[2]), newInfo) - info, found = suite.slashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[2])) - suite.Require().True(found) - suite.Require().Equal(info.StartHeight, int64(4)) - suite.Require().Equal(info.IndexOffset, int64(3)) - suite.Require().Equal(info.JailedUntil, time.Unix(2, 0).UTC()) - suite.Require().Equal(info.MissedBlocksCounter, int64(10)) -} -func (suite *KeeperTestSuite) TestGetSetValidatorMissedBlockBitArray() { - ctx := suite.ctx - addrDels := simtestutil.AddTestAddrsIncremental(suite.bankKeeper, suite.stakingKeeper, ctx, 1, suite.stakingKeeper.TokensFromConsensusPower(ctx, 200)) + // set the validator signing information + keeper.SetValidatorSigningInfo(ctx, consAddr, signingInfo) - missed := suite.slashingKeeper.GetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(addrDels[0]), 0) - suite.Require().False(missed) // treat empty key as not missed - suite.slashingKeeper.SetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(addrDels[0]), 0, true) - missed = suite.slashingKeeper.GetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(addrDels[0]), 0) - suite.Require().True(missed) // now should be missed -} + require.True(keeper.HasValidatorSigningInfo(ctx, consAddr)) + info, found := keeper.GetValidatorSigningInfo(ctx, consAddr) + require.True(found) + require.Equal(info.StartHeight, ctx.BlockHeight()) + require.Equal(info.IndexOffset, int64(3)) + require.Equal(info.JailedUntil, time.Unix(2, 0).UTC()) + require.Equal(info.MissedBlocksCounter, int64(10)) -func (suite *KeeperTestSuite) TestTombstoned() { - ctx := suite.ctx - addrDels := suite.addrDels + var signingInfos []slashingtypes.ValidatorSigningInfo - suite.Require().Panics(func() { suite.slashingKeeper.Tombstone(ctx, sdk.ConsAddress(addrDels[4])) }) - suite.Require().False(suite.slashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(addrDels[4]))) + keeper.IterateValidatorSigningInfos(ctx, func(consAddr sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) { + signingInfos = append(signingInfos, info) + return false + }) - newInfo := types.NewValidatorSigningInfo( - sdk.ConsAddress(addrDels[4]), - int64(4), - int64(3), - time.Unix(2, 0), - false, - int64(10), - ) - suite.slashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[4]), newInfo) + require.Equal(signingInfos[0].Address, signingInfo.Address) + + // test Tombstone + keeper.Tombstone(ctx, consAddr) + require.True(keeper.IsTombstoned(ctx, consAddr)) - suite.Require().False(suite.slashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(addrDels[4]))) - suite.slashingKeeper.Tombstone(ctx, sdk.ConsAddress(addrDels[4])) - suite.Require().True(suite.slashingKeeper.IsTombstoned(ctx, sdk.ConsAddress(addrDels[4]))) - suite.Require().Panics(func() { suite.slashingKeeper.Tombstone(ctx, sdk.ConsAddress(addrDels[4])) }) + // test JailUntil + jailTime := time.Now().Add(time.Hour).UTC() + keeper.JailUntil(ctx, consAddr, jailTime) + sInfo, _ := keeper.GetValidatorSigningInfo(ctx, consAddr) + require.Equal(sInfo.JailedUntil, jailTime) } -func (suite *KeeperTestSuite) TestJailUntil() { - ctx := suite.ctx - addrDels := suite.addrDels +func (s *KeeperTestSuite) TestValidatorMissedBlockBitArray() { + ctx, keeper := s.ctx, s.slashingKeeper + require := s.Require() - suite.Require().Panics(func() { suite.slashingKeeper.JailUntil(ctx, sdk.ConsAddress(addrDels[3]), time.Now()) }) + params := testslashing.TestParams() + params.SignedBlocksWindow = 100 + require.NoError(keeper.SetParams(ctx, params)) - newInfo := types.NewValidatorSigningInfo( - sdk.ConsAddress(addrDels[3]), - int64(4), - int64(3), - time.Unix(2, 0), - false, - int64(10), - ) - suite.slashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[3]), newInfo) - suite.slashingKeeper.JailUntil(ctx, sdk.ConsAddress(addrDels[3]), time.Unix(253402300799, 0).UTC()) + testCases := []struct { + name string + index int64 + missed bool + }{ + { + name: "missed block with false", + index: 50, + missed: false, + }, + { + name: "missed block with true", + index: 51, + missed: true, + }, + } + for ind, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + keeper.SetValidatorMissedBlockBitArray(ctx, consAddr, tc.index, tc.missed) + missed := keeper.GetValidatorMissedBlockBitArray(ctx, consAddr, tc.index) - info, ok := suite.slashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[3])) - suite.Require().True(ok) - suite.Require().Equal(time.Unix(253402300799, 0).UTC(), info.JailedUntil) + require.Equal(missed, tc.missed) + missedBlocks := keeper.GetValidatorMissedBlocks(ctx, consAddr) + require.Equal(len(missedBlocks), ind+1) + require.Equal(missedBlocks[ind].Index, tc.index) + require.Equal(missedBlocks[ind].Missed, tc.missed) + }) + } } diff --git a/x/slashing/testutil/expected_keepers_mocks.go b/x/slashing/testutil/expected_keepers_mocks.go new file mode 100644 index 000000000000..05eec6974153 --- /dev/null +++ b/x/slashing/testutil/expected_keepers_mocks.go @@ -0,0 +1,425 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: x/slashing/types/expected_keepers.go + +// Package testutil is a generated GoMock package. +package testutil + +import ( + reflect "reflect" + + math "cosmossdk.io/math" + types "github.com/cosmos/cosmos-sdk/types" + types0 "github.com/cosmos/cosmos-sdk/x/auth/types" + types1 "github.com/cosmos/cosmos-sdk/x/params/types" + types2 "github.com/cosmos/cosmos-sdk/x/staking/types" + gomock "github.com/golang/mock/gomock" +) + +// MockAccountKeeper is a mock of AccountKeeper interface. +type MockAccountKeeper struct { + ctrl *gomock.Controller + recorder *MockAccountKeeperMockRecorder +} + +// MockAccountKeeperMockRecorder is the mock recorder for MockAccountKeeper. +type MockAccountKeeperMockRecorder struct { + mock *MockAccountKeeper +} + +// NewMockAccountKeeper creates a new mock instance. +func NewMockAccountKeeper(ctrl *gomock.Controller) *MockAccountKeeper { + mock := &MockAccountKeeper{ctrl: ctrl} + mock.recorder = &MockAccountKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAccountKeeper) EXPECT() *MockAccountKeeperMockRecorder { + return m.recorder +} + +// GetAccount mocks base method. +func (m *MockAccountKeeper) GetAccount(ctx types.Context, addr types.AccAddress) types0.AccountI { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAccount", ctx, addr) + ret0, _ := ret[0].(types0.AccountI) + return ret0 +} + +// GetAccount indicates an expected call of GetAccount. +func (mr *MockAccountKeeperMockRecorder) GetAccount(ctx, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetAccount), ctx, addr) +} + +// IterateAccounts mocks base method. +func (m *MockAccountKeeper) IterateAccounts(ctx types.Context, process func(types0.AccountI) bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "IterateAccounts", ctx, process) +} + +// IterateAccounts indicates an expected call of IterateAccounts. +func (mr *MockAccountKeeperMockRecorder) IterateAccounts(ctx, process interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateAccounts", reflect.TypeOf((*MockAccountKeeper)(nil).IterateAccounts), ctx, process) +} + +// MockBankKeeper is a mock of BankKeeper interface. +type MockBankKeeper struct { + ctrl *gomock.Controller + recorder *MockBankKeeperMockRecorder +} + +// MockBankKeeperMockRecorder is the mock recorder for MockBankKeeper. +type MockBankKeeperMockRecorder struct { + mock *MockBankKeeper +} + +// NewMockBankKeeper creates a new mock instance. +func NewMockBankKeeper(ctrl *gomock.Controller) *MockBankKeeper { + mock := &MockBankKeeper{ctrl: ctrl} + mock.recorder = &MockBankKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBankKeeper) EXPECT() *MockBankKeeperMockRecorder { + return m.recorder +} + +// GetAllBalances mocks base method. +func (m *MockBankKeeper) GetAllBalances(ctx types.Context, addr types.AccAddress) types.Coins { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllBalances", ctx, addr) + ret0, _ := ret[0].(types.Coins) + return ret0 +} + +// GetAllBalances indicates an expected call of GetAllBalances. +func (mr *MockBankKeeperMockRecorder) GetAllBalances(ctx, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllBalances", reflect.TypeOf((*MockBankKeeper)(nil).GetAllBalances), ctx, addr) +} + +// GetBalance mocks base method. +func (m *MockBankKeeper) GetBalance(ctx types.Context, addr types.AccAddress, denom string) types.Coin { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBalance", ctx, addr, denom) + ret0, _ := ret[0].(types.Coin) + return ret0 +} + +// GetBalance indicates an expected call of GetBalance. +func (mr *MockBankKeeperMockRecorder) GetBalance(ctx, addr, denom interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalance", reflect.TypeOf((*MockBankKeeper)(nil).GetBalance), ctx, addr, denom) +} + +// LockedCoins mocks base method. +func (m *MockBankKeeper) LockedCoins(ctx types.Context, addr types.AccAddress) types.Coins { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LockedCoins", ctx, addr) + ret0, _ := ret[0].(types.Coins) + return ret0 +} + +// LockedCoins indicates an expected call of LockedCoins. +func (mr *MockBankKeeperMockRecorder) LockedCoins(ctx, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LockedCoins", reflect.TypeOf((*MockBankKeeper)(nil).LockedCoins), ctx, addr) +} + +// SpendableCoins mocks base method. +func (m *MockBankKeeper) SpendableCoins(ctx types.Context, addr types.AccAddress) types.Coins { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SpendableCoins", ctx, addr) + ret0, _ := ret[0].(types.Coins) + return ret0 +} + +// SpendableCoins indicates an expected call of SpendableCoins. +func (mr *MockBankKeeperMockRecorder) SpendableCoins(ctx, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpendableCoins", reflect.TypeOf((*MockBankKeeper)(nil).SpendableCoins), ctx, addr) +} + +// MockParamSubspace is a mock of ParamSubspace interface. +type MockParamSubspace struct { + ctrl *gomock.Controller + recorder *MockParamSubspaceMockRecorder +} + +// MockParamSubspaceMockRecorder is the mock recorder for MockParamSubspace. +type MockParamSubspaceMockRecorder struct { + mock *MockParamSubspace +} + +// NewMockParamSubspace creates a new mock instance. +func NewMockParamSubspace(ctrl *gomock.Controller) *MockParamSubspace { + mock := &MockParamSubspace{ctrl: ctrl} + mock.recorder = &MockParamSubspaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockParamSubspace) EXPECT() *MockParamSubspaceMockRecorder { + return m.recorder +} + +// Get mocks base method. +func (m *MockParamSubspace) Get(ctx types.Context, key []byte, ptr interface{}) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Get", ctx, key, ptr) +} + +// Get indicates an expected call of Get. +func (mr *MockParamSubspaceMockRecorder) Get(ctx, key, ptr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockParamSubspace)(nil).Get), ctx, key, ptr) +} + +// GetParamSet mocks base method. +func (m *MockParamSubspace) GetParamSet(ctx types.Context, ps types1.ParamSet) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "GetParamSet", ctx, ps) +} + +// GetParamSet indicates an expected call of GetParamSet. +func (mr *MockParamSubspaceMockRecorder) GetParamSet(ctx, ps interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParamSet", reflect.TypeOf((*MockParamSubspace)(nil).GetParamSet), ctx, ps) +} + +// HasKeyTable mocks base method. +func (m *MockParamSubspace) HasKeyTable() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasKeyTable") + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasKeyTable indicates an expected call of HasKeyTable. +func (mr *MockParamSubspaceMockRecorder) HasKeyTable() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasKeyTable", reflect.TypeOf((*MockParamSubspace)(nil).HasKeyTable)) +} + +// SetParamSet mocks base method. +func (m *MockParamSubspace) SetParamSet(ctx types.Context, ps types1.ParamSet) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetParamSet", ctx, ps) +} + +// SetParamSet indicates an expected call of SetParamSet. +func (mr *MockParamSubspaceMockRecorder) SetParamSet(ctx, ps interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetParamSet", reflect.TypeOf((*MockParamSubspace)(nil).SetParamSet), ctx, ps) +} + +// WithKeyTable mocks base method. +func (m *MockParamSubspace) WithKeyTable(table types1.KeyTable) types1.Subspace { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WithKeyTable", table) + ret0, _ := ret[0].(types1.Subspace) + return ret0 +} + +// WithKeyTable indicates an expected call of WithKeyTable. +func (mr *MockParamSubspaceMockRecorder) WithKeyTable(table interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WithKeyTable", reflect.TypeOf((*MockParamSubspace)(nil).WithKeyTable), table) +} + +// MockStakingKeeper is a mock of StakingKeeper interface. +type MockStakingKeeper struct { + ctrl *gomock.Controller + recorder *MockStakingKeeperMockRecorder +} + +// MockStakingKeeperMockRecorder is the mock recorder for MockStakingKeeper. +type MockStakingKeeperMockRecorder struct { + mock *MockStakingKeeper +} + +// NewMockStakingKeeper creates a new mock instance. +func NewMockStakingKeeper(ctrl *gomock.Controller) *MockStakingKeeper { + mock := &MockStakingKeeper{ctrl: ctrl} + mock.recorder = &MockStakingKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockStakingKeeper) EXPECT() *MockStakingKeeperMockRecorder { + return m.recorder +} + +// Delegation mocks base method. +func (m *MockStakingKeeper) Delegation(arg0 types.Context, arg1 types.AccAddress, arg2 types.ValAddress) types2.DelegationI { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delegation", arg0, arg1, arg2) + ret0, _ := ret[0].(types2.DelegationI) + return ret0 +} + +// Delegation indicates an expected call of Delegation. +func (mr *MockStakingKeeperMockRecorder) Delegation(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delegation", reflect.TypeOf((*MockStakingKeeper)(nil).Delegation), arg0, arg1, arg2) +} + +// IterateValidators mocks base method. +func (m *MockStakingKeeper) IterateValidators(arg0 types.Context, arg1 func(int64, types2.ValidatorI) bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "IterateValidators", arg0, arg1) +} + +// IterateValidators indicates an expected call of IterateValidators. +func (mr *MockStakingKeeperMockRecorder) IterateValidators(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateValidators", reflect.TypeOf((*MockStakingKeeper)(nil).IterateValidators), arg0, arg1) +} + +// Jail mocks base method. +func (m *MockStakingKeeper) Jail(arg0 types.Context, arg1 types.ConsAddress) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Jail", arg0, arg1) +} + +// Jail indicates an expected call of Jail. +func (mr *MockStakingKeeperMockRecorder) Jail(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Jail", reflect.TypeOf((*MockStakingKeeper)(nil).Jail), arg0, arg1) +} + +// MaxValidators mocks base method. +func (m *MockStakingKeeper) MaxValidators(arg0 types.Context) uint32 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MaxValidators", arg0) + ret0, _ := ret[0].(uint32) + return ret0 +} + +// MaxValidators indicates an expected call of MaxValidators. +func (mr *MockStakingKeeperMockRecorder) MaxValidators(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MaxValidators", reflect.TypeOf((*MockStakingKeeper)(nil).MaxValidators), arg0) +} + +// Slash mocks base method. +func (m *MockStakingKeeper) Slash(arg0 types.Context, arg1 types.ConsAddress, arg2, arg3 int64, arg4 types.Dec) math.Int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Slash", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(math.Int) + return ret0 +} + +// Slash indicates an expected call of Slash. +func (mr *MockStakingKeeperMockRecorder) Slash(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Slash", reflect.TypeOf((*MockStakingKeeper)(nil).Slash), arg0, arg1, arg2, arg3, arg4) +} + +// Unjail mocks base method. +func (m *MockStakingKeeper) Unjail(arg0 types.Context, arg1 types.ConsAddress) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Unjail", arg0, arg1) +} + +// Unjail indicates an expected call of Unjail. +func (mr *MockStakingKeeperMockRecorder) Unjail(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unjail", reflect.TypeOf((*MockStakingKeeper)(nil).Unjail), arg0, arg1) +} + +// Validator mocks base method. +func (m *MockStakingKeeper) Validator(arg0 types.Context, arg1 types.ValAddress) types2.ValidatorI { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Validator", arg0, arg1) + ret0, _ := ret[0].(types2.ValidatorI) + return ret0 +} + +// Validator indicates an expected call of Validator. +func (mr *MockStakingKeeperMockRecorder) Validator(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validator", reflect.TypeOf((*MockStakingKeeper)(nil).Validator), arg0, arg1) +} + +// ValidatorByConsAddr mocks base method. +func (m *MockStakingKeeper) ValidatorByConsAddr(arg0 types.Context, arg1 types.ConsAddress) types2.ValidatorI { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidatorByConsAddr", arg0, arg1) + ret0, _ := ret[0].(types2.ValidatorI) + return ret0 +} + +// ValidatorByConsAddr indicates an expected call of ValidatorByConsAddr. +func (mr *MockStakingKeeperMockRecorder) ValidatorByConsAddr(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatorByConsAddr", reflect.TypeOf((*MockStakingKeeper)(nil).ValidatorByConsAddr), arg0, arg1) +} + +// MockStakingHooks is a mock of StakingHooks interface. +type MockStakingHooks struct { + ctrl *gomock.Controller + recorder *MockStakingHooksMockRecorder +} + +// MockStakingHooksMockRecorder is the mock recorder for MockStakingHooks. +type MockStakingHooksMockRecorder struct { + mock *MockStakingHooks +} + +// NewMockStakingHooks creates a new mock instance. +func NewMockStakingHooks(ctrl *gomock.Controller) *MockStakingHooks { + mock := &MockStakingHooks{ctrl: ctrl} + mock.recorder = &MockStakingHooksMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockStakingHooks) EXPECT() *MockStakingHooksMockRecorder { + return m.recorder +} + +// AfterValidatorBonded mocks base method. +func (m *MockStakingHooks) AfterValidatorBonded(ctx types.Context, consAddr types.ConsAddress, valAddr types.ValAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AfterValidatorBonded", ctx, consAddr, valAddr) + ret0, _ := ret[0].(error) + return ret0 +} + +// AfterValidatorBonded indicates an expected call of AfterValidatorBonded. +func (mr *MockStakingHooksMockRecorder) AfterValidatorBonded(ctx, consAddr, valAddr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorBonded", reflect.TypeOf((*MockStakingHooks)(nil).AfterValidatorBonded), ctx, consAddr, valAddr) +} + +// AfterValidatorCreated mocks base method. +func (m *MockStakingHooks) AfterValidatorCreated(ctx types.Context, valAddr types.ValAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AfterValidatorCreated", ctx, valAddr) + ret0, _ := ret[0].(error) + return ret0 +} + +// AfterValidatorCreated indicates an expected call of AfterValidatorCreated. +func (mr *MockStakingHooksMockRecorder) AfterValidatorCreated(ctx, valAddr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorCreated", reflect.TypeOf((*MockStakingHooks)(nil).AfterValidatorCreated), ctx, valAddr) +} + +// AfterValidatorRemoved mocks base method. +func (m *MockStakingHooks) AfterValidatorRemoved(ctx types.Context, consAddr types.ConsAddress, valAddr types.ValAddress) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AfterValidatorRemoved", ctx, consAddr, valAddr) + ret0, _ := ret[0].(error) + return ret0 +} + +// AfterValidatorRemoved indicates an expected call of AfterValidatorRemoved. +func (mr *MockStakingHooksMockRecorder) AfterValidatorRemoved(ctx, consAddr, valAddr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterValidatorRemoved", reflect.TypeOf((*MockStakingHooks)(nil).AfterValidatorRemoved), ctx, consAddr, valAddr) +}