diff --git a/CHANGELOG.md b/CHANGELOG.md index b8e3b5b834d0..525ead0c8969 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#9594](https://github.com/cosmos/cosmos-sdk/pull/9594) `types/rest` package moved to `testutil/rest`. * [\#9432](https://github.com/cosmos/cosmos-sdk/pull/9432) `ConsensusParamsKeyTable` moved from `params/keeper` to `params/types` * [\#9576](https://github.com/cosmos/cosmos-sdk/pull/9576) Add debug error message to `sdkerrors.QueryResult` when enabled +* [\#9650](https://github.com/cosmos/cosmos-sdk/pull/9650) Removed deprecated message handler implementation from the SDK modules. ### Client Breaking Changes diff --git a/x/auth/module.go b/x/auth/module.go index c48d723c12b4..dfb125058bd9 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -111,8 +111,10 @@ func (AppModule) Name() string { // RegisterInvariants performs a no-op. func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} -// Route returns the message routing key for the auth module. -func (AppModule) Route() sdk.Route { return sdk.Route{} } +// Deprecated: Route returns the message routing key for the auth module. +func (AppModule) Route() sdk.Route { + return sdk.Route{} +} // QuerierRoute returns the auth module's querier route name. func (AppModule) QuerierRoute() string { diff --git a/x/auth/vesting/handler.go b/x/auth/vesting/handler.go deleted file mode 100644 index 1d32e9969bb5..000000000000 --- a/x/auth/vesting/handler.go +++ /dev/null @@ -1,26 +0,0 @@ -package vesting - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/auth/keeper" - "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" -) - -// NewHandler returns a handler for x/auth message types. -func NewHandler(ak keeper.AccountKeeper, bk types.BankKeeper) sdk.Handler { - msgServer := NewMsgServerImpl(ak, bk) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgCreateVestingAccount: - res, err := msgServer.CreateVestingAccount(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg) - } - } -} diff --git a/x/auth/vesting/handler_test.go b/x/auth/vesting/handler_test.go deleted file mode 100644 index 8af58073e90d..000000000000 --- a/x/auth/vesting/handler_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package vesting_test - -import ( - "testing" - - "github.com/stretchr/testify/suite" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - - "github.com/cosmos/cosmos-sdk/simapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/vesting" - "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" -) - -type HandlerTestSuite struct { - suite.Suite - - handler sdk.Handler - app *simapp.SimApp -} - -func (suite *HandlerTestSuite) SetupTest() { - checkTx := false - app := simapp.Setup(checkTx) - - suite.handler = vesting.NewHandler(app.AccountKeeper, app.BankKeeper) - suite.app = app -} - -func (suite *HandlerTestSuite) TestMsgCreateVestingAccount() { - ctx := suite.app.BaseApp.NewContext(false, tmproto.Header{Height: suite.app.LastBlockHeight() + 1}) - - balances := sdk.NewCoins(sdk.NewInt64Coin("test", 1000)) - addr1 := sdk.AccAddress([]byte("addr1_______________")) - addr2 := sdk.AccAddress([]byte("addr2_______________")) - addr3 := sdk.AccAddress([]byte("addr3_______________")) - - acc1 := suite.app.AccountKeeper.NewAccountWithAddress(ctx, addr1) - suite.app.AccountKeeper.SetAccount(ctx, acc1) - suite.Require().NoError(testutil.FundAccount(suite.app.BankKeeper, ctx, addr1, balances)) - - testCases := []struct { - name string - msg *types.MsgCreateVestingAccount - expectErr bool - }{ - { - name: "create delayed vesting account", - msg: types.NewMsgCreateVestingAccount(addr1, addr2, sdk.NewCoins(sdk.NewInt64Coin("test", 100)), ctx.BlockTime().Unix()+10000, true), - expectErr: false, - }, - { - name: "create continuous vesting account", - msg: types.NewMsgCreateVestingAccount(addr1, addr3, sdk.NewCoins(sdk.NewInt64Coin("test", 100)), ctx.BlockTime().Unix()+10000, false), - expectErr: false, - }, - { - name: "continuous vesting account already exists", - msg: types.NewMsgCreateVestingAccount(addr1, addr3, sdk.NewCoins(sdk.NewInt64Coin("test", 100)), ctx.BlockTime().Unix()+10000, false), - expectErr: true, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - res, err := suite.handler(ctx, tc.msg) - if tc.expectErr { - suite.Require().Error(err) - } else { - suite.Require().NoError(err) - suite.Require().NotNil(res) - - toAddr, err := sdk.AccAddressFromBech32(tc.msg.ToAddress) - suite.Require().NoError(err) - accI := suite.app.AccountKeeper.GetAccount(ctx, toAddr) - suite.Require().NotNil(accI) - - if tc.msg.Delayed { - acc, ok := accI.(*types.DelayedVestingAccount) - suite.Require().True(ok) - suite.Require().Equal(tc.msg.Amount, acc.GetVestingCoins(ctx.BlockTime())) - } else { - acc, ok := accI.(*types.ContinuousVestingAccount) - suite.Require().True(ok) - suite.Require().Equal(tc.msg.Amount, acc.GetVestingCoins(ctx.BlockTime())) - } - } - }) - } -} - -func TestHandlerTestSuite(t *testing.T) { - suite.Run(t, new(HandlerTestSuite)) -} diff --git a/x/auth/vesting/module.go b/x/auth/vesting/module.go index f0594784ca05..272ebf2656bf 100644 --- a/x/auth/vesting/module.go +++ b/x/auth/vesting/module.go @@ -92,9 +92,9 @@ func NewAppModule(ak keeper.AccountKeeper, bk types.BankKeeper) AppModule { // RegisterInvariants performs a no-op; there are no invariants to enforce. func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} -// Route returns the module's message router and handler. +// Deprecated: Route returns the module's message router and handler. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(types.RouterKey, NewHandler(am.accountKeeper, am.bankKeeper)) + return sdk.Route{} } // QuerierRoute returns an empty string as the module contains no query diff --git a/x/authz/module/module.go b/x/authz/module/module.go index 38b4eb535081..b1afdc06e12f 100644 --- a/x/authz/module/module.go +++ b/x/authz/module/module.go @@ -117,9 +117,9 @@ func (AppModule) Name() string { // RegisterInvariants does nothing, there are no invariants to enforce func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} -// Route returns the message routing key for the staking module. +// Deprecated: Route returns the message routing key for the authz module. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(authz.RouterKey, nil) + return sdk.Route{} } func (am AppModule) NewHandler() sdk.Handler { diff --git a/x/bank/handler.go b/x/bank/handler.go deleted file mode 100644 index 0fb0f53a4cd8..000000000000 --- a/x/bank/handler.go +++ /dev/null @@ -1,30 +0,0 @@ -package bank - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/bank/keeper" - "github.com/cosmos/cosmos-sdk/x/bank/types" -) - -// NewHandler returns a handler for "bank" type messages. -func NewHandler(k keeper.Keeper) sdk.Handler { - msgServer := keeper.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgSend: - res, err := msgServer.Send(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgMultiSend: - res, err := msgServer.MultiSend(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized bank message type: %T", msg) - } - } -} diff --git a/x/bank/handler_test.go b/x/bank/handler_test.go deleted file mode 100644 index 5fcdf02f1a93..000000000000 --- a/x/bank/handler_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package bank_test - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - "github.com/cosmos/cosmos-sdk/simapp" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/bank" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - "github.com/cosmos/cosmos-sdk/x/bank/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -func TestInvalidMsg(t *testing.T) { - h := bank.NewHandler(nil) - - res, err := h(sdk.NewContext(nil, tmproto.Header{}, false, nil), testdata.NewTestMsg()) - require.Error(t, err) - require.Nil(t, res) - - _, _, log := sdkerrors.ABCIInfo(err, false) - require.True(t, strings.Contains(log, "unrecognized bank message type")) -} - -// A module account cannot be the recipient of bank sends unless it has been marked as such -func TestSendToModuleAccount(t *testing.T) { - priv1 := secp256k1.GenPrivKey() - addr1 := sdk.AccAddress(priv1.PubKey().Address()) - moduleAccAddr := authtypes.NewModuleAddress(stakingtypes.BondedPoolName) - coins := sdk.Coins{sdk.NewInt64Coin("foocoin", 10)} - - tests := []struct { - name string - expectedError error - msg *types.MsgSend - }{ - { - name: "not allowed module account", - msg: types.NewMsgSend(addr1, moduleAccAddr, coins), - expectedError: sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", moduleAccAddr), - }, - { - name: "allowed module account", - msg: types.NewMsgSend(addr1, authtypes.NewModuleAddress(stakingtypes.ModuleName), coins), - expectedError: nil, - }, - } - - acc1 := &authtypes.BaseAccount{ - Address: addr1.String(), - } - accs := authtypes.GenesisAccounts{acc1} - balances := []types.Balance{ - { - Address: addr1.String(), - Coins: coins, - }, - } - - app := simapp.SetupWithGenesisAccounts(accs, balances...) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - - app.BankKeeper = bankkeeper.NewBaseKeeper( - app.AppCodec(), app.GetKey(types.StoreKey), app.AccountKeeper, app.GetSubspace(types.ModuleName), map[string]bool{ - moduleAccAddr.String(): true, - }, - ) - handler := bank.NewHandler(app.BankKeeper) - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - _, err := handler(ctx, tc.msg) - if tc.expectedError != nil { - require.EqualError(t, err, tc.expectedError.Error()) - } else { - require.NoError(t, err) - } - }) - } -} diff --git a/x/bank/module.go b/x/bank/module.go index 3c8918c5a159..55fda845c317 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -123,9 +123,9 @@ func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { keeper.RegisterInvariants(ir, am.keeper) } -// Route returns the message routing key for the bank module. +// Deprecated: Route returns the message routing key for the bank module. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) + return sdk.Route{} } // QuerierRoute returns the bank module's querier route name. diff --git a/x/capability/module.go b/x/capability/module.go index 8047f31f056a..9d298c26e0b1 100644 --- a/x/capability/module.go +++ b/x/capability/module.go @@ -103,8 +103,10 @@ func (am AppModule) Name() string { return am.AppModuleBasic.Name() } -// Route returns the capability module's message routing key. -func (AppModule) Route() sdk.Route { return sdk.Route{} } +// Deprecated: Route returns the capability module's message routing key. +func (AppModule) Route() sdk.Route { + return sdk.Route{} +} // QuerierRoute returns the capability module's query routing key. func (AppModule) QuerierRoute() string { return "" } diff --git a/x/crisis/handler.go b/x/crisis/handler.go deleted file mode 100644 index 0e6cf985f877..000000000000 --- a/x/crisis/handler.go +++ /dev/null @@ -1,25 +0,0 @@ -package crisis - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/crisis/types" -) - -// RouterKey -const RouterKey = types.ModuleName - -func NewHandler(k types.MsgServer) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgVerifyInvariant: - res, err := k.VerifyInvariant(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized crisis message type: %T", msg) - } - } -} diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go deleted file mode 100644 index e981a1a78749..000000000000 --- a/x/crisis/handler_test.go +++ /dev/null @@ -1,116 +0,0 @@ -package crisis_test - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - - "github.com/cosmos/cosmos-sdk/simapp" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/crisis" - "github.com/cosmos/cosmos-sdk/x/crisis/types" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -var ( - testModuleName = "dummy" - dummyRouteWhichPasses = types.NewInvarRoute(testModuleName, "which-passes", func(_ sdk.Context) (string, bool) { return "", false }) - dummyRouteWhichFails = types.NewInvarRoute(testModuleName, "which-fails", func(_ sdk.Context) (string, bool) { return "whoops", true }) -) - -func createTestApp() (*simapp.SimApp, sdk.Context, []sdk.AccAddress) { - app := simapp.Setup(false) - ctx := app.NewContext(false, tmproto.Header{}) - - constantFee := sdk.NewInt64Coin(sdk.DefaultBondDenom, 10) - app.CrisisKeeper.SetConstantFee(ctx, constantFee) - app.StakingKeeper.SetParams(ctx, stakingtypes.DefaultParams()) - - app.CrisisKeeper.RegisterRoute(testModuleName, dummyRouteWhichPasses.Route, dummyRouteWhichPasses.Invar) - app.CrisisKeeper.RegisterRoute(testModuleName, dummyRouteWhichFails.Route, dummyRouteWhichFails.Invar) - - feePool := distrtypes.InitialFeePool() - feePool.CommunityPool = sdk.NewDecCoinsFromCoins(sdk.NewCoins(constantFee)...) - app.DistrKeeper.SetFeePool(ctx, feePool) - - addrs := simapp.AddTestAddrs(app, ctx, 1, sdk.NewInt(10000)) - - return app, ctx, addrs -} - -func TestHandleMsgVerifyInvariant(t *testing.T) { - app, ctx, addrs := createTestApp() - sender := addrs[0] - - cases := []struct { - name string - msg sdk.Msg - expectedResult string - }{ - {"bad invariant route", types.NewMsgVerifyInvariant(sender, testModuleName, "route-that-doesnt-exist"), "fail"}, - {"invariant broken", types.NewMsgVerifyInvariant(sender, testModuleName, dummyRouteWhichFails.Route), "panic"}, - {"invariant passing", types.NewMsgVerifyInvariant(sender, testModuleName, dummyRouteWhichPasses.Route), "pass"}, - {"invalid msg", testdata.NewTestMsg(), "fail"}, - } - - for _, tc := range cases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - h := crisis.NewHandler(app.CrisisKeeper) - - switch tc.expectedResult { - case "fail": - res, err := h(ctx, tc.msg) - require.Error(t, err) - require.Nil(t, res) - - case "pass": - res, err := h(ctx, tc.msg) - require.NoError(t, err) - require.NotNil(t, res) - - case "panic": - require.Panics(t, func() { - h(ctx, tc.msg) // nolint:errcheck - }) - } - }) - } -} - -func TestHandleMsgVerifyInvariantWithNotEnoughSenderCoins(t *testing.T) { - app, ctx, addrs := createTestApp() - sender := addrs[0] - coin := app.BankKeeper.GetAllBalances(ctx, sender)[0] - excessCoins := sdk.NewCoin(coin.Denom, coin.Amount.AddRaw(1)) - app.CrisisKeeper.SetConstantFee(ctx, excessCoins) - - h := crisis.NewHandler(app.CrisisKeeper) - msg := types.NewMsgVerifyInvariant(sender, testModuleName, dummyRouteWhichPasses.Route) - - res, err := h(ctx, msg) - require.Error(t, err) - require.Nil(t, res) -} - -func TestHandleMsgVerifyInvariantWithInvariantBrokenAndNotEnoughPoolCoins(t *testing.T) { - app, ctx, addrs := createTestApp() - sender := addrs[0] - - // set the community pool to empty - feePool := app.DistrKeeper.GetFeePool(ctx) - feePool.CommunityPool = sdk.DecCoins{} - app.DistrKeeper.SetFeePool(ctx, feePool) - - h := crisis.NewHandler(app.CrisisKeeper) - msg := types.NewMsgVerifyInvariant(sender, testModuleName, dummyRouteWhichFails.Route) - - var res *sdk.Result - require.Panics(t, func() { - res, _ = h(ctx, msg) - }, fmt.Sprintf("%v", res)) -} diff --git a/x/crisis/module.go b/x/crisis/module.go index 4a29fc21736b..428e8adc1a05 100644 --- a/x/crisis/module.go +++ b/x/crisis/module.go @@ -119,9 +119,9 @@ func (AppModule) Name() string { // RegisterInvariants performs a no-op. func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} -// Route returns the message routing key for the crisis module. +// Deprecated: Route returns the message routing key for the crisis module. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(RouterKey, NewHandler(*am.keeper)) + return sdk.Route{} } // QuerierRoute returns no querier route. diff --git a/x/distribution/handler.go b/x/distribution/handler.go index 279a6bf726de..f356aee32845 100644 --- a/x/distribution/handler.go +++ b/x/distribution/handler.go @@ -8,35 +8,6 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) -func NewHandler(k keeper.Keeper) sdk.Handler { - msgServer := keeper.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgSetWithdrawAddress: - res, err := msgServer.SetWithdrawAddress(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgWithdrawDelegatorReward: - res, err := msgServer.WithdrawDelegatorReward(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgWithdrawValidatorCommission: - res, err := msgServer.WithdrawValidatorCommission(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgFundCommunityPool: - res, err := msgServer.FundCommunityPool(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized distribution message type: %T", msg) - } - } -} - func NewCommunityPoolSpendProposalHandler(k keeper.Keeper) govtypes.Handler { return func(ctx sdk.Context, content govtypes.Content) error { switch c := content.(type) { diff --git a/x/distribution/module.go b/x/distribution/module.go index e66fc6764e5f..09232331e333 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -121,9 +121,9 @@ func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { keeper.RegisterInvariants(ir, am.keeper) } -// Route returns the message routing key for the distribution module. +// Deprecated: Route returns the message routing key for the distribution module. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) + return sdk.Route{} } // QuerierRoute returns the distribution module's querier route name. diff --git a/x/evidence/handler.go b/x/evidence/handler.go deleted file mode 100644 index 93da4d7bf50d..000000000000 --- a/x/evidence/handler.go +++ /dev/null @@ -1,26 +0,0 @@ -package evidence - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/evidence/keeper" - "github.com/cosmos/cosmos-sdk/x/evidence/types" -) - -// NewHandler returns a handler for evidence messages. -func NewHandler(k keeper.Keeper) sdk.Handler { - msgServer := keeper.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgSubmitEvidence: - res, err := msgServer.SubmitEvidence(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg) - } - } -} diff --git a/x/evidence/handler_test.go b/x/evidence/handler_test.go deleted file mode 100644 index f6294f3e5526..000000000000 --- a/x/evidence/handler_test.go +++ /dev/null @@ -1,127 +0,0 @@ -package evidence_test - -import ( - "fmt" - "testing" - "time" - - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - "github.com/cosmos/cosmos-sdk/simapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/evidence" - "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/evidence/keeper" - "github.com/cosmos/cosmos-sdk/x/evidence/types" -) - -type HandlerTestSuite struct { - suite.Suite - - handler sdk.Handler - app *simapp.SimApp -} - -func testMsgSubmitEvidence(r *require.Assertions, e exported.Evidence, s sdk.AccAddress) exported.MsgSubmitEvidenceI { - msg, err := types.NewMsgSubmitEvidence(s, e) - r.NoError(err) - return msg -} - -func testEquivocationHandler(k interface{}) types.Handler { - return func(ctx sdk.Context, e exported.Evidence) error { - if err := e.ValidateBasic(); err != nil { - return err - } - - ee, ok := e.(*types.Equivocation) - if !ok { - return fmt.Errorf("unexpected evidence type: %T", e) - } - if ee.Height%2 == 0 { - return fmt.Errorf("unexpected even evidence height: %d", ee.Height) - } - - return nil - } -} - -func (suite *HandlerTestSuite) SetupTest() { - checkTx := false - app := simapp.Setup(checkTx) - - // recreate keeper in order to use custom testing types - evidenceKeeper := keeper.NewKeeper( - app.AppCodec(), app.GetKey(types.StoreKey), app.StakingKeeper, app.SlashingKeeper, - ) - router := types.NewRouter() - router = router.AddRoute(types.RouteEquivocation, testEquivocationHandler(*evidenceKeeper)) - evidenceKeeper.SetRouter(router) - - app.EvidenceKeeper = *evidenceKeeper - - suite.handler = evidence.NewHandler(*evidenceKeeper) - suite.app = app -} - -func (suite *HandlerTestSuite) TestMsgSubmitEvidence() { - pk := ed25519.GenPrivKey() - s := sdk.AccAddress("test________________") - - testCases := []struct { - msg sdk.Msg - expectErr bool - }{ - { - testMsgSubmitEvidence( - suite.Require(), - &types.Equivocation{ - Height: 11, - Time: time.Now().UTC(), - Power: 100, - ConsensusAddress: pk.PubKey().Address().String(), - }, - s, - ), - false, - }, - { - testMsgSubmitEvidence( - suite.Require(), - &types.Equivocation{ - Height: 10, - Time: time.Now().UTC(), - Power: 100, - ConsensusAddress: pk.PubKey().Address().String(), - }, - s, - ), - true, - }, - } - - for i, tc := range testCases { - ctx := suite.app.BaseApp.NewContext(false, tmproto.Header{Height: suite.app.LastBlockHeight() + 1}) - - res, err := suite.handler(ctx, tc.msg) - if tc.expectErr { - suite.Require().Error(err, "expected error; tc #%d", i) - } else { - suite.Require().NoError(err, "unexpected error; tc #%d", i) - suite.Require().NotNil(res, "expected non-nil result; tc #%d", i) - - msg := tc.msg.(exported.MsgSubmitEvidenceI) - - var resultData types.MsgSubmitEvidenceResponse - suite.app.AppCodec().Unmarshal(res.Data, &resultData) - suite.Require().Equal(msg.GetEvidence().Hash().Bytes(), resultData.Hash, "invalid hash; tc #%d", i) - } - } -} - -func TestHandlerTestSuite(t *testing.T) { - suite.Run(t, new(HandlerTestSuite)) -} diff --git a/x/evidence/keeper/keeper_test.go b/x/evidence/keeper/keeper_test.go index 102f9773e61d..5352867de1fd 100644 --- a/x/evidence/keeper/keeper_test.go +++ b/x/evidence/keeper/keeper_test.go @@ -19,7 +19,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/keeper" "github.com/cosmos/cosmos-sdk/x/evidence/types" - "github.com/cosmos/cosmos-sdk/x/staking" ) var ( @@ -77,7 +76,6 @@ type KeeperTestSuite struct { app *simapp.SimApp queryClient types.QueryClient - stakingHdl sdk.Handler } func (suite *KeeperTestSuite) SetupTest() { @@ -106,7 +104,6 @@ func (suite *KeeperTestSuite) SetupTest() { queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, app.InterfaceRegistry()) types.RegisterQueryServer(queryHelper, app.EvidenceKeeper) suite.queryClient = types.NewQueryClient(queryHelper) - suite.stakingHdl = staking.NewHandler(app.StakingKeeper) } func (suite *KeeperTestSuite) populateEvidence(ctx sdk.Context, numEvidence int) []exported.Evidence { diff --git a/x/evidence/module.go b/x/evidence/module.go index 367716dd746b..cb6a358c164a 100644 --- a/x/evidence/module.go +++ b/x/evidence/module.go @@ -126,9 +126,9 @@ func (am AppModule) Name() string { return am.AppModuleBasic.Name() } -// Route returns the evidence module's message routing key. +// Deprecated: Route returns the evidence module's message routing key. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) + return sdk.Route{} } // QuerierRoute returns the evidence module's query routing key. diff --git a/x/feegrant/module/module.go b/x/feegrant/module/module.go index b53a4ad5ad55..df6089b40fba 100644 --- a/x/feegrant/module/module.go +++ b/x/feegrant/module/module.go @@ -132,9 +132,9 @@ func (AppModule) Name() string { // RegisterInvariants registers the feegrant module invariants. func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} -// Route returns the message routing key for the feegrant module. +// Deprecated: Route returns the message routing key for the feegrant module. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(feegrant.RouterKey, nil) + return sdk.Route{} } // NewHandler returns an sdk.Handler for the feegrant module. diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 7681bae95cf6..168e544c9f4b 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -4,7 +4,6 @@ import ( "testing" "time" - "github.com/golang/protobuf/proto" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -12,8 +11,11 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/staking" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) func TestTickExpiredDepositPeriod(t *testing.T) { @@ -24,7 +26,7 @@ func TestTickExpiredDepositPeriod(t *testing.T) { header := tmproto.Header{Height: app.LastBlockHeight() + 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) - govHandler := gov.NewHandler(app.GovKeeper) + govMsgSvr := keeper.NewMsgServerImpl(app.GovKeeper) inactiveQueue := app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) @@ -37,7 +39,8 @@ func TestTickExpiredDepositPeriod(t *testing.T) { ) require.NoError(t, err) - res, err := govHandler(ctx, newProposalMsg) + wrapCtx := sdk.WrapSDKContext(ctx) + res, err := govMsgSvr.SubmitProposal(wrapCtx, newProposalMsg) require.NoError(t, err) require.NotNil(t, res) @@ -76,7 +79,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { header := tmproto.Header{Height: app.LastBlockHeight() + 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) - govHandler := gov.NewHandler(app.GovKeeper) + govMsgSvr := keeper.NewMsgServerImpl(app.GovKeeper) inactiveQueue := app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) @@ -89,7 +92,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { ) require.NoError(t, err) - res, err := govHandler(ctx, newProposalMsg) + res, err := govMsgSvr.SubmitProposal(sdk.WrapSDKContext(ctx), newProposalMsg) require.NoError(t, err) require.NotNil(t, res) @@ -112,7 +115,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { ) require.NoError(t, err) - res, err = govHandler(ctx, newProposalMsg2) + res, err = govMsgSvr.SubmitProposal(sdk.WrapSDKContext(ctx), newProposalMsg2) require.NoError(t, err) require.NotNil(t, res) @@ -153,7 +156,7 @@ func TestTickPassedDepositPeriod(t *testing.T) { header := tmproto.Header{Height: app.LastBlockHeight() + 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) - govHandler := gov.NewHandler(app.GovKeeper) + govMsgSvr := keeper.NewMsgServerImpl(app.GovKeeper) inactiveQueue := app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) @@ -169,15 +172,11 @@ func TestTickPassedDepositPeriod(t *testing.T) { ) require.NoError(t, err) - res, err := govHandler(ctx, newProposalMsg) + res, err := govMsgSvr.SubmitProposal(sdk.WrapSDKContext(ctx), newProposalMsg) require.NoError(t, err) require.NotNil(t, res) - var proposalData types.MsgSubmitProposalResponse - err = proto.Unmarshal(res.Data, &proposalData) - require.NoError(t, err) - - proposalID := proposalData.ProposalId + proposalID := res.ProposalId inactiveQueue = app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) @@ -193,9 +192,9 @@ func TestTickPassedDepositPeriod(t *testing.T) { newDepositMsg := types.NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}) - res, err = govHandler(ctx, newDepositMsg) + res1, err := govMsgSvr.Deposit(sdk.WrapSDKContext(ctx), newDepositMsg) require.NoError(t, err) - require.NotNil(t, res) + require.NotNil(t, res1) activeQueue = app.GovKeeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, activeQueue.Valid()) @@ -212,7 +211,7 @@ func TestTickPassedVotingPeriod(t *testing.T) { header := tmproto.Header{Height: app.LastBlockHeight() + 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) - govHandler := gov.NewHandler(app.GovKeeper) + govMsgSvr := keeper.NewMsgServerImpl(app.GovKeeper) inactiveQueue := app.GovKeeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) @@ -225,15 +224,13 @@ func TestTickPassedVotingPeriod(t *testing.T) { newProposalMsg, err := types.NewMsgSubmitProposal(TestProposal, proposalCoins, addrs[0]) require.NoError(t, err) - res, err := govHandler(ctx, newProposalMsg) - require.NoError(t, err) - require.NotNil(t, res) + wrapCtx := sdk.WrapSDKContext(ctx) - var proposalData types.MsgSubmitProposalResponse - err = proto.Unmarshal(res.Data, &proposalData) + res, err := govMsgSvr.SubmitProposal(wrapCtx, newProposalMsg) require.NoError(t, err) + require.NotNil(t, res) - proposalID := proposalData.ProposalId + proposalID := res.ProposalId newHeader := ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) @@ -241,9 +238,9 @@ func TestTickPassedVotingPeriod(t *testing.T) { newDepositMsg := types.NewMsgDeposit(addrs[1], proposalID, proposalCoins) - res, err = govHandler(ctx, newDepositMsg) + res1, err := govMsgSvr.Deposit(wrapCtx, newDepositMsg) require.NoError(t, err) - require.NotNil(t, res) + require.NotNil(t, res1) newHeader = ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod).Add(app.GovKeeper.GetVotingParams(ctx).VotingPeriod) @@ -277,15 +274,15 @@ func TestProposalPassedEndblocker(t *testing.T) { SortAddresses(addrs) - handler := gov.NewHandler(app.GovKeeper) - stakingHandler := staking.NewHandler(app.StakingKeeper) + govMsgSvr := keeper.NewMsgServerImpl(app.GovKeeper) + stakingMsgSvr := stakingkeeper.NewMsgServerImpl(app.StakingKeeper) header := tmproto.Header{Height: app.LastBlockHeight() + 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) valAddr := sdk.ValAddress(addrs[0]) - createValidators(t, stakingHandler, ctx, []sdk.ValAddress{valAddr}, []int64{10}) + createValidators(t, stakingMsgSvr, ctx, []sdk.ValAddress{valAddr}, []int64{10}) staking.EndBlocker(ctx, app.StakingKeeper) macc := app.GovKeeper.GetGovernanceAccount(ctx) @@ -298,7 +295,9 @@ func TestProposalPassedEndblocker(t *testing.T) { proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 10))} newDepositMsg := types.NewMsgDeposit(addrs[0], proposal.ProposalId, proposalCoins) - handleAndCheck(t, handler, ctx, newDepositMsg) + res, err := govMsgSvr.Deposit(sdk.WrapSDKContext(ctx), newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) macc = app.GovKeeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) @@ -328,13 +327,13 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) { SortAddresses(addrs) - stakingHandler := staking.NewHandler(app.StakingKeeper) + stakingMsgSvr := stakingkeeper.NewMsgServerImpl(app.StakingKeeper) header := tmproto.Header{Height: app.LastBlockHeight() + 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) valAddr := sdk.ValAddress(addrs[0]) - createValidators(t, stakingHandler, ctx, []sdk.ValAddress{valAddr}, []int64{10}) + createValidators(t, stakingMsgSvr, ctx, []sdk.ValAddress{valAddr}, []int64{10}) staking.EndBlocker(ctx, app.StakingKeeper) // Create a proposal where the handler will pass for the test proposal @@ -346,7 +345,10 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) { proposalCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 10))) newDepositMsg := types.NewMsgDeposit(addrs[0], proposal.ProposalId, proposalCoins) - handleAndCheck(t, gov.NewHandler(app.GovKeeper), ctx, newDepositMsg) + govMsgSvr := keeper.NewMsgServerImpl(app.GovKeeper) + res, err := govMsgSvr.Deposit(sdk.WrapSDKContext(ctx), newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) err = app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.NewNonSplitVoteOption(types.OptionYes)) require.NoError(t, err) @@ -362,3 +364,19 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) { // validate that the proposal fails/has been rejected gov.EndBlocker(ctx, app.GovKeeper) } + +func createValidators(t *testing.T, stakingMsgSvr stakingtypes.MsgServer, ctx sdk.Context, addrs []sdk.ValAddress, powerAmt []int64) { + require.True(t, len(addrs) <= len(pubkeys), "Not enough pubkeys specified at top of file.") + + for i := 0; i < len(addrs); i++ { + valTokens := sdk.TokensFromConsensusPower(powerAmt[i], sdk.DefaultPowerReduction) + valCreateMsg, err := stakingtypes.NewMsgCreateValidator( + addrs[i], pubkeys[i], sdk.NewCoin(sdk.DefaultBondDenom, valTokens), + TestDescription, TestCommissionRates, sdk.OneInt(), + ) + require.NoError(t, err) + res, err := stakingMsgSvr.CreateValidator(sdk.WrapSDKContext(ctx), valCreateMsg) + require.NoError(t, err) + require.NotNil(t, res) + } +} diff --git a/x/gov/common_test.go b/x/gov/common_test.go index 3ff367e15972..e0a79835280c 100644 --- a/x/gov/common_test.go +++ b/x/gov/common_test.go @@ -4,9 +4,6 @@ import ( "bytes" "log" "sort" - "testing" - - "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -77,23 +74,3 @@ var ( ed25519.GenPrivKey().PubKey(), } ) - -func createValidators(t *testing.T, stakingHandler sdk.Handler, ctx sdk.Context, addrs []sdk.ValAddress, powerAmt []int64) { - require.True(t, len(addrs) <= len(pubkeys), "Not enough pubkeys specified at top of file.") - - for i := 0; i < len(addrs); i++ { - valTokens := sdk.TokensFromConsensusPower(powerAmt[i], sdk.DefaultPowerReduction) - valCreateMsg, err := stakingtypes.NewMsgCreateValidator( - addrs[i], pubkeys[i], sdk.NewCoin(sdk.DefaultBondDenom, valTokens), - TestDescription, TestCommissionRates, sdk.OneInt(), - ) - require.NoError(t, err) - handleAndCheck(t, stakingHandler, ctx, valCreateMsg) - } -} - -func handleAndCheck(t *testing.T, h sdk.Handler, ctx sdk.Context, msg sdk.Msg) { - res, err := h(ctx, msg) - require.NoError(t, err) - require.NotNil(t, res) -} diff --git a/x/gov/handler.go b/x/gov/handler.go deleted file mode 100644 index 6af451d3dd31..000000000000 --- a/x/gov/handler.go +++ /dev/null @@ -1,38 +0,0 @@ -package gov - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/gov/keeper" - "github.com/cosmos/cosmos-sdk/x/gov/types" -) - -// NewHandler creates an sdk.Handler for all the gov type messages -func NewHandler(k keeper.Keeper) sdk.Handler { - msgServer := keeper.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgDeposit: - res, err := msgServer.Deposit(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgSubmitProposal: - res, err := msgServer.SubmitProposal(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgVote: - res, err := msgServer.Vote(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgVoteWeighted: - res, err := msgServer.VoteWeighted(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg) - } - } -} diff --git a/x/gov/handler_test.go b/x/gov/handler_test.go deleted file mode 100644 index a62134e4259e..000000000000 --- a/x/gov/handler_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package gov_test - -import ( - "strings" - "testing" - - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - - "github.com/cosmos/cosmos-sdk/testutil/testdata" - - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/gov" - "github.com/cosmos/cosmos-sdk/x/gov/keeper" -) - -func TestInvalidMsg(t *testing.T) { - k := keeper.Keeper{} - h := gov.NewHandler(k) - - res, err := h(sdk.NewContext(nil, tmproto.Header{}, false, nil), testdata.NewTestMsg()) - require.Error(t, err) - require.Nil(t, res) - require.True(t, strings.Contains(err.Error(), "unrecognized gov message type")) -} diff --git a/x/gov/module.go b/x/gov/module.go index a8121e3ff225..659e5559275c 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -130,9 +130,9 @@ func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { keeper.RegisterInvariants(ir, am.keeper, am.bankKeeper) } -// Route returns the message routing key for the gov module. +// Deprecated: Route returns the message routing key for the gov module. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) + return sdk.Route{} } // QuerierRoute returns the gov module's querier route name. diff --git a/x/mint/module.go b/x/mint/module.go index f502acc87c7f..e923790dc0fb 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -107,7 +107,7 @@ func (AppModule) Name() string { // RegisterInvariants registers the mint module invariants. func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} -// Route returns the message routing key for the mint module. +// Deprecated: Route returns the message routing key for the mint module. func (AppModule) Route() sdk.Route { return sdk.Route{} } // QuerierRoute returns the mint module's querier route name. diff --git a/x/params/module.go b/x/params/module.go index 3f14475cd087..e27eaf44a2ef 100644 --- a/x/params/module.go +++ b/x/params/module.go @@ -95,7 +95,10 @@ func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONCodec, _ json.RawMess return []abci.ValidatorUpdate{} } -func (AppModule) Route() sdk.Route { return sdk.Route{} } +// Deprecated: Route returns the message routing key for the params module. +func (AppModule) Route() sdk.Route { + return sdk.Route{} +} // GenerateGenesisState performs a no-op. func (AppModule) GenerateGenesisState(simState *module.SimulationState) {} diff --git a/x/slashing/handler.go b/x/slashing/handler.go deleted file mode 100644 index eab71edb4188..000000000000 --- a/x/slashing/handler.go +++ /dev/null @@ -1,26 +0,0 @@ -package slashing - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/slashing/keeper" - "github.com/cosmos/cosmos-sdk/x/slashing/types" -) - -// NewHandler creates an sdk.Handler for all the slashing type messages -func NewHandler(k keeper.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - msgServer := keeper.NewMsgServerImpl(k) - - switch msg := msg.(type) { - case *types.MsgUnjail: - res, err := msgServer.Unjail(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg) - } - } -} diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go deleted file mode 100644 index e6b6af64b68d..000000000000 --- a/x/slashing/handler_test.go +++ /dev/null @@ -1,295 +0,0 @@ -package slashing_test - -import ( - "errors" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/require" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - - "github.com/cosmos/cosmos-sdk/simapp" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/slashing" - "github.com/cosmos/cosmos-sdk/x/slashing/keeper" - "github.com/cosmos/cosmos-sdk/x/slashing/testslashing" - "github.com/cosmos/cosmos-sdk/x/slashing/types" - "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/cosmos/cosmos-sdk/x/staking/teststaking" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -func TestCannotUnjailUnlessJailed(t *testing.T) { - // initial setup - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - pks := simapp.CreateTestPubKeys(1) - simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) - - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - slh := slashing.NewHandler(app.SlashingKeeper) - addr, val := sdk.ValAddress(pks[0].Address()), pks[0] - - amt := tstaking.CreateValidatorWithValPower(addr, val, 100, true) - staking.EndBlocker(ctx, app.StakingKeeper) - require.Equal( - t, app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.Coins{sdk.NewCoin(app.StakingKeeper.GetParams(ctx).BondDenom, InitTokens.Sub(amt))}, - ) - require.Equal(t, amt, app.StakingKeeper.Validator(ctx, addr).GetBondedTokens()) - - // assert non-jailed validator can't be unjailed - res, err := slh(ctx, types.NewMsgUnjail(addr)) - require.Error(t, err) - require.Nil(t, res) - require.True(t, errors.Is(types.ErrValidatorNotJailed, err)) -} - -func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { - // initial setup - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - pks := simapp.CreateTestPubKeys(1) - simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) - - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - slh := slashing.NewHandler(app.SlashingKeeper) - addr, val := sdk.ValAddress(pks[0].Address()), pks[0] - amt := app.StakingKeeper.TokensFromConsensusPower(ctx, 100) - msg := tstaking.CreateValidatorMsg(addr, val, amt) - msg.MinSelfDelegation = amt - tstaking.Handle(msg, true) - - staking.EndBlocker(ctx, app.StakingKeeper) - require.Equal( - t, app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.Coins{sdk.NewCoin(app.StakingKeeper.GetParams(ctx).BondDenom, InitTokens.Sub(amt))}, - ) - - tstaking.Undelegate(sdk.AccAddress(addr), addr, sdk.OneInt(), true) - require.True(t, app.StakingKeeper.Validator(ctx, addr).IsJailed()) - - // assert non-jailed validator can't be unjailed - res, err := slh(ctx, types.NewMsgUnjail(addr)) - require.Error(t, err) - require.Nil(t, res) - require.True(t, errors.Is(types.ErrSelfDelegationTooLowToUnjail, err)) -} - -func TestJailedValidatorDelegations(t *testing.T) { - // initial setup - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, tmproto.Header{Time: time.Unix(0, 0)}) - pks := simapp.CreateTestPubKeys(3) - - simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 20)) - app.SlashingKeeper.SetParams(ctx, testslashing.TestParams()) - - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - stakingParams := app.StakingKeeper.GetParams(ctx) - app.StakingKeeper.SetParams(ctx, stakingParams) - valAddr, consAddr := sdk.ValAddress(pks[1].Address()), sdk.ConsAddress(pks[0].Address()) - - amt := tstaking.CreateValidatorWithValPower(valAddr, pks[1], 10, true) - staking.EndBlocker(ctx, app.StakingKeeper) - - // set dummy signing info - newInfo := types.NewValidatorSigningInfo(consAddr, 0, 0, time.Unix(0, 0), false, 0) - app.SlashingKeeper.SetValidatorSigningInfo(ctx, consAddr, newInfo) - - // delegate tokens to the validator - delAddr := sdk.AccAddress(pks[2].Address()) - tstaking.Delegate(delAddr, valAddr, amt) - - // unbond validator total self-delegations (which should jail the validator) - valAcc := sdk.AccAddress(valAddr) - tstaking.Undelegate(valAcc, valAddr, amt, true) - _, err := app.StakingKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr) - require.Nil(t, err, "expected complete unbonding validator to be ok, got: %v", err) - - // verify validator still exists and is jailed - validator, found := app.StakingKeeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.True(t, validator.IsJailed()) - - // verify the validator cannot unjail itself - res, err := slashing.NewHandler(app.SlashingKeeper)(ctx, types.NewMsgUnjail(valAddr)) - require.Error(t, err) - require.Nil(t, res) - - // self-delegate to validator - tstaking.Delegate(valAcc, valAddr, amt) - - // verify the validator can now unjail itself - res, err = slashing.NewHandler(app.SlashingKeeper)(ctx, types.NewMsgUnjail(valAddr)) - require.NoError(t, err) - require.NotNil(t, res) -} - -func TestInvalidMsg(t *testing.T) { - k := keeper.Keeper{} - h := slashing.NewHandler(k) - - res, err := h(sdk.NewContext(nil, tmproto.Header{}, false, nil), testdata.NewTestMsg()) - require.Error(t, err) - require.Nil(t, res) - require.True(t, strings.Contains(err.Error(), "unrecognized slashing message type")) -} - -// Test a validator through uptime, downtime, revocation, -// unrevocation, starting height reset, and revocation again -func TestHandleAbsentValidator(t *testing.T) { - // initial setup - app := simapp.Setup(false) - ctx := app.BaseApp.NewContext(false, tmproto.Header{Time: time.Unix(0, 0)}) - pks := simapp.CreateTestPubKeys(1) - simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 200)) - app.SlashingKeeper.SetParams(ctx, testslashing.TestParams()) - - power := int64(100) - addr, val := sdk.ValAddress(pks[0].Address()), pks[0] - slh := slashing.NewHandler(app.SlashingKeeper) - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - amt := tstaking.CreateValidatorWithValPower(addr, val, power, true) - staking.EndBlocker(ctx, app.StakingKeeper) - - require.Equal( - t, app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(addr)), - sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.GetParams(ctx).BondDenom, InitTokens.Sub(amt))), - ) - require.Equal(t, amt, app.StakingKeeper.Validator(ctx, addr).GetBondedTokens()) - - // will exist since the validator has been bonded - info, found := app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, int64(0), info.IndexOffset) - require.Equal(t, int64(0), info.MissedBlocksCounter) - require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil) - height := int64(0) - - // 1000 first blocks OK - for ; height < app.SlashingKeeper.SignedBlocksWindow(ctx); height++ { - ctx = ctx.WithBlockHeight(height) - app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, true) - } - info, found = app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, int64(0), info.MissedBlocksCounter) - - // 500 blocks missed - for ; height < app.SlashingKeeper.SignedBlocksWindow(ctx)+(app.SlashingKeeper.SignedBlocksWindow(ctx)-app.SlashingKeeper.MinSignedPerWindow(ctx)); height++ { - ctx = ctx.WithBlockHeight(height) - app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - info, found = app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, app.SlashingKeeper.SignedBlocksWindow(ctx)-app.SlashingKeeper.MinSignedPerWindow(ctx), info.MissedBlocksCounter) - - // validator should be bonded still - validator, _ := app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, stakingtypes.Bonded, validator.GetStatus()) - - bondPool := app.StakingKeeper.GetBondedPool(ctx) - require.True(sdk.IntEq(t, amt, app.BankKeeper.GetBalance(ctx, bondPool.GetAddress(), app.StakingKeeper.BondDenom(ctx)).Amount)) - - // 501st block missed - ctx = ctx.WithBlockHeight(height) - app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) - info, found = app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - // counter now reset to zero - require.Equal(t, int64(0), info.MissedBlocksCounter) - - // end block - staking.EndBlocker(ctx, app.StakingKeeper) - - // validator should have been jailed - validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, stakingtypes.Unbonding, validator.GetStatus()) - - slashAmt := amt.ToDec().Mul(app.SlashingKeeper.SlashFractionDowntime(ctx)).RoundInt() - - // validator should have been slashed - require.True(t, amt.Sub(slashAmt).Equal(validator.GetTokens())) - - // 502nd block *also* missed (since the LastCommit would have still included the just-unbonded validator) - height++ - ctx = ctx.WithBlockHeight(height) - app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) - info, found = app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, int64(1), info.MissedBlocksCounter) - - // end block - staking.EndBlocker(ctx, app.StakingKeeper) - - // validator should not have been slashed any more, since it was already jailed - validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.True(t, amt.Sub(slashAmt).Equal(validator.GetTokens())) - - // unrevocation should fail prior to jail expiration - res, err := slh(ctx, types.NewMsgUnjail(addr)) - require.Error(t, err) - require.Nil(t, res) - - // unrevocation should succeed after jail expiration - ctx = ctx.WithBlockHeader(tmproto.Header{Time: time.Unix(1, 0).Add(app.SlashingKeeper.DowntimeJailDuration(ctx))}) - res, err = slh(ctx, types.NewMsgUnjail(addr)) - require.NoError(t, err) - require.NotNil(t, res) - - // end block - staking.EndBlocker(ctx, app.StakingKeeper) - - // validator should be rebonded now - validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, stakingtypes.Bonded, validator.GetStatus()) - - // validator should have been slashed - require.True(t, amt.Sub(slashAmt).Equal(app.BankKeeper.GetBalance(ctx, bondPool.GetAddress(), app.StakingKeeper.BondDenom(ctx)).Amount)) - - // Validator start height should not have been changed - info, found = app.SlashingKeeper.GetValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) - require.True(t, found) - require.Equal(t, int64(0), info.StartHeight) - // we've missed 2 blocks more than the maximum, so the counter was reset to 0 at 1 block more and is now 1 - require.Equal(t, int64(1), info.MissedBlocksCounter) - - // validator should not be immediately jailed again - height++ - ctx = ctx.WithBlockHeight(height) - app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) - validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, stakingtypes.Bonded, validator.GetStatus()) - - // 500 signed blocks - nextHeight := height + app.SlashingKeeper.MinSignedPerWindow(ctx) + 1 - for ; height < nextHeight; height++ { - ctx = ctx.WithBlockHeight(height) - app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - - // end block - staking.EndBlocker(ctx, app.StakingKeeper) - - // validator should be jailed again after 500 unsigned blocks - nextHeight = height + app.SlashingKeeper.MinSignedPerWindow(ctx) + 1 - for ; height <= nextHeight; height++ { - ctx = ctx.WithBlockHeight(height) - app.SlashingKeeper.HandleValidatorSignature(ctx, val.Address(), power, false) - } - - // end block - staking.EndBlocker(ctx, app.StakingKeeper) - - validator, _ = app.StakingKeeper.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) - require.Equal(t, stakingtypes.Unbonding, validator.GetStatus()) -} diff --git a/x/slashing/keeper/keeper_test.go b/x/slashing/keeper/keeper_test.go index 7f3d42b0a7ed..c0cf249855f8 100644 --- a/x/slashing/keeper/keeper_test.go +++ b/x/slashing/keeper/keeper_test.go @@ -42,7 +42,9 @@ func TestUnJailNotBonded(t *testing.T) { amt := app.StakingKeeper.TokensFromConsensusPower(ctx, 50) msg := tstaking.CreateValidatorMsg(addr, val, amt) msg.MinSelfDelegation = amt - tstaking.Handle(msg, true) + res, err := tstaking.CreateValidatorWithMsg(sdk.WrapSDKContext(ctx), msg) + require.NoError(t, err) + require.NotNil(t, res) staking.EndBlocker(ctx, app.StakingKeeper) ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) diff --git a/x/slashing/module.go b/x/slashing/module.go index 030a26c5917c..68c3c2919cdd 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -119,9 +119,9 @@ func (AppModule) Name() string { // RegisterInvariants registers the slashing module invariants. func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} -// Route returns the message routing key for the slashing module. +// Deprecated: Route returns the message routing key for the slashing module. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) + return sdk.Route{} } // QuerierRoute returns the slashing module's querier route name. diff --git a/x/staking/handler.go b/x/staking/handler.go deleted file mode 100644 index 6d89c7a29c53..000000000000 --- a/x/staking/handler.go +++ /dev/null @@ -1,41 +0,0 @@ -package staking - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/staking/keeper" - "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -func NewHandler(k keeper.Keeper) sdk.Handler { - msgServer := keeper.NewMsgServerImpl(k) - - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - - switch msg := msg.(type) { - case *types.MsgCreateValidator: - res, err := msgServer.CreateValidator(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgEditValidator: - res, err := msgServer.EditValidator(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgDelegate: - res, err := msgServer.Delegate(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgBeginRedelegate: - res, err := msgServer.BeginRedelegate(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - case *types.MsgUndelegate: - res, err := msgServer.Undelegate(sdk.WrapSDKContext(ctx), msg) - return sdk.WrapServiceResult(ctx, res, err) - - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg) - } - } -} diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go deleted file mode 100644 index 240ddfee6a5a..000000000000 --- a/x/staking/handler_test.go +++ /dev/null @@ -1,1217 +0,0 @@ -package staking_test - -import ( - "strings" - "testing" - "time" - - "github.com/golang/protobuf/proto" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmtypes "github.com/tendermint/tendermint/types" - - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/simapp" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank/testutil" - "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/cosmos/cosmos-sdk/x/staking/keeper" - "github.com/cosmos/cosmos-sdk/x/staking/teststaking" - "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -func bootstrapHandlerGenesisTest(t *testing.T, power int64, numAddrs int, accAmount sdk.Int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { - _, app, ctx := getBaseSimappWithCustomKeeper() - - addrDels, addrVals := generateAddresses(app, ctx, numAddrs, accAmount) - - amt := app.StakingKeeper.TokensFromConsensusPower(ctx, power) - totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) - - notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - - // set non bonded pool balance - app.AccountKeeper.SetModuleAccount(ctx, notBondedPool) - require.NoError(t, testutil.FundModuleAccount(app.BankKeeper, ctx, notBondedPool.GetName(), totalSupply)) - return app, ctx, addrDels, addrVals -} - -func TestValidatorByPowerIndex(t *testing.T) { - initPower := int64(1000000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - validatorAddr, validatorAddr3 := valAddrs[0], valAddrs[1] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // create validator - initBond := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], initPower, true) - - // must end-block - updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.NoError(t, err) - require.Equal(t, 1, len(updates)) - - // verify the self-delegation exists - bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found) - gotBond := bond.Shares.RoundInt() - require.Equal(t, initBond, gotBond) - - // verify that the by power index exists - validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - power := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx)) - require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) - - // create a second validator keep it bonded - tstaking.CreateValidatorWithValPower(validatorAddr3, PKs[2], initPower, true) - - // must end-block - updates, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.NoError(t, err) - require.Equal(t, 1, len(updates)) - - // slash and jail the first validator - consAddr0 := sdk.ConsAddress(PKs[0].Address()) - app.StakingKeeper.Slash(ctx, consAddr0, 0, initPower, sdk.NewDecWithPrec(5, 1)) - app.StakingKeeper.Jail(ctx, consAddr0) - app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - - validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.Equal(t, types.Unbonding, validator.Status) // ensure is unbonding - require.Equal(t, initBond.QuoRaw(2), validator.Tokens) // ensure tokens slashed - app.StakingKeeper.Unjail(ctx, consAddr0) - - // the old power record should have been deleted as the power changed - require.False(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power)) - - // but the new power record should have been created - validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - power2 := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx)) - require.True(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power2)) - - // now the new record power index should be the same as the original record - power3 := types.GetValidatorsByPowerIndexKey(validator, app.StakingKeeper.PowerReduction(ctx)) - require.Equal(t, power2, power3) - - // unbond self-delegation - totalBond := validator.TokensFromShares(bond.GetShares()).TruncateInt() - res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, totalBond, true) - - var resData types.MsgUndelegateResponse - err = proto.Unmarshal(res.Data, &resData) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(resData.CompletionTime) - staking.EndBlocker(ctx, app.StakingKeeper) - staking.EndBlocker(ctx, app.StakingKeeper) - - // verify that by power key nolonger exists - _, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.False(t, found) - require.False(t, keeper.ValidatorByPowerIndexExists(ctx, app.StakingKeeper, power3)) -} - -func TestDuplicatesMsgCreateValidator(t *testing.T) { - initPower := int64(1000000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 10, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - - addr1, addr2 := valAddrs[0], valAddrs[1] - pk1, pk2 := PKs[0], PKs[1] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - valTokens := tstaking.CreateValidatorWithValPower(addr1, pk1, 10, true) - app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - - validator := tstaking.CheckValidator(addr1, types.Bonded, false) - assert.Equal(t, addr1.String(), validator.OperatorAddress) - consKey, err := validator.TmConsPublicKey() - require.NoError(t, err) - tmPk1, err := cryptocodec.ToTmProtoPublicKey(pk1) - require.NoError(t, err) - assert.Equal(t, tmPk1, consKey) - assert.Equal(t, valTokens, validator.BondedTokens()) - assert.Equal(t, valTokens.ToDec(), validator.DelegatorShares) - assert.Equal(t, types.Description{}, validator.Description) - - // two validators can't have the same operator address - tstaking.CreateValidator(addr1, pk2, valTokens, false) - - // two validators can't have the same pubkey - tstaking.CreateValidator(addr2, pk1, valTokens, false) - - // must have different pubkey and operator - tstaking.CreateValidator(addr2, pk2, valTokens, true) - - // must end-block - updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.NoError(t, err) - require.Equal(t, 1, len(updates)) - - validator = tstaking.CheckValidator(addr2, types.Bonded, false) - assert.Equal(t, addr2.String(), validator.OperatorAddress) - consPk, err := validator.TmConsPublicKey() - require.NoError(t, err) - tmPk2, err := cryptocodec.ToTmProtoPublicKey(pk2) - require.NoError(t, err) - assert.Equal(t, tmPk2, consPk) - assert.True(sdk.IntEq(t, valTokens, validator.Tokens)) - assert.True(sdk.DecEq(t, valTokens.ToDec(), validator.DelegatorShares)) - assert.Equal(t, types.Description{}, validator.Description) -} - -func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { - initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ - Validator: &tmproto.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}}, - }) - - addr := valAddrs[0] - invalidPk := secp256k1.GenPrivKey().PubKey() - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // invalid pukKey type should not be allowed - tstaking.CreateValidator(addr, invalidPk, sdk.NewInt(10), false) -} - -func TestBothPubKeyTypesMsgCreateValidator(t *testing.T) { - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, 1000, 2, sdk.NewInt(1000)) - ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ - Validator: &tmproto.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519, tmtypes.ABCIPubKeyTypeSecp256k1}}, - }) - - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - testCases := []struct { - name string - addr sdk.ValAddress - pk cryptotypes.PubKey - }{ - { - "can create a validator with ed25519 pubkey", - valAddrs[0], - ed25519.GenPrivKey().PubKey(), - }, - { - "can create a validator with secp256k1 pubkey", - valAddrs[1], - secp256k1.GenPrivKey().PubKey(), - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(*testing.T) { - tstaking.CreateValidator(tc.addr, tc.pk, sdk.NewInt(10), true) - }) - } -} - -func TestLegacyValidatorDelegations(t *testing.T) { - initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - valAddr := valAddrs[0] - valConsPubKey, valConsAddr := PKs[0], sdk.ConsAddress(PKs[0].Address()) - delAddr := delAddrs[1] - - // create validator - bondAmount := tstaking.CreateValidatorWithValPower(valAddr, valConsPubKey, 10, true) - - // must end-block - updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.NoError(t, err) - require.Equal(t, 1, len(updates)) - - // verify the validator exists and has the correct attributes - validator := tstaking.CheckValidator(valAddr, types.Bonded, false) - require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) - require.Equal(t, bondAmount, validator.BondedTokens()) - - // delegate tokens to the validator - tstaking.Delegate(delAddr, valAddr, bondAmount) - - // verify validator bonded shares - validator = tstaking.CheckValidator(valAddr, types.Bonded, false) - require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) - require.Equal(t, bondAmount.MulRaw(2), validator.BondedTokens()) - - // unbond validator total self-delegations (which should jail the validator) - res := tstaking.Undelegate(sdk.AccAddress(valAddr), valAddr, bondAmount, true) - - var resData types.MsgUndelegateResponse - err = proto.Unmarshal(res.Data, &resData) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(resData.CompletionTime) - tstaking.Ctx = ctx - staking.EndBlocker(ctx, app.StakingKeeper) - - // verify the validator record still exists, is jailed, and has correct tokens - validator = tstaking.CheckValidator(valAddr, -1, true) - require.Equal(t, bondAmount, validator.Tokens) - - // verify delegation still exists - bond, found := app.StakingKeeper.GetDelegation(ctx, delAddr, valAddr) - require.True(t, found) - require.Equal(t, bondAmount, bond.Shares.RoundInt()) - require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) - - // verify the validator can still self-delegate - tstaking.Delegate(sdk.AccAddress(valAddr), valAddr, bondAmount) - - // verify validator bonded shares - validator, found = app.StakingKeeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.Equal(t, bondAmount.MulRaw(2), validator.DelegatorShares.RoundInt()) - require.Equal(t, bondAmount.MulRaw(2), validator.Tokens) - - // unjail the validator now that is has non-zero self-delegated shares - app.StakingKeeper.Unjail(ctx, valConsAddr) - - // verify the validator can now accept delegations - tstaking.Delegate(delAddr, valAddr, bondAmount) - - // verify validator bonded shares - validator, found = app.StakingKeeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) - require.Equal(t, bondAmount.MulRaw(3), validator.Tokens) - - // verify new delegation - bond, found = app.StakingKeeper.GetDelegation(ctx, delAddr, valAddr) - require.True(t, found) - require.Equal(t, bondAmount.MulRaw(2), bond.Shares.RoundInt()) - require.Equal(t, bondAmount.MulRaw(3), validator.DelegatorShares.RoundInt()) -} - -func TestIncrementsMsgDelegate(t *testing.T) { - initPower := int64(1000) - initBond := sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - - params := app.StakingKeeper.GetParams(ctx) - validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // first create validator - bondAmount := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], 10, true) - - // apply TM updates - app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - - validator := tstaking.CheckValidator(validatorAddr, types.Bonded, false) - require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt()) - require.Equal(t, bondAmount, validator.BondedTokens(), "validator: %v", validator) - - tstaking.CheckDelegator(delegatorAddr, validatorAddr, false) - - bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found) - require.Equal(t, bondAmount, bond.Shares.RoundInt()) - - bondedTokens := app.StakingKeeper.TotalBondedTokens(ctx) - require.Equal(t, bondAmount, bondedTokens) - - for i := int64(0); i < 5; i++ { - ctx = ctx.WithBlockHeight(i) - tstaking.Ctx = ctx - tstaking.Delegate(delegatorAddr, validatorAddr, bondAmount) - - //Check that the accounts and the bond account have the appropriate values - validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - bond, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) - require.True(t, found) - - expBond := bondAmount.MulRaw(i + 1) - expDelegatorShares := bondAmount.MulRaw(i + 2) // (1 self delegation) - expDelegatorAcc := initBond.Sub(expBond) - - gotBond := bond.Shares.RoundInt() - gotDelegatorShares := validator.DelegatorShares.RoundInt() - gotDelegatorAcc := app.BankKeeper.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount - - require.Equal(t, expBond, gotBond, - "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", - i, expBond, gotBond, validator, bond) - require.Equal(t, expDelegatorShares, gotDelegatorShares, - "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", - i, expDelegatorShares, gotDelegatorShares, validator, bond) - require.Equal(t, expDelegatorAcc, gotDelegatorAcc, - "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", - i, expDelegatorAcc, gotDelegatorAcc, validator, bond) - } -} - -func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { - initPower := int64(100) - initBond := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - - validatorAddr := valAddrs[0] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // create validator - msgCreateValidator := tstaking.CreateValidatorMsg(validatorAddr, PKs[0], initBond) - msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) - tstaking.Handle(msgCreateValidator, true) - - // must end-block - updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.NoError(t, err) - require.Equal(t, 1, len(updates)) - - // verify the self-delegation exists - bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found) - gotBond := bond.Shares.RoundInt() - require.Equal(t, initBond, gotBond, - "initBond: %v\ngotBond: %v\nbond: %v\n", - initBond, gotBond, bond) - - newMinSelfDelegation := sdk.OneInt() - msgEditValidator := types.NewMsgEditValidator(validatorAddr, types.Description{}, nil, &newMinSelfDelegation) - tstaking.Handle(msgEditValidator, false) -} - -func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { - initPower := int64(100) - initBond := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction) - - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - validatorAddr := valAddrs[0] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // create validator - msgCreateValidator := tstaking.CreateValidatorMsg(validatorAddr, PKs[0], initBond) - msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) - tstaking.Handle(msgCreateValidator, true) - - // must end-block - updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.NoError(t, err) - require.Equal(t, 1, len(updates)) - - // verify the self-delegation exists - bond, found := app.StakingKeeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found) - gotBond := bond.Shares.RoundInt() - require.Equal(t, initBond, gotBond, - "initBond: %v\ngotBond: %v\nbond: %v\n", - initBond, gotBond, bond) - - newMinSelfDelegation := initBond.Add(sdk.OneInt()) - msgEditValidator := types.NewMsgEditValidator(validatorAddr, types.Description{}, nil, &newMinSelfDelegation) - tstaking.Handle(msgEditValidator, false) -} - -func TestIncrementsMsgUnbond(t *testing.T) { - initPower := int64(1000) - - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - params := app.StakingKeeper.GetParams(ctx) - denom := params.BondDenom - - // create validator, delegate - validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] - initBond := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], initPower, true) - - // initial balance - amt1 := app.BankKeeper.GetBalance(ctx, delegatorAddr, denom).Amount - - tstaking.Delegate(delegatorAddr, validatorAddr, initBond) - - // balance should have been subtracted after delegation - amt2 := app.BankKeeper.GetBalance(ctx, delegatorAddr, denom).Amount - require.True(sdk.IntEq(t, amt1.Sub(initBond), amt2)) - - // apply TM updates - app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - - validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.Equal(t, initBond.MulRaw(2), validator.DelegatorShares.RoundInt()) - require.Equal(t, initBond.MulRaw(2), validator.BondedTokens()) - - // just send the same msgUnbond multiple times - // TODO use decimals here - unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgUndelegate := types.NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - numUnbonds := int64(5) - - for i := int64(0); i < numUnbonds; i++ { - res := tstaking.Handle(msgUndelegate, true) - - var resData types.MsgUndelegateResponse - err := proto.Unmarshal(res.Data, &resData) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(resData.CompletionTime) - tstaking.Ctx = ctx - staking.EndBlocker(ctx, app.StakingKeeper) - - // check that the accounts and the bond account have the appropriate values - validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - bond, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) - require.True(t, found) - - expBond := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) - expDelegatorShares := initBond.MulRaw(2).Sub(unbondAmt.Amount.Mul(sdk.NewInt(i + 1))) - expDelegatorAcc := initBond.Sub(expBond) - - gotBond := bond.Shares.RoundInt() - gotDelegatorShares := validator.DelegatorShares.RoundInt() - gotDelegatorAcc := app.BankKeeper.GetBalance(ctx, delegatorAddr, params.BondDenom).Amount - - require.Equal(t, expBond, gotBond, - "i: %v\nexpBond: %v\ngotBond: %v\nvalidator: %v\nbond: %v\n", - i, expBond, gotBond, validator, bond) - require.Equal(t, expDelegatorShares, gotDelegatorShares, - "i: %v\nexpDelegatorShares: %v\ngotDelegatorShares: %v\nvalidator: %v\nbond: %v\n", - i, expDelegatorShares, gotDelegatorShares, validator, bond) - require.Equal(t, expDelegatorAcc, gotDelegatorAcc, - "i: %v\nexpDelegatorAcc: %v\ngotDelegatorAcc: %v\nvalidator: %v\nbond: %v\n", - i, expDelegatorAcc, gotDelegatorAcc, validator, bond) - } - - // these are more than we have bonded now - errorCases := []sdk.Int{ - //1<<64 - 1, // more than int64 power - //1<<63 + 1, // more than int64 power - app.StakingKeeper.TokensFromConsensusPower(ctx, 1<<63-1), - app.StakingKeeper.TokensFromConsensusPower(ctx, 1<<31), - initBond, - } - - for _, c := range errorCases { - tstaking.Undelegate(delegatorAddr, validatorAddr, c, false) - } - - // should be able to unbond remaining - leftBonded := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(numUnbonds))) - tstaking.Undelegate(delegatorAddr, validatorAddr, leftBonded, true) -} - -func TestMultipleMsgCreateValidator(t *testing.T) { - initPower := int64(1000) - initTokens := sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - - params := app.StakingKeeper.GetParams(ctx) - blockTime := time.Now().UTC() - ctx = ctx.WithBlockTime(blockTime) - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - validatorAddrs := []sdk.ValAddress{ - valAddrs[0], - valAddrs[1], - valAddrs[2], - } - delegatorAddrs := []sdk.AccAddress{ - delAddrs[0], - delAddrs[1], - delAddrs[2], - } - - // bond them all - amt := app.StakingKeeper.TokensFromConsensusPower(ctx, 10) - for i, validatorAddr := range validatorAddrs { - tstaking.CreateValidator(validatorAddr, PKs[i], amt, true) - // verify that the account is bonded - validators := app.StakingKeeper.GetValidators(ctx, 100) - require.Equal(t, (i + 1), len(validators)) - - val := validators[i] - balanceExpd := initTokens.Sub(amt) - balanceGot := app.BankKeeper.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount - - require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators) - require.Equal(t, amt, val.DelegatorShares.RoundInt(), "expected %d shares, got %d", amt, val.DelegatorShares) - require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) - } - - staking.EndBlocker(ctx, app.StakingKeeper) - - // unbond them all by removing delegation - for i, validatorAddr := range validatorAddrs { - _, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - - res := tstaking.Undelegate(delegatorAddrs[i], validatorAddr, amt, true) - - var resData types.MsgUndelegateResponse - err := proto.Unmarshal(res.Data, &resData) - require.NoError(t, err) - - // adds validator into unbonding queue - staking.EndBlocker(ctx, app.StakingKeeper) - - // removes validator from queue and set - staking.EndBlocker(ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)), app.StakingKeeper) - - // Check that the validator is deleted from state - validators := app.StakingKeeper.GetValidators(ctx, 100) - require.Equal(t, len(validatorAddrs)-(i+1), len(validators), - "expected %d validators got %d", len(validatorAddrs)-(i+1), len(validators)) - - _, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.False(t, found) - - gotBalance := app.BankKeeper.GetBalance(ctx, delegatorAddrs[i], params.BondDenom).Amount - require.Equal(t, initTokens, gotBalance, "expected account to have %d, got %d", initTokens, gotBalance) - } -} - -func TestMultipleMsgDelegate(t *testing.T) { - initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 50, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - validatorAddr, delegatorAddrs := valAddrs[0], delAddrs[1:] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - var amount int64 = 10 - - // first make a validator - tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(amount), true) - - // delegate multiple parties - for _, delegatorAddr := range delegatorAddrs { - tstaking.Delegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - tstaking.CheckDelegator(delegatorAddr, validatorAddr, true) - } - - // unbond them all - for _, delegatorAddr := range delegatorAddrs { - res := tstaking.Undelegate(delegatorAddr, validatorAddr, sdk.NewInt(amount), true) - - var resData types.MsgUndelegateResponse - err := proto.Unmarshal(res.Data, &resData) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(resData.CompletionTime) - staking.EndBlocker(ctx, app.StakingKeeper) - tstaking.Ctx = ctx - - // check that the account is unbonded - _, found := app.StakingKeeper.GetDelegation(ctx, delegatorAddr, validatorAddr) - require.False(t, found) - } -} - -func TestJailValidator(t *testing.T) { - initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - var amt int64 = 10 - - // create the validator and delegate - tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(amt), true) - tstaking.Delegate(delegatorAddr, validatorAddr, sdk.NewInt(amt)) - - // unbond the validators bond portion - unamt := sdk.NewInt(amt) - res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, unamt, true) - - var resData types.MsgUndelegateResponse - err := proto.Unmarshal(res.Data, &resData) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(resData.CompletionTime) - staking.EndBlocker(ctx, app.StakingKeeper) - tstaking.Ctx = ctx - - tstaking.CheckValidator(validatorAddr, -1, true) - - // test that the delegator can still withdraw their bonds - tstaking.Undelegate(delegatorAddr, validatorAddr, unamt, true) - - err = proto.Unmarshal(res.Data, &resData) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(resData.CompletionTime) - staking.EndBlocker(ctx, app.StakingKeeper) - tstaking.Ctx = ctx - - // verify that the pubkey can now be reused - tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(amt), true) -} - -func TestValidatorQueue(t *testing.T) { - initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // set the unbonding time - params := app.StakingKeeper.GetParams(ctx) - params.UnbondingTime = 7 * time.Second - app.StakingKeeper.SetParams(ctx, params) - - // create the validator and make a bond - amt := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], 10, true) - tstaking.Delegate(delegatorAddr, validatorAddr, amt) - staking.EndBlocker(ctx, app.StakingKeeper) - - // unbond the all self-delegation to put validator in unbonding state - res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, amt, true) - - var resData types.MsgUndelegateResponse - err := proto.Unmarshal(res.Data, &resData) - require.NoError(t, err) - - finishTime := resData.CompletionTime - - ctx = tstaking.TurnBlock(finishTime) - origHeader := ctx.BlockHeader() - - validator, found := app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.True(t, validator.IsUnbonding(), "%v", validator) - - // should still be unbonding at time 6 seconds later - ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 6)) - - validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.True(t, validator.IsUnbonding(), "%v", validator) - - // should be in unbonded state at time 7 seconds later - ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 7)) - - validator, found = app.StakingKeeper.GetValidator(ctx, validatorAddr) - require.True(t, found) - require.True(t, validator.IsUnbonded(), "%v", validator) -} - -func TestUnbondingPeriod(t *testing.T) { - initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - validatorAddr := valAddrs[0] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // set the unbonding time - params := app.StakingKeeper.GetParams(ctx) - params.UnbondingTime = 7 * time.Second - app.StakingKeeper.SetParams(ctx, params) - - // create the validator - amt := tstaking.CreateValidatorWithValPower(validatorAddr, PKs[0], 10, true) - staking.EndBlocker(ctx, app.StakingKeeper) - - // begin unbonding - tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, amt, true) - - origHeader := ctx.BlockHeader() - - _, found := app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found, "should not have unbonded") - - // cannot complete unbonding at same time - staking.EndBlocker(ctx, app.StakingKeeper) - _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found, "should not have unbonded") - - // cannot complete unbonding at time 6 seconds later - ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 6)) - _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.True(t, found, "should not have unbonded") - - // can complete unbonding at time 7 seconds later - ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 7)) - _, found = app.StakingKeeper.GetUnbondingDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) - require.False(t, found, "should have unbonded") -} - -func TestUnbondingFromUnbondingValidator(t *testing.T) { - initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - validatorAddr, delegatorAddr := valAddrs[0], delAddrs[1] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // create the validator and delegate - tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(10), true) - tstaking.Delegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - - // unbond the validators bond portion - unbondAmt := sdk.NewInt(10) - res := tstaking.Undelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt, true) - - // change the ctx to Block Time one second before the validator would have unbonded - var resData types.MsgUndelegateResponse - err := proto.Unmarshal(res.Data, &resData) - require.NoError(t, err) - - ctx = ctx.WithBlockTime(resData.CompletionTime.Add(time.Second * -1)) - - // unbond the delegator from the validator - res = tstaking.Undelegate(delegatorAddr, validatorAddr, unbondAmt, true) - - ctx = tstaking.TurnBlockTimeDiff(app.StakingKeeper.UnbondingTime(ctx)) - tstaking.Ctx = ctx - - // Check to make sure that the unbonding delegation is no longer in state - // (meaning it was deleted in the above EndBlocker) - _, found := app.StakingKeeper.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) - require.False(t, found, "should be removed from state") -} - -func TestRedelegationPeriod(t *testing.T) { - initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - validatorAddr, validatorAddr2 := valAddrs[0], valAddrs[1] - denom := app.StakingKeeper.GetParams(ctx).BondDenom - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // set the unbonding time - params := app.StakingKeeper.GetParams(ctx) - params.UnbondingTime = 7 * time.Second - app.StakingKeeper.SetParams(ctx, params) - // initial balance - amt1 := app.BankKeeper.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount - - // create the validators - tstaking.CreateValidator(validatorAddr, PKs[0], sdk.NewInt(10), true) - - // balance should have been subtracted after creation - amt2 := app.BankKeeper.GetBalance(ctx, sdk.AccAddress(validatorAddr), denom).Amount - require.Equal(t, amt1.Sub(sdk.NewInt(10)), amt2, "expected coins to be subtracted") - - tstaking.CreateValidator(validatorAddr2, PKs[1], sdk.NewInt(10), true) - bal1 := app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) - - // begin redelegate - redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgBeginRedelegate := types.NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) - tstaking.Handle(msgBeginRedelegate, true) - - // origin account should not lose tokens as with a regular delegation - bal2 := app.BankKeeper.GetAllBalances(ctx, sdk.AccAddress(validatorAddr)) - require.Equal(t, bal1, bal2) - - origHeader := ctx.BlockHeader() - - // cannot complete redelegation at same time - staking.EndBlocker(ctx, app.StakingKeeper) - _, found := app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) - require.True(t, found, "should not have unbonded") - - // cannot complete redelegation at time 6 seconds later - ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 6)) - _, found = app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) - require.True(t, found, "should not have unbonded") - - // can complete redelegation at time 7 seconds later - ctx = tstaking.TurnBlock(origHeader.Time.Add(time.Second * 7)) - _, found = app.StakingKeeper.GetRedelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) - require.False(t, found, "should have unbonded") -} - -func TestTransitiveRedelegation(t *testing.T) { - initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - - val1, val2, val3 := valAddrs[0], valAddrs[1], valAddrs[2] - blockTime := time.Now().UTC() - ctx = ctx.WithBlockTime(blockTime) - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // create the validators - tstaking.CreateValidator(val1, PKs[0], sdk.NewInt(10), true) - tstaking.CreateValidator(val2, PKs[1], sdk.NewInt(10), true) - tstaking.CreateValidator(val3, PKs[2], sdk.NewInt(10), true) - - // begin redelegate - redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) - msgBeginRedelegate := types.NewMsgBeginRedelegate(sdk.AccAddress(val1), val1, val2, redAmt) - tstaking.Handle(msgBeginRedelegate, true) - - // cannot redelegation to next validator while first delegation exists - msgBeginRedelegate = types.NewMsgBeginRedelegate(sdk.AccAddress(val1), val2, val3, redAmt) - tstaking.Handle(msgBeginRedelegate, false) - - params := app.StakingKeeper.GetParams(ctx) - ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)) - tstaking.Ctx = ctx - - // complete first redelegation - staking.EndBlocker(ctx, app.StakingKeeper) - - // now should be able to redelegate from the second validator to the third - tstaking.Handle(msgBeginRedelegate, true) -} - -func TestMultipleRedelegationAtSameTime(t *testing.T) { - initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - valAddr := valAddrs[0] - valAddr2 := valAddrs[1] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // set the unbonding time - params := app.StakingKeeper.GetParams(ctx) - params.UnbondingTime = 1 * time.Second - app.StakingKeeper.SetParams(ctx, params) - - // create the validators - valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true) - tstaking.CreateValidator(valAddr2, PKs[1], valTokens, true) - - // end block to bond them - staking.EndBlocker(ctx, app.StakingKeeper) - - // begin a redelegate - selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) - redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgBeginRedelegate := types.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) - tstaking.Handle(msgBeginRedelegate, true) - - // there should only be one entry in the redelegation object - rd, found := app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.True(t, found) - require.Len(t, rd.Entries, 1) - - // start a second redelegation at this same time as the first - tstaking.Handle(msgBeginRedelegate, true) - - // now there should be two entries - rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.True(t, found) - require.Len(t, rd.Entries, 2) - - // move forward in time, should complete both redelegations - ctx = tstaking.TurnBlockTimeDiff(1 * time.Second) - rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.False(t, found) -} - -func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { - initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 2, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - valAddr := valAddrs[0] - valAddr2 := valAddrs[1] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // set the unbonding time - params := app.StakingKeeper.GetParams(ctx) - params.UnbondingTime = 10 * time.Second - app.StakingKeeper.SetParams(ctx, params) - - // create the validators - valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true) - tstaking.CreateValidator(valAddr2, PKs[1], valTokens, true) - - // end block to bond them - staking.EndBlocker(ctx, app.StakingKeeper) - - // begin a redelegate - selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) - redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) - msgBeginRedelegate := types.NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) - tstaking.Handle(msgBeginRedelegate, true) - - // move forward in time and start a second redelegation - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - tstaking.Ctx = ctx - tstaking.Handle(msgBeginRedelegate, true) - - // now there should be two entries - rd, found := app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.True(t, found) - require.Len(t, rd.Entries, 2) - - // move forward in time, should complete the first redelegation, but not the second - ctx = tstaking.TurnBlockTimeDiff(5 * time.Second) - rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.True(t, found) - require.Len(t, rd.Entries, 1) - - // move forward in time, should complete the second redelegation - ctx = tstaking.TurnBlockTimeDiff(5 * time.Second) - rd, found = app.StakingKeeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) - require.False(t, found) -} - -func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { - initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - valAddr := valAddrs[0] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // set the unbonding time - params := app.StakingKeeper.GetParams(ctx) - params.UnbondingTime = 1 * time.Second - app.StakingKeeper.SetParams(ctx, params) - - // create the validators - valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true) - - // end block to bond - staking.EndBlocker(ctx, app.StakingKeeper) - - // begin an unbonding delegation - selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) - tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true) - - // there should only be one entry in the ubd object - ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // start a second ubd at this same time as the first - tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true) - - // now there should be two entries - ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.True(t, found) - require.Len(t, ubd.Entries, 2) - - // move forwaubd in time, should complete both ubds - ctx = tstaking.TurnBlockTimeDiff(1 * time.Second) - ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.False(t, found) -} - -func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { - initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 1, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - valAddr := valAddrs[0] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // set the unbonding time - params := app.StakingKeeper.GetParams(ctx) - params.UnbondingTime = 10 * time.Second - app.StakingKeeper.SetParams(ctx, params) - - // create the validator - valTokens := tstaking.CreateValidatorWithValPower(valAddr, PKs[0], 10, true) - - // end block to bond - staking.EndBlocker(ctx, app.StakingKeeper) - - // begin an unbonding delegation - selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) - tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true) - - // there should only be one entry in the ubd object - ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // move forwaubd in time and start a second redelegation - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - tstaking.Ctx = ctx - tstaking.Undelegate(selfDelAddr, valAddr, valTokens.QuoRaw(2), true) - - // now there should be two entries - ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.True(t, found) - require.Len(t, ubd.Entries, 2) - - // move forwaubd in time, should complete the first redelegation, but not the second - ctx = tstaking.TurnBlockTimeDiff(5 * time.Second) - ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // move forwaubd in time, should complete the second redelegation - ctx = tstaking.TurnBlockTimeDiff(5 * time.Second) - ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) - require.False(t, found) -} - -func TestUnbondingWhenExcessValidators(t *testing.T) { - initPower := int64(1000) - app, ctx, _, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - val1 := valAddrs[0] - val2 := valAddrs[1] - val3 := valAddrs[2] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - // set the unbonding time - params := app.StakingKeeper.GetParams(ctx) - params.MaxValidators = 2 - app.StakingKeeper.SetParams(ctx, params) - - // add three validators - tstaking.CreateValidatorWithValPower(val1, PKs[0], 50, true) - // apply TM updates - app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(app.StakingKeeper.GetLastValidators(ctx))) - - valTokens2 := tstaking.CreateValidatorWithValPower(val2, PKs[1], 30, true) - app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(app.StakingKeeper.GetLastValidators(ctx))) - - tstaking.CreateValidatorWithValPower(val3, PKs[2], 10, true) - app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(app.StakingKeeper.GetLastValidators(ctx))) - - // unbond the validator-2 - tstaking.Undelegate(sdk.AccAddress(val2), val2, valTokens2, true) - // apply TM updates - app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - - // because there are extra validators waiting to get in, the queued - // validator (aka. validator-1) should make it into the bonded group, thus - // the total number of validators should stay the same - vals := app.StakingKeeper.GetLastValidators(ctx) - require.Equal(t, 2, len(vals), "vals %v", vals) - tstaking.CheckValidator(val1, types.Bonded, false) -} - -func TestBondUnbondRedelegateSlashTwice(t *testing.T) { - initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - valA, valB, del := valAddrs[0], valAddrs[1], delAddrs[2] - consAddr0 := sdk.ConsAddress(PKs[0].Address()) - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - valTokens := tstaking.CreateValidatorWithValPower(valA, PKs[0], 10, true) - tstaking.CreateValidator(valB, PKs[1], valTokens, true) - - // delegate 10 stake - tstaking.Delegate(del, valA, valTokens) - - // apply Tendermint updates - updates, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.NoError(t, err) - require.Equal(t, 2, len(updates)) - - // a block passes - ctx = ctx.WithBlockHeight(1) - tstaking.Ctx = ctx - - // begin unbonding 4 stake - unbondAmt := app.StakingKeeper.TokensFromConsensusPower(ctx, 4) - tstaking.Undelegate(del, valA, unbondAmt, true) - - // begin redelegate 6 stake - redAmt := sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 6)) - msgBeginRedelegate := types.NewMsgBeginRedelegate(del, valA, valB, redAmt) - tstaking.Handle(msgBeginRedelegate, true) - - // destination delegation should have 6 shares - delegation, found := app.StakingKeeper.GetDelegation(ctx, del, valB) - require.True(t, found) - require.Equal(t, sdk.NewDecFromInt(redAmt.Amount), delegation.Shares) - - // must apply validator updates - updates, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.NoError(t, err) - require.Equal(t, 2, len(updates)) - - // slash the validator by half - app.StakingKeeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1)) - - // unbonding delegation should have been slashed by half - ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, del, valA) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - require.Equal(t, unbondAmt.QuoRaw(2), ubd.Entries[0].Balance) - - // redelegation should have been slashed by half - redelegation, found := app.StakingKeeper.GetRedelegation(ctx, del, valA, valB) - require.True(t, found) - require.Len(t, redelegation.Entries, 1) - - // destination delegation should have been slashed by half - delegation, found = app.StakingKeeper.GetDelegation(ctx, del, valB) - require.True(t, found) - require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) - - // validator power should have been reduced by half - validator, found := app.StakingKeeper.GetValidator(ctx, valA) - require.True(t, found) - require.Equal(t, valTokens.QuoRaw(2), validator.GetBondedTokens()) - - // slash the validator for an infraction committed after the unbonding and redelegation begin - ctx = ctx.WithBlockHeight(3) - app.StakingKeeper.Slash(ctx, consAddr0, 2, 10, sdk.NewDecWithPrec(5, 1)) - tstaking.Ctx = ctx - - // unbonding delegation should be unchanged - ubd, found = app.StakingKeeper.GetUnbondingDelegation(ctx, del, valA) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - require.Equal(t, unbondAmt.QuoRaw(2), ubd.Entries[0].Balance) - - // redelegation should be unchanged - redelegation, found = app.StakingKeeper.GetRedelegation(ctx, del, valA, valB) - require.True(t, found) - require.Len(t, redelegation.Entries, 1) - - // destination delegation should be unchanged - delegation, found = app.StakingKeeper.GetDelegation(ctx, del, valB) - require.True(t, found) - require.Equal(t, sdk.NewDecFromInt(redAmt.Amount.QuoRaw(2)), delegation.Shares) - - // end blocker - staking.EndBlocker(ctx, app.StakingKeeper) - - // validator power should have been reduced to zero - // validator should be in unbonding state - validator, _ = app.StakingKeeper.GetValidator(ctx, valA) - require.Equal(t, validator.GetStatus(), types.Unbonding) -} - -func TestInvalidMsg(t *testing.T) { - k := keeper.Keeper{} - h := staking.NewHandler(k) - - res, err := h(sdk.NewContext(nil, tmproto.Header{}, false, nil), testdata.NewTestMsg()) - require.Error(t, err) - require.Nil(t, res) - require.True(t, strings.Contains(err.Error(), "unrecognized staking message type")) -} - -func TestInvalidCoinDenom(t *testing.T) { - initPower := int64(1000) - app, ctx, delAddrs, valAddrs := bootstrapHandlerGenesisTest(t, initPower, 3, sdk.TokensFromConsensusPower(initPower, sdk.DefaultPowerReduction)) - valA, valB, delAddr := valAddrs[0], valAddrs[1], delAddrs[2] - tstaking := teststaking.NewHelper(t, ctx, app.StakingKeeper) - - valTokens := app.StakingKeeper.TokensFromConsensusPower(ctx, 100) - invalidCoin := sdk.NewCoin("churros", valTokens) - validCoin := sdk.NewCoin(sdk.DefaultBondDenom, valTokens) - oneCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()) - - commission := types.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.ZeroDec()) - msgCreate, err := types.NewMsgCreateValidator(valA, PKs[0], invalidCoin, types.Description{}, commission, sdk.OneInt()) - require.NoError(t, err) - tstaking.Handle(msgCreate, false) - - msgCreate, err = types.NewMsgCreateValidator(valA, PKs[0], validCoin, types.Description{}, commission, sdk.OneInt()) - require.NoError(t, err) - tstaking.Handle(msgCreate, true) - - msgCreate, err = types.NewMsgCreateValidator(valB, PKs[1], validCoin, types.Description{}, commission, sdk.OneInt()) - require.NoError(t, err) - tstaking.Handle(msgCreate, true) - - msgDelegate := types.NewMsgDelegate(delAddr, valA, invalidCoin) - tstaking.Handle(msgDelegate, false) - - msgDelegate = types.NewMsgDelegate(delAddr, valA, validCoin) - tstaking.Handle(msgDelegate, true) - - msgUndelegate := types.NewMsgUndelegate(delAddr, valA, invalidCoin) - tstaking.Handle(msgUndelegate, false) - - msgUndelegate = types.NewMsgUndelegate(delAddr, valA, oneCoin) - tstaking.Handle(msgUndelegate, true) - - msgRedelegate := types.NewMsgBeginRedelegate(delAddr, valA, valB, invalidCoin) - tstaking.Handle(msgRedelegate, false) - - msgRedelegate = types.NewMsgBeginRedelegate(delAddr, valA, valB, oneCoin) - tstaking.Handle(msgRedelegate, true) -} diff --git a/x/staking/module.go b/x/staking/module.go index 71cf34eec4de..aa395b80ca17 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -117,9 +117,9 @@ func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { keeper.RegisterInvariants(ir, am.keeper) } -// Route returns the message routing key for the staking module. +// Deprecated: Route returns the message routing key for the staking module. func (am AppModule) Route() sdk.Route { - return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) + return sdk.Route{} } // QuerierRoute returns the staking module's querier route name. diff --git a/x/staking/teststaking/helper.go b/x/staking/teststaking/helper.go index 25b021df07a1..012f21f00eda 100644 --- a/x/staking/teststaking/helper.go +++ b/x/staking/teststaking/helper.go @@ -1,6 +1,7 @@ package teststaking import ( + "context" "testing" "time" @@ -13,12 +14,12 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) -// Helper is a structure which wraps the staking handler +// Helper is a structure which wraps the staking message server // and provides methods useful in tests type Helper struct { - t *testing.T - h sdk.Handler - k keeper.Keeper + t *testing.T + msgSrvr stakingtypes.MsgServer + k keeper.Keeper Ctx sdk.Context Commission stakingtypes.CommissionRates @@ -26,18 +27,18 @@ type Helper struct { Denom string } -// NewHelper creates staking Handler wrapper for tests +// NewHelper creates a new instance of Helper. func NewHelper(t *testing.T, ctx sdk.Context, k keeper.Keeper) *Helper { - return &Helper{t, staking.NewHandler(k), k, ctx, ZeroCommission(), sdk.DefaultBondDenom} + return &Helper{t, keeper.NewMsgServerImpl(k), k, ctx, ZeroCommission(), sdk.DefaultBondDenom} } -// CreateValidator calls handler to create a new staking validator +// CreateValidator calls staking module `MsgServer/CreateValidator` to create a new validator func (sh *Helper) CreateValidator(addr sdk.ValAddress, pk cryptotypes.PubKey, stakeAmount sdk.Int, ok bool) { coin := sdk.NewCoin(sh.Denom, stakeAmount) sh.createValidator(addr, pk, coin, ok) } -// CreateValidatorWithValPower calls handler to create a new staking validator with zero +// CreateValidatorWithValPower calls staking module `MsgServer/CreateValidator` to create a new validator with zero // commission func (sh *Helper) CreateValidatorWithValPower(addr sdk.ValAddress, pk cryptotypes.PubKey, valPower int64, ok bool) sdk.Int { amount := sh.k.TokensFromConsensusPower(sh.Ctx, valPower) @@ -54,36 +55,47 @@ func (sh *Helper) CreateValidatorMsg(addr sdk.ValAddress, pk cryptotypes.PubKey, return msg } +// CreateValidatorWithMsg calls staking module `MsgServer/CreateValidator` +func (sh *Helper) CreateValidatorWithMsg(ctx context.Context, msg *stakingtypes.MsgCreateValidator) (*stakingtypes.MsgCreateValidatorResponse, error) { + return sh.msgSrvr.CreateValidator(ctx, msg) +} + func (sh *Helper) createValidator(addr sdk.ValAddress, pk cryptotypes.PubKey, coin sdk.Coin, ok bool) { msg, err := stakingtypes.NewMsgCreateValidator(addr, pk, coin, stakingtypes.Description{}, sh.Commission, sdk.OneInt()) require.NoError(sh.t, err) - sh.Handle(msg, ok) + res, err := sh.msgSrvr.CreateValidator(sdk.WrapSDKContext(sh.Ctx), msg) + if ok { + require.NoError(sh.t, err) + require.NotNil(sh.t, res) + } else { + require.Error(sh.t, err) + require.Nil(sh.t, res) + } } -// Delegate calls handler to delegate stake for a validator +// Delegate calls staking module staking module `MsgServer/Delegate` to delegate stake for a validator func (sh *Helper) Delegate(delegator sdk.AccAddress, val sdk.ValAddress, amount sdk.Int) { coin := sdk.NewCoin(sh.Denom, amount) msg := stakingtypes.NewMsgDelegate(delegator, val, coin) - sh.Handle(msg, true) + res, err := sh.msgSrvr.Delegate(sdk.WrapSDKContext(sh.Ctx), msg) + require.NoError(sh.t, err) + require.NotNil(sh.t, res) } -// DelegateWithPower calls handler to delegate stake for a validator +// DelegateWithPower calls staking module `MsgServer/Delegate` to delegate stake for a validator func (sh *Helper) DelegateWithPower(delegator sdk.AccAddress, val sdk.ValAddress, power int64) { coin := sdk.NewCoin(sh.Denom, sh.k.TokensFromConsensusPower(sh.Ctx, power)) msg := stakingtypes.NewMsgDelegate(delegator, val, coin) - sh.Handle(msg, true) + res, err := sh.msgSrvr.Delegate(sdk.WrapSDKContext(sh.Ctx), msg) + require.NoError(sh.t, err) + require.NotNil(sh.t, res) } -// Undelegate calls handler to unbound some stake from a validator. -func (sh *Helper) Undelegate(delegator sdk.AccAddress, val sdk.ValAddress, amount sdk.Int, ok bool) *sdk.Result { +// Undelegate calls staking module `MsgServer/Undelegate` to unbound some stake from a validator. +func (sh *Helper) Undelegate(delegator sdk.AccAddress, val sdk.ValAddress, amount sdk.Int, ok bool) { unbondAmt := sdk.NewCoin(sh.Denom, amount) msg := stakingtypes.NewMsgUndelegate(delegator, val, unbondAmt) - return sh.Handle(msg, ok) -} - -// Handle calls staking handler on a given message -func (sh *Helper) Handle(msg sdk.Msg, ok bool) *sdk.Result { - res, err := sh.h(sh.Ctx, msg) + res, err := sh.msgSrvr.Undelegate(sdk.WrapSDKContext(sh.Ctx), msg) if ok { require.NoError(sh.t, err) require.NotNil(sh.t, res) @@ -91,7 +103,6 @@ func (sh *Helper) Handle(msg sdk.Msg, ok bool) *sdk.Result { require.Error(sh.t, err) require.Nil(sh.t, res) } - return res } // CheckValidator asserts that a validor exists and has a given status (if status!="") diff --git a/x/upgrade/module.go b/x/upgrade/module.go index b586193a6b27..00e966912d13 100644 --- a/x/upgrade/module.go +++ b/x/upgrade/module.go @@ -82,8 +82,10 @@ func NewAppModule(keeper keeper.Keeper) AppModule { // RegisterInvariants does nothing, there are no invariants to enforce func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} -// Route is empty, as we do not handle Messages (just proposals) -func (AppModule) Route() sdk.Route { return sdk.Route{} } +// Deprecated: Route returns the message routing key for the upgrade module. +func (AppModule) Route() sdk.Route { + return sdk.Route{} +} // QuerierRoute returns the route we respond to for abci queries func (AppModule) QuerierRoute() string { return types.QuerierKey }