diff --git a/x/ibc/02-client/alias.go b/x/ibc/02-client/alias.go index ac62fc7602c8..762cb695ab26 100644 --- a/x/ibc/02-client/alias.go +++ b/x/ibc/02-client/alias.go @@ -37,8 +37,6 @@ var ( ErrRootNotFound = types.ErrRootNotFound ErrInvalidHeader = types.ErrInvalidHeader ErrInvalidEvidence = types.ErrInvalidEvidence - NewMsgCreateClient = types.NewMsgCreateClient - NewMsgUpdateClient = types.NewMsgUpdateClient // variable aliases SubModuleCdc = types.SubModuleCdc @@ -48,8 +46,6 @@ var ( ) type ( - Keeper = keeper.Keeper - StakingKeeper = types.StakingKeeper - MsgCreateClient = types.MsgCreateClient - MsgUpdateClient = types.MsgUpdateClient + Keeper = keeper.Keeper + StakingKeeper = types.StakingKeeper ) diff --git a/x/ibc/02-client/client/cli/cli.go b/x/ibc/02-client/client/cli/cli.go index 757b8894f719..bd9d8d361be2 100644 --- a/x/ibc/02-client/client/cli/cli.go +++ b/x/ibc/02-client/client/cli/cli.go @@ -26,21 +26,3 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { )...) return ics02ClientQueryCmd } - -// GetTxCmd returns the transaction commands for IBC clients -func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { - ics02ClientTxCmd := &cobra.Command{ - Use: "client", - Short: "Client transaction subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - } - - ics02ClientTxCmd.AddCommand(flags.PostCommands( - GetCmdCreateClient(cdc), - GetCmdUpdateClient(cdc), - GetCmdSubmitMisbehaviour(cdc), - )...) - - return ics02ClientTxCmd -} diff --git a/x/ibc/02-client/client/rest/rest.go b/x/ibc/02-client/client/rest/rest.go index f562634cd742..a6b8b215b2c3 100644 --- a/x/ibc/02-client/client/rest/rest.go +++ b/x/ibc/02-client/client/rest/rest.go @@ -1,14 +1,9 @@ package rest import ( - "time" - "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/types/rest" - evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ) // REST client flags @@ -20,26 +15,4 @@ const ( // RegisterRoutes - Central function to define routes that get registered by the main application func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { registerQueryRoutes(cliCtx, r) - registerTxRoutes(cliCtx, r) -} - -// CreateClientReq defines the properties of a create client request's body. -type CreateClientReq struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - ClientID string `json:"client_id" yaml:"client_id"` - ConsensusState exported.ConsensusState `json:"consensus_state" yaml:"consensus_state"` - TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` - UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"` -} - -// UpdateClientReq defines the properties of a update client request's body. -type UpdateClientReq struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - Header exported.Header `json:"header" yaml:"header"` -} - -// SubmitMisbehaviourReq defines the properties of a submit misbehaviour request's body. -type SubmitMisbehaviourReq struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - Evidence evidenceexported.Evidence `json:"evidence" yaml:"evidence"` } diff --git a/x/ibc/02-client/client/rest/swagger.go b/x/ibc/02-client/client/rest/swagger.go index 42809a112192..7c78a9f4808b 100644 --- a/x/ibc/02-client/client/rest/swagger.go +++ b/x/ibc/02-client/client/rest/swagger.go @@ -1,10 +1,8 @@ package rest import ( - auth "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/evidence" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -17,7 +15,7 @@ type ( QueryHeader struct { Height int64 `json:"height"` - Result tendermint.Header `json:"result"` + Result ibctmtypes.Header `json:"result"` } QueryClientState struct { @@ -27,32 +25,11 @@ type ( QueryNodeConsensusState struct { Height int64 `json:"height"` - Result tendermint.ConsensusState `json:"result"` + Result ibctmtypes.ConsensusState `json:"result"` } QueryPath struct { Height int64 `json:"height"` Result commitment.Prefix `json:"result"` } - - PostCreateClient struct { - Msgs []types.MsgCreateClient `json:"msg" yaml:"msg"` - Fee auth.StdFee `json:"fee" yaml:"fee"` - Signatures []auth.StdSignature `json:"signatures" yaml:"signatures"` - Memo string `json:"memo" yaml:"memo"` - } - - PostUpdateClient struct { - Msgs []types.MsgUpdateClient `json:"msg" yaml:"msg"` - Fee auth.StdFee `json:"fee" yaml:"fee"` - Signatures []auth.StdSignature `json:"signatures" yaml:"signatures"` - Memo string `json:"memo" yaml:"memo"` - } - - PostSubmitMisbehaviour struct { - Msgs []evidence.MsgSubmitEvidence `json:"msg" yaml:"msg"` - Fee auth.StdFee `json:"fee" yaml:"fee"` - Signatures []auth.StdSignature `json:"signatures" yaml:"signatures"` - Memo string `json:"memo" yaml:"memo"` - } ) diff --git a/x/ibc/02-client/client/utils/utils.go b/x/ibc/02-client/client/utils/utils.go index 84a430dc4282..eb83f1bc9df8 100644 --- a/x/ibc/02-client/client/utils/utils.go +++ b/x/ibc/02-client/client/utils/utils.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -91,30 +91,30 @@ func QueryConsensusState( // QueryTendermintHeader takes a client context and returns the appropriate // tendermint header -func QueryTendermintHeader(cliCtx context.CLIContext) (tendermint.Header, int64, error) { +func QueryTendermintHeader(cliCtx context.CLIContext) (ibctmtypes.Header, int64, error) { node, err := cliCtx.GetNode() if err != nil { - return tendermint.Header{}, 0, err + return ibctmtypes.Header{}, 0, err } info, err := node.ABCIInfo() if err != nil { - return tendermint.Header{}, 0, err + return ibctmtypes.Header{}, 0, err } height := info.Response.LastBlockHeight commit, err := node.Commit(&height) if err != nil { - return tendermint.Header{}, 0, err + return ibctmtypes.Header{}, 0, err } validators, err := node.Validators(&height, 0, 10000) if err != nil { - return tendermint.Header{}, 0, err + return ibctmtypes.Header{}, 0, err } - header := tendermint.Header{ + header := ibctmtypes.Header{ SignedHeader: commit.SignedHeader, ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), } @@ -124,30 +124,30 @@ func QueryTendermintHeader(cliCtx context.CLIContext) (tendermint.Header, int64, // QueryNodeConsensusState takes a client context and returns the appropriate // tendermint consensus state -func QueryNodeConsensusState(cliCtx context.CLIContext) (tendermint.ConsensusState, int64, error) { +func QueryNodeConsensusState(cliCtx context.CLIContext) (ibctmtypes.ConsensusState, int64, error) { node, err := cliCtx.GetNode() if err != nil { - return tendermint.ConsensusState{}, 0, err + return ibctmtypes.ConsensusState{}, 0, err } info, err := node.ABCIInfo() if err != nil { - return tendermint.ConsensusState{}, 0, err + return ibctmtypes.ConsensusState{}, 0, err } height := info.Response.LastBlockHeight commit, err := node.Commit(&height) if err != nil { - return tendermint.ConsensusState{}, 0, err + return ibctmtypes.ConsensusState{}, 0, err } validators, err := node.Validators(&height, 0, 10000) if err != nil { - return tendermint.ConsensusState{}, 0, err + return ibctmtypes.ConsensusState{}, 0, err } - state := tendermint.ConsensusState{ + state := ibctmtypes.ConsensusState{ Timestamp: commit.Time, Root: commitment.NewRoot(commit.AppHash), ValidatorSet: tmtypes.NewValidatorSet(validators.Validators), diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index bdaa85583bce..e5623ed8ddca 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -4,6 +4,8 @@ import ( "encoding/json" "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/codec" evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" @@ -90,6 +92,9 @@ type ClientState interface { type ConsensusState interface { ClientType() ClientType // Consensus kind + // GetHeight returns the height of the consensus state + GetHeight() uint64 + // GetRoot returns the commitment root of the consensus state, // which is used for key-value pair verification. GetRoot() commitment.RootI @@ -110,6 +115,23 @@ type Header interface { GetHeight() uint64 } +// MsgCreateClient defines the msg interface that the +// CreateClient Handler expects +type MsgCreateClient interface { + sdk.Msg + GetClientID() string + GetClientType() string + GetConsensusState() ConsensusState +} + +// MsgUpdateClient defines the msg interface that the +// UpdateClient Handler expects +type MsgUpdateClient interface { + sdk.Msg + GetClientID() string + GetHeader() Header +} + // ClientType defines the type of the consensus algorithm type ClientType byte diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index 8a06c3485c9d..3354fe93b8c4 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -7,32 +7,52 @@ import ( evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" ) // HandleMsgCreateClient defines the sdk.Handler for MsgCreateClient -func HandleMsgCreateClient(ctx sdk.Context, k Keeper, msg MsgCreateClient) (*sdk.Result, error) { - clientType := exported.ClientTypeFromString(msg.ClientType) - if clientType == 0 { - return nil, sdkerrors.Wrap(ErrInvalidClientType, msg.ClientType) +func HandleMsgCreateClient(ctx sdk.Context, k Keeper, msg exported.MsgCreateClient) (*sdk.Result, error) { + clientType := exported.ClientTypeFromString(msg.GetClientType()) + var clientState exported.ClientState + switch clientType { + case 0: + return nil, sdkerrors.Wrap(ErrInvalidClientType, msg.GetClientType()) + case exported.Tendermint: + tmMsg, ok := msg.(ibctmtypes.MsgCreateClient) + if !ok { + return nil, sdkerrors.Wrap(ErrInvalidClientType, "Msg is not a Tendermint CreateClient msg") + } + var err error + clientState, err = ibctmtypes.InitializeFromMsg(tmMsg) + if err != nil { + return nil, err + } + default: + return nil, sdkerrors.Wrap(ErrInvalidClientType, msg.GetClientType()) } _, err := k.CreateClient( - ctx, msg.ClientID, clientType, msg.ConsensusState, msg.TrustingPeriod, msg.UnbondingPeriod, + ctx, clientState, msg.GetConsensusState(), ) if err != nil { return nil, err } + attributes := make([]sdk.Attribute, len(msg.GetSigners())+1) + attributes[0] = sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory) + for i, signer := range msg.GetSigners() { + attributes[i+1] = sdk.NewAttribute(sdk.AttributeKeySender, signer.String()) + } + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( EventTypeCreateClient, - sdk.NewAttribute(AttributeKeyClientID, msg.ClientID), - sdk.NewAttribute(AttrbuteKeyClientType, msg.ClientType), + sdk.NewAttribute(AttributeKeyClientID, msg.GetClientID()), + sdk.NewAttribute(AttrbuteKeyClientType, msg.GetClientType()), ), sdk.NewEvent( sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + attributes..., ), }) @@ -42,21 +62,26 @@ func HandleMsgCreateClient(ctx sdk.Context, k Keeper, msg MsgCreateClient) (*sdk } // HandleMsgUpdateClient defines the sdk.Handler for MsgUpdateClient -func HandleMsgUpdateClient(ctx sdk.Context, k Keeper, msg MsgUpdateClient) (*sdk.Result, error) { - if err := k.UpdateClient(ctx, msg.ClientID, msg.Header); err != nil { +func HandleMsgUpdateClient(ctx sdk.Context, k Keeper, msg exported.MsgUpdateClient) (*sdk.Result, error) { + if err := k.UpdateClient(ctx, msg.GetClientID(), msg.GetHeader()); err != nil { return nil, err } + attributes := make([]sdk.Attribute, len(msg.GetSigners())+1) + attributes[0] = sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory) + for i, signer := range msg.GetSigners() { + attributes[i+1] = sdk.NewAttribute(sdk.AttributeKeySender, signer.String()) + } + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( EventTypeUpdateClient, - sdk.NewAttribute(AttributeKeyClientID, msg.ClientID), - sdk.NewAttribute(AttrbuteKeyClientType, msg.Header.ClientType().String()), + sdk.NewAttribute(AttributeKeyClientID, msg.GetClientID()), + sdk.NewAttribute(AttrbuteKeyClientType, msg.GetHeader().ClientType().String()), ), sdk.NewEvent( sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, AttributeValueCategory), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()), + attributes..., ), }) diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index a4bd68077632..98f2220727ef 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -2,22 +2,23 @@ package keeper import ( "fmt" - "time" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" ) // CreateClient creates a new client state and populates it with a given consensus // state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create +// +// CONTRACT: ClientState was constructed correctly from given initial consensusState func (k Keeper) CreateClient( - ctx sdk.Context, clientID string, - clientType exported.ClientType, consensusState exported.ConsensusState, - trustingPeriod, unbondingPeriod time.Duration, + ctx sdk.Context, clientState exported.ClientState, consensusState exported.ConsensusState, ) (exported.ClientState, error) { + clientID := clientState.GetID() _, found := k.GetClientState(ctx, clientID) if found { return nil, sdkerrors.Wrapf(types.ErrClientExists, "cannot create client with ID %s", clientID) @@ -28,13 +29,13 @@ func (k Keeper) CreateClient( panic(fmt.Sprintf("client type is already defined for client %s", clientID)) } - clientState, err := k.initialize(ctx, clientID, clientType, consensusState, trustingPeriod, unbondingPeriod) - if err != nil { - return nil, sdkerrors.Wrapf(err, "cannot create client with ID %s", clientID) + height := consensusState.GetHeight() + if consensusState != nil { + k.SetClientConsensusState(ctx, clientID, height, consensusState) } k.SetClientState(ctx, clientState) - k.SetClientType(ctx, clientID, clientType) + k.SetClientType(ctx, clientID, clientState.ClientType()) k.Logger(ctx).Info(fmt.Sprintf("client %s created at height %d", clientID, clientState.GetLatestHeight())) ctx.EventManager().EmitEvents(sdk.Events{ @@ -81,7 +82,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H switch clientType { case exported.Tendermint: clientState, consensusState, err = tendermint.CheckValidityAndUpdateState( - clientState, header, ctx.ChainID(), ctx.BlockTime(), + clientState, header, ctx.BlockTime(), ) default: err = types.ErrInvalidClientType @@ -117,16 +118,16 @@ func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, misbehaviour ex return sdkerrors.Wrap(types.ErrClientNotFound, misbehaviour.GetClientID()) } - consensusState, found := k.GetClientConsensusState(ctx, misbehaviour.GetClientID(), uint64(misbehaviour.GetHeight())) + consensusState, found := k.GetClientConsensusStateLTE(ctx, misbehaviour.GetClientID(), uint64(misbehaviour.GetHeight())) if !found { return sdkerrors.Wrap(types.ErrConsensusStateNotFound, misbehaviour.GetClientID()) } var err error switch e := misbehaviour.(type) { - case tendermint.Evidence: + case ibctmtypes.Evidence: clientState, err = tendermint.CheckMisbehaviourAndUpdateState( - clientState, consensusState, misbehaviour, uint64(misbehaviour.GetHeight()), ctx.BlockTime(), + clientState, consensusState, misbehaviour, consensusState.GetHeight(), ctx.BlockTime(), ) default: diff --git a/x/ibc/02-client/keeper/client_test.go b/x/ibc/02-client/keeper/client_test.go index a3f29aa19979..dcd7ef911474 100644 --- a/x/ibc/02-client/keeper/client_test.go +++ b/x/ibc/02-client/keeper/client_test.go @@ -7,7 +7,8 @@ import ( tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -25,14 +26,13 @@ func (suite *KeeperTestSuite) TestCreateClient() { cases := []struct { msg string - params params + clientID string expPass bool expPanic bool }{ - {"success", params{testClientID, exported.Tendermint}, true, false}, - {"client ID exists", params{testClientID, exported.Tendermint}, false, false}, - {"client type exists", params{testClientID2, exported.Tendermint}, false, true}, - {"invalid client type", params{testClientID3, invalidClientType}, false, false}, + {"success", testClientID, true, false}, + {"client ID exists", testClientID, false, false}, + {"client type exists", testClientID2, false, true}, } for i, tc := range cases { @@ -40,17 +40,25 @@ func (suite *KeeperTestSuite) TestCreateClient() { if tc.expPanic { suite.Require().Panics(func() { - suite.keeper.CreateClient(suite.ctx, tc.params.clientID, tc.params.clientType, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(tc.clientID, tc.clientID, suite.consensusState, trustingPeriod, ubdPeriod) + suite.Require().NoError(err, "err on client state initialization") + suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) }, "Msg %d didn't panic: %s", i, tc.msg) } else { - clientState, err := suite.keeper.CreateClient(suite.ctx, tc.params.clientID, tc.params.clientType, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(tc.clientID, tc.clientID, suite.consensusState, trustingPeriod, ubdPeriod) + if tc.expPass { + suite.Require().NoError(err, "errored on initialization") + suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.msg) + } + // If we were able to initialize clientstate successfully, try persisting it to state + if err == nil { + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + } if tc.expPass { suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) - suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.msg) } else { suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) - suite.Require().Nil(clientState, "invalid test case %d passed: %s", i, tc.msg) } } } @@ -63,7 +71,11 @@ func (suite *KeeperTestSuite) TestUpdateClient() { expPass bool }{ {"valid update", func() error { - _, err := suite.keeper.CreateClient(suite.ctx, testClientID, exported.Tendermint, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + if err != nil { + return err + } + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) return err }, true}, {"client type not found", func() error { @@ -78,13 +90,17 @@ func (suite *KeeperTestSuite) TestUpdateClient() { return nil }, false}, {"frozen client", func() error { - clientState := tendermint.ClientState{FrozenHeight: 1, ID: testClientID, LatestHeight: 10} + clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LatestHeight: 10} suite.keeper.SetClientState(suite.ctx, clientState) suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint) return nil }, false}, {"invalid header", func() error { - _, err := suite.keeper.CreateClient(suite.ctx, testClientID, exported.Tendermint, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + if err != nil { + return err + } + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) if err != nil { return err } @@ -104,7 +120,7 @@ func (suite *KeeperTestSuite) TestUpdateClient() { err = suite.keeper.UpdateClient(suite.ctx, testClientID, suite.header) if tc.expPass { - expConsensusState := tendermint.ConsensusState{ + expConsensusState := ibctmtypes.ConsensusState{ Timestamp: suite.header.Time, Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.header.ValidatorSet, @@ -115,10 +131,14 @@ func (suite *KeeperTestSuite) TestUpdateClient() { consensusState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, uint64(suite.header.GetHeight())) suite.Require().True(found, "valid test case %d failed: %s", i, tc.name) + tmConsState, ok := consensusState.(ibctmtypes.ConsensusState) + suite.Require().True(ok, "consensus state is not a tendermint consensus state") + // recalculate cached totalVotingPower field for equality check + tmConsState.ValidatorSet.TotalVotingPower() suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - suite.Require().Equal(suite.header.GetHeight(), clientState.GetLatestHeight(), "client state height not updated correctly") - suite.Require().Equal(expConsensusState, consensusState, "consensus state should have been updated") + suite.Require().Equal(suite.header.GetHeight(), clientState.GetLatestHeight(), "client state height not updated correctly on case %s", tc.name) + suite.Require().Equal(expConsensusState, consensusState, "consensus state should have been updated on case %s", tc.name) } else { suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) } @@ -147,41 +167,66 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { testCases := []struct { name string - evidence tendermint.Evidence + evidence ibctmtypes.Evidence malleate func() error expPass bool }{ { "trusting period misbehavior should pass", - tendermint.Evidence{ - Header1: tendermint.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, suite.valSet, bothSigners), - Header2: tendermint.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, suite.valSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), + ChainID: testClientID, + ClientID: testClientID, + }, + func() error { + suite.consensusState.ValidatorSet = bothValSet + clientState, err := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + if err != nil { + return err + } + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + + return err + }, + true, + }, + { + "misbehavior at later height should pass", + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.ctx.BlockTime(), bothValSet, suite.valSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), ChainID: testClientID, ClientID: testClientID, }, func() error { suite.consensusState.ValidatorSet = bothValSet - _, err := suite.keeper.CreateClient(suite.ctx, testClientID, exported.Tendermint, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + if err != nil { + return err + } + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + return err }, true, }, { "client state not found", - tendermint.Evidence{}, + ibctmtypes.Evidence{}, func() error { return nil }, false, }, { "consensus state not found", - tendermint.Evidence{ - Header1: tendermint.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, suite.valSet, bothSigners), - Header2: tendermint.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, suite.valSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), ChainID: testClientID, ClientID: testClientID, }, func() error { - clientState := tendermint.ClientState{FrozenHeight: 1, ID: testClientID, LatestHeight: 10} + clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LatestHeight: 10} suite.keeper.SetClientState(suite.ctx, clientState) return nil }, @@ -189,14 +234,14 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "consensus state not found", - tendermint.Evidence{ - Header1: tendermint.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, suite.valSet, bothSigners), - Header2: tendermint.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, suite.valSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), ChainID: testClientID, ClientID: testClientID, }, func() error { - clientState := tendermint.ClientState{FrozenHeight: 1, ID: testClientID, LatestHeight: 10} + clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LatestHeight: 10} suite.keeper.SetClientState(suite.ctx, clientState) return nil }, @@ -204,14 +249,19 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "misbehaviour check failed", - tendermint.Evidence{ - Header1: tendermint.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), - Header2: tendermint.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners), + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(testClientID, testClientHeight, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners), ChainID: testClientID, ClientID: testClientID, }, func() error { - _, err := suite.keeper.CreateClient(suite.ctx, testClientID, exported.Tendermint, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + if err != nil { + return err + } + _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + return err }, false, diff --git a/x/ibc/02-client/keeper/keeper.go b/x/ibc/02-client/keeper/keeper.go index ddbef34f3f70..f9b1dbdcfdc9 100644 --- a/x/ibc/02-client/keeper/keeper.go +++ b/x/ibc/02-client/keeper/keeper.go @@ -2,7 +2,6 @@ package keeper import ( "fmt" - "time" "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" @@ -11,7 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -97,6 +96,34 @@ func (k Keeper) SetClientConsensusState(ctx sdk.Context, clientID string, height store.Set(ibctypes.KeyConsensusState(clientID, height), bz) } +// HasClientConsensusState returns if keeper has a ConsensusState for a particular +// client at the given height +func (k Keeper) HasClientConsensusState(ctx sdk.Context, clientID string, height uint64) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(ibctypes.KeyConsensusState(clientID, height)) +} + +// GetLatestClientConsensusState gets the latest ConsensusState stored for a given client +func (k Keeper) GetLatestClientConsensusState(ctx sdk.Context, clientID string) (exported.ConsensusState, bool) { + clientState, ok := k.GetClientState(ctx, clientID) + if !ok { + return nil, false + } + return k.GetClientConsensusState(ctx, clientID, clientState.GetLatestHeight()) +} + +// GetClientConsensusStatelTE will get the latest ConsensusState of a particular client at the latest height +// less than or equal to the given height +func (k Keeper) GetClientConsensusStateLTE(ctx sdk.Context, clientID string, maxHeight uint64) (exported.ConsensusState, bool) { + for i := maxHeight; i > 0; i-- { + found := k.HasClientConsensusState(ctx, clientID, i) + if found { + return k.GetClientConsensusState(ctx, clientID, i) + } + } + return nil, false +} + // GetSelfConsensusState introspects the (self) past historical info at a given height // and returns the expected consensus state at that height. func (k Keeper) GetSelfConsensusState(ctx sdk.Context, height uint64) (exported.ConsensusState, bool) { @@ -107,7 +134,8 @@ func (k Keeper) GetSelfConsensusState(ctx sdk.Context, height uint64) (exported. valSet := stakingtypes.Validators(histInfo.Valset) - consensusState := tendermint.ConsensusState{ + consensusState := ibctmtypes.ConsensusState{ + Height: height, Timestamp: ctx.BlockTime(), Root: commitment.NewRoot(histInfo.Header.AppHash), ValidatorSet: tmtypes.NewValidatorSet(valSet.ToTmValidators()), @@ -141,32 +169,3 @@ func (k Keeper) GetAllClients(ctx sdk.Context) (states []exported.ClientState) { }) return states } - -// State returns a new client state with a given id as defined in -// https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#example-implementation -func (k Keeper) initialize( - ctx sdk.Context, clientID string, clientType exported.ClientType, - consensusState exported.ConsensusState, trustingPeriod, unbondingPeriod time.Duration, -) (exported.ClientState, error) { - height := uint64(ctx.BlockHeight()) - - var ( - clientState exported.ClientState - err error - ) - switch clientType { - case exported.Tendermint: - clientState, err = tendermint.Initialize( - clientID, consensusState, trustingPeriod, unbondingPeriod, height, - ) - default: - err = types.ErrInvalidClientType - } - - if err != nil { - return nil, err - } - - k.SetClientConsensusState(ctx, clientID, height, consensusState) - return clientState, nil -} diff --git a/x/ibc/02-client/keeper/keeper_test.go b/x/ibc/02-client/keeper/keeper_test.go index 5c7c54c4e71b..1cdf296ed6b1 100644 --- a/x/ibc/02-client/keeper/keeper_test.go +++ b/x/ibc/02-client/keeper/keeper_test.go @@ -15,7 +15,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/staking" ) @@ -37,8 +37,8 @@ type KeeperTestSuite struct { cdc *codec.Codec ctx sdk.Context keeper *keeper.Keeper - consensusState tendermint.ConsensusState - header tendermint.Header + consensusState ibctmtypes.ConsensusState + header ibctmtypes.Header valSet *tmtypes.ValidatorSet privVal tmtypes.PrivValidator now time.Time @@ -56,8 +56,9 @@ func (suite *KeeperTestSuite) SetupTest() { suite.privVal = tmtypes.NewMockPV() validator := tmtypes.NewValidator(suite.privVal.GetPubKey(), 1) suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - suite.header = tendermint.CreateTestHeader(testClientID, testClientHeight+2, now2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) - suite.consensusState = tendermint.ConsensusState{ + suite.header = ibctmtypes.CreateTestHeader(testClientID, testClientHeight+2, now2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + suite.consensusState = ibctmtypes.ConsensusState{ + Height: testClientHeight, Timestamp: suite.now, Root: commitment.NewRoot([]byte("hash")), ValidatorSet: suite.valSet, @@ -81,7 +82,7 @@ func TestKeeperTestSuite(t *testing.T) { } func (suite *KeeperTestSuite) TestSetClientState() { - clientState := tendermint.NewClientState(testClientID, trustingPeriod, ubdPeriod, testClientHeight, suite.now) + clientState := ibctmtypes.NewClientState(testClientID, testClientID, trustingPeriod, ubdPeriod, testClientHeight, suite.now) suite.keeper.SetClientState(suite.ctx, clientState) retrievedState, found := suite.keeper.GetClientState(suite.ctx, testClientID) @@ -103,16 +104,18 @@ func (suite *KeeperTestSuite) TestSetClientConsensusState() { retrievedConsState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, testClientHeight) suite.Require().True(found, "GetConsensusState failed") - tmConsState, ok := retrievedConsState.(tendermint.ConsensusState) + tmConsState, ok := retrievedConsState.(ibctmtypes.ConsensusState) + // recalculate cached totalVotingPower field for equality check + tmConsState.ValidatorSet.TotalVotingPower() suite.Require().True(ok) suite.Require().Equal(suite.consensusState, tmConsState, "ConsensusState not stored correctly") } func (suite KeeperTestSuite) TestGetAllClients() { expClients := []exported.ClientState{ - tendermint.NewClientState(testClientID2, trustingPeriod, ubdPeriod, testClientHeight, suite.now), - tendermint.NewClientState(testClientID3, trustingPeriod, ubdPeriod, testClientHeight, suite.now), - tendermint.NewClientState(testClientID, trustingPeriod, ubdPeriod, testClientHeight, suite.now), + ibctmtypes.NewClientState(testClientID2, testClientID, trustingPeriod, ubdPeriod, testClientHeight, suite.now), + ibctmtypes.NewClientState(testClientID3, testClientID, trustingPeriod, ubdPeriod, testClientHeight, suite.now), + ibctmtypes.NewClientState(testClientID, testClientID, trustingPeriod, ubdPeriod, testClientHeight, suite.now), } for i := range expClients { @@ -149,3 +152,35 @@ func (suite KeeperTestSuite) TestGetConsensusState() { } } } + +func (suite KeeperTestSuite) TestConsensusStateHelpers() { + // initial setup + clientState, _ := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + suite.keeper.SetClientState(suite.ctx, clientState) + suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState) + + nextState := ibctmtypes.ConsensusState{ + Height: testClientHeight + 5, + Timestamp: suite.now, + Root: commitment.NewRoot([]byte("next")), + ValidatorSet: suite.valSet, + } + + // mock update functionality + suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight+5, nextState) + clientState.LatestHeight += 5 + suite.keeper.SetClientState(suite.ctx, clientState) + + latest, ok := suite.keeper.GetLatestClientConsensusState(suite.ctx, testClientID) + // recalculate cached totalVotingPower for equality check + latest.(ibctmtypes.ConsensusState).ValidatorSet.TotalVotingPower() + suite.Require().True(ok) + suite.Require().Equal(nextState, latest, "Latest client not returned correctly") + + // Should return existing consensusState at latestClientHeight + lte, ok := suite.keeper.GetClientConsensusStateLTE(suite.ctx, testClientID, testClientHeight+3) + // recalculate cached totalVotingPower for equality check + lte.(ibctmtypes.ConsensusState).ValidatorSet.TotalVotingPower() + suite.Require().True(ok) + suite.Require().Equal(suite.consensusState, lte, "LTE helper function did not return latest client state below height: %d", testClientHeight+3) +} diff --git a/x/ibc/02-client/module.go b/x/ibc/02-client/module.go index 9e5ddbd7dbd5..fd1fd48c06b2 100644 --- a/x/ibc/02-client/module.go +++ b/x/ibc/02-client/module.go @@ -22,11 +22,6 @@ func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router, queryRoute stri rest.RegisterRoutes(ctx, rtr, fmt.Sprintf("%s/%s", queryRoute, SubModuleName)) } -// GetTxCmd returns the root tx command for the IBC client -func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command { - return cli.GetTxCmd(fmt.Sprintf("%s/%s", storeKey, SubModuleName), cdc) -} - // GetQueryCmd returns no root query command for the IBC client func GetQueryCmd(cdc *codec.Codec, queryRoute string) *cobra.Command { return cli.GetQueryCmd(fmt.Sprintf("%s/%s", queryRoute, SubModuleName), cdc) diff --git a/x/ibc/02-client/types/codec.go b/x/ibc/02-client/types/codec.go index 3226fc02c2cf..b8c0eed6ee61 100644 --- a/x/ibc/02-client/types/codec.go +++ b/x/ibc/02-client/types/codec.go @@ -11,13 +11,12 @@ var SubModuleCdc *codec.Codec // RegisterCodec registers the IBC client interfaces and types func RegisterCodec(cdc *codec.Codec) { cdc.RegisterInterface((*exported.ClientState)(nil), nil) + cdc.RegisterInterface((*exported.MsgCreateClient)(nil), nil) + cdc.RegisterInterface((*exported.MsgUpdateClient)(nil), nil) cdc.RegisterInterface((*exported.ConsensusState)(nil), nil) cdc.RegisterInterface((*exported.Header)(nil), nil) cdc.RegisterInterface((*exported.Misbehaviour)(nil), nil) - cdc.RegisterConcrete(MsgCreateClient{}, "ibc/client/MsgCreateClient", nil) - cdc.RegisterConcrete(MsgUpdateClient{}, "ibc/client/MsgUpdateClient", nil) - SetSubModuleCodec(cdc) } diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors.go index 03e0224349d7..ceba41f85988 100644 --- a/x/ibc/02-client/types/errors.go +++ b/x/ibc/02-client/types/errors.go @@ -23,6 +23,4 @@ var ( ErrFailedPacketAckVerification = sdkerrors.Register(SubModuleName, 17, "packet acknowledgement verification failed") ErrFailedPacketAckAbsenceVerification = sdkerrors.Register(SubModuleName, 18, "packet acknowledgement absence verification failed") ErrFailedNextSeqRecvVerification = sdkerrors.Register(SubModuleName, 19, "next sequence receive verification failed") - ErrInvalidTrustingPeriod = sdkerrors.Register(SubModuleName, 20, "invalid trusting period") - ErrInvalidUnbondingPeriod = sdkerrors.Register(SubModuleName, 21, "invalid unbonding period") ) diff --git a/x/ibc/02-client/types/events.go b/x/ibc/02-client/types/events.go index ea0dcc7d6606..9692cd389232 100644 --- a/x/ibc/02-client/types/events.go +++ b/x/ibc/02-client/types/events.go @@ -14,9 +14,9 @@ const ( // IBC client events vars var ( - EventTypeCreateClient = TypeMsgCreateClient - EventTypeUpdateClient = TypeMsgUpdateClient - EventTypeSubmitMisbehaviour = TypeClientMisbehaviour + EventTypeCreateClient = "create_client" + EventTypeUpdateClient = "update_client" + EventTypeSubmitMisbehaviour = "client_misbehaviour" AttributeValueCategory = fmt.Sprintf("%s_%s", ibctypes.ModuleName, SubModuleName) ) diff --git a/x/ibc/02-client/types/msgs_test.go b/x/ibc/02-client/types/msgs_test.go deleted file mode 100644 index b529836b51b6..000000000000 --- a/x/ibc/02-client/types/msgs_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package types_test - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/tendermint/tendermint/crypto/secp256k1" - tmtypes "github.com/tendermint/tendermint/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" -) - -const ( - trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 - ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 -) - -func TestMsgCreateClientValidateBasic(t *testing.T) { - validator := tmtypes.NewValidator(tmtypes.NewMockPV().GetPubKey(), 1) - valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - - now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) - cs := tendermint.ConsensusState{ - Timestamp: now, - Root: commitment.NewRoot([]byte("root")), - ValidatorSet: valSet, - } - privKey := secp256k1.GenPrivKey() - signer := sdk.AccAddress(privKey.PubKey().Address()) - - cases := []struct { - msg types.MsgCreateClient - expPass bool - errMsg string - }{ - {types.NewMsgCreateClient(exported.ClientTypeTendermint, exported.ClientTypeTendermint, cs, trustingPeriod, ubdPeriod, signer), true, "success msg should pass"}, - {types.NewMsgCreateClient("BADCHAIN", exported.ClientTypeTendermint, cs, trustingPeriod, ubdPeriod, signer), false, "invalid client id passed"}, - {types.NewMsgCreateClient("goodchain", "invalid_client_type", cs, trustingPeriod, ubdPeriod, signer), false, "unregistered client type passed"}, - {types.NewMsgCreateClient("goodchain", exported.ClientTypeTendermint, nil, trustingPeriod, ubdPeriod, signer), false, "nil Consensus State in msg passed"}, - {types.NewMsgCreateClient("goodchain", exported.ClientTypeTendermint, tendermint.ConsensusState{}, trustingPeriod, ubdPeriod, signer), false, "invalid Consensus State in msg passed"}, - {types.NewMsgCreateClient("goodchain", exported.ClientTypeTendermint, cs, 0, ubdPeriod, signer), false, "zero trusting period passed"}, - {types.NewMsgCreateClient("goodchain", exported.ClientTypeTendermint, cs, trustingPeriod, 0, signer), false, "zero unbonding period passed"}, - {types.NewMsgCreateClient("goodchain", exported.ClientTypeTendermint, cs, trustingPeriod, ubdPeriod, nil), false, "Empty address passed"}, - } - - for i, tc := range cases { - err := tc.msg.ValidateBasic() - if tc.expPass { - require.NoError(t, err, "Msg %d failed: %v", i, err) - } else { - require.Error(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) - } - } -} - -func TestMsgUpdateClient(t *testing.T) { - privKey := secp256k1.GenPrivKey() - signer := sdk.AccAddress(privKey.PubKey().Address()) - - cases := []struct { - msg types.MsgUpdateClient - expPass bool - errMsg string - }{ - {types.NewMsgUpdateClient(exported.ClientTypeTendermint, tendermint.Header{}, signer), true, "success msg should pass"}, - {types.NewMsgUpdateClient("badClient", tendermint.Header{}, signer), false, "invalid client id passed"}, - {types.NewMsgUpdateClient(exported.ClientTypeTendermint, nil, signer), false, "Nil Header passed"}, - {types.NewMsgUpdateClient(exported.ClientTypeTendermint, tendermint.Header{}, nil), false, "Empty address passed"}, - } - - for i, tc := range cases { - err := tc.msg.ValidateBasic() - if tc.expPass { - require.NoError(t, err, "Msg %d failed: %v", i, err) - } else { - require.Error(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) - } - } -} diff --git a/x/ibc/03-connection/keeper/keeper_test.go b/x/ibc/03-connection/keeper/keeper_test.go index 3163496c4af7..3ddfaf5a52ff 100644 --- a/x/ibc/03-connection/keeper/keeper_test.go +++ b/x/ibc/03-connection/keeper/keeper_test.go @@ -20,7 +20,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" "github.com/cosmos/cosmos-sdk/x/staking" @@ -30,7 +30,6 @@ const ( clientType = clientexported.Tendermint storeKey = ibctypes.StoreKey chainID = "gaia" - testHeight = 10 testClientID1 = "testclientidone" testConnectionID1 = "connectionidone" @@ -45,6 +44,8 @@ const ( ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 ) +var testHeight uint64 + type KeeperTestSuite struct { suite.Suite @@ -53,11 +54,12 @@ type KeeperTestSuite struct { app *simapp.SimApp valSet *tmtypes.ValidatorSet consensusState clientexported.ConsensusState - header tendermint.Header + header ibctmtypes.Header now time.Time } func (suite *KeeperTestSuite) SetupTest() { + testHeight = 1 isCheckTx := false app := simapp.Setup(isCheckTx) suite.now = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) @@ -69,8 +71,9 @@ func (suite *KeeperTestSuite) SetupTest() { privVal := tmtypes.NewMockPV() validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - suite.header = tendermint.CreateTestHeader(chainID, testHeight, now2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{privVal}) - suite.consensusState = tendermint.ConsensusState{ + suite.header = ibctmtypes.CreateTestHeader(chainID, int64(testHeight), now2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{privVal}) + suite.consensusState = ibctmtypes.ConsensusState{ + Height: testHeight, Timestamp: suite.now, Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.valSet, @@ -112,14 +115,18 @@ func (suite *KeeperTestSuite) createClient(clientID string) { suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1, Time: suite.now}}) suite.ctx = suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 1) + testHeight++ - consensusState := tendermint.ConsensusState{ + consensusState := ibctmtypes.ConsensusState{ + Height: testHeight, Timestamp: suite.now, Root: commitment.NewRoot(commitID.Hash), ValidatorSet: suite.valSet, } - _, err := suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientID, clientType, consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(clientID, clientID, consensusState, trustingPeriod, ubdPeriod) + suite.Require().NoError(err) + _, err = suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientState, consensusState) suite.Require().NoError(err) // _, _, err := simapp.SignCheckDeliver( @@ -142,8 +149,10 @@ func (suite *KeeperTestSuite) updateClient(clientID string) { suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1, Time: suite.now}}) suite.ctx = suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 1) + testHeight++ - consensusState := tendermint.ConsensusState{ + consensusState := ibctmtypes.ConsensusState{ + Height: testHeight, Timestamp: suite.now, Root: commitment.NewRoot(commitID.Hash), ValidatorSet: suite.valSet, @@ -153,7 +162,7 @@ func (suite *KeeperTestSuite) updateClient(clientID string) { suite.ctx, clientID, uint64(suite.app.LastBlockHeight()), consensusState, ) suite.app.IBCKeeper.ClientKeeper.SetClientState( - suite.ctx, tendermint.NewClientState(clientID, trustingPeriod, ubdPeriod, uint64(suite.app.LastBlockHeight()), suite.now), + suite.ctx, ibctmtypes.NewClientState(clientID, clientID, trustingPeriod, ubdPeriod, uint64(suite.app.LastBlockHeight()), suite.now), ) // _, _, err := simapp.SignCheckDeliver( diff --git a/x/ibc/04-channel/keeper/handshake_test.go b/x/ibc/04-channel/keeper/handshake_test.go index aee68d6cd00c..59c42ca40d9f 100644 --- a/x/ibc/04-channel/keeper/handshake_test.go +++ b/x/ibc/04-channel/keeper/handshake_test.go @@ -101,14 +101,14 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenTry( suite.ctx, exported.ORDERED, []string{testConnectionID2}, testPort2, testChannel2, counterparty, testChannelVersion, testChannelVersion, - validProof{}, uint64(suite.ctx.BlockHeight()), + validProof{}, uint64(testHeight), ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenTry( suite.ctx, exported.ORDERED, []string{testConnectionID2}, testPort2, testChannel2, counterparty, testChannelVersion, testChannelVersion, - invalidProof{}, uint64(suite.ctx.BlockHeight()), + invalidProof{}, uint64(testHeight), ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } @@ -184,13 +184,13 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { if tc.expPass { err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenAck( suite.ctx, testPort1, testChannel1, testChannelVersion, - validProof{}, uint64(suite.ctx.BlockHeight()), + validProof{}, uint64(testHeight), ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenAck( suite.ctx, testPort1, testChannel1, testChannelVersion, - invalidProof{}, uint64(suite.ctx.BlockHeight()), + invalidProof{}, uint64(testHeight), ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } @@ -266,13 +266,13 @@ func (suite *KeeperTestSuite) TestChanOpenConfirm() { if tc.expPass { err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenConfirm( suite.ctx, testPort2, testChannel2, - validProof{}, uint64(suite.ctx.BlockHeight()), + validProof{}, uint64(testHeight), ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenConfirm( suite.ctx, testPort2, testChannel2, - invalidProof{}, uint64(suite.ctx.BlockHeight()), + invalidProof{}, uint64(testHeight), ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } @@ -404,13 +404,13 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() { if tc.expPass { err := suite.app.IBCKeeper.ChannelKeeper.ChanCloseConfirm( suite.ctx, testPort2, testChannel2, - validProof{}, uint64(suite.ctx.BlockHeight()), + validProof{}, uint64(testHeight), ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { err := suite.app.IBCKeeper.ChannelKeeper.ChanCloseConfirm( suite.ctx, testPort2, testChannel2, - invalidProof{}, uint64(suite.ctx.BlockHeight()), + invalidProof{}, uint64(testHeight), ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } diff --git a/x/ibc/04-channel/keeper/keeper_test.go b/x/ibc/04-channel/keeper/keeper_test.go index f618f6fc27e0..58bc96c5f05c 100644 --- a/x/ibc/04-channel/keeper/keeper_test.go +++ b/x/ibc/04-channel/keeper/keeper_test.go @@ -18,7 +18,8 @@ import ( connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -44,6 +45,8 @@ const ( testChannelOrder = exported.ORDERED testChannelVersion = "1.0" + testHeight = 10 + trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 ) @@ -203,12 +206,15 @@ func (suite *KeeperTestSuite) createClient(clientID string) { suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{Height: suite.app.LastBlockHeight()}) - consensusState := tendermint.ConsensusState{ + consensusState := ibctmtypes.ConsensusState{ + Height: testHeight, Root: commitment.NewRoot(commitID.Hash), ValidatorSet: suite.valSet, } - _, err := suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientID, testClientType, consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(clientID, clientID, consensusState, trustingPeriod, ubdPeriod) + suite.Require().NoError(err) + _, err = suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientState, consensusState) suite.Require().NoError(err) } @@ -222,13 +228,13 @@ func (suite *KeeperTestSuite) updateClient() { suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: height}}) suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{Height: suite.app.LastBlockHeight()}) - state := tendermint.ConsensusState{ + state := ibctmtypes.ConsensusState{ Root: commitment.NewRoot(commitID.Hash), } suite.app.IBCKeeper.ClientKeeper.SetClientConsensusState(suite.ctx, testClientID1, uint64(height-1), state) csi, _ := suite.app.IBCKeeper.ClientKeeper.GetClientState(suite.ctx, testClientID1) - cs, _ := csi.(tendermint.ClientState) + cs, _ := csi.(ibctmtypes.ClientState) cs.LatestHeight = uint64(height - 1) suite.app.IBCKeeper.ClientKeeper.SetClientState(suite.ctx, cs) } diff --git a/x/ibc/07-tendermint/client/cli/cli.go b/x/ibc/07-tendermint/client/cli/cli.go new file mode 100644 index 000000000000..e25dd98536ed --- /dev/null +++ b/x/ibc/07-tendermint/client/cli/cli.go @@ -0,0 +1,26 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" +) + +// GetTxCmd returns the transaction commands for IBC clients +func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command { + ics07TendermintTxCmd := &cobra.Command{ + Use: "tendermint", + Short: "Tendermint transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + ics07TendermintTxCmd.AddCommand(flags.PostCommands( + GetCmdCreateClient(cdc), + GetCmdUpdateClient(cdc), + GetCmdSubmitMisbehaviour(cdc), + )...) + + return ics07TendermintTxCmd +} diff --git a/x/ibc/02-client/client/cli/tx.go b/x/ibc/07-tendermint/client/cli/tx.go similarity index 89% rename from x/ibc/02-client/client/cli/tx.go rename to x/ibc/07-tendermint/client/cli/tx.go index 78d3973c53b7..58931f5bf97f 100644 --- a/x/ibc/02-client/client/cli/tx.go +++ b/x/ibc/07-tendermint/client/cli/tx.go @@ -20,15 +20,14 @@ import ( authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/evidence" evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" ) // GetCmdCreateClient defines the command to create a new IBC Client as defined // in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "create [client-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period]", + Use: "create [client-id] [chain-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period]", Short: "create new client with a consensus state", Long: strings.TrimSpace(fmt.Sprintf(`create new client with a specified identifier and consensus state: @@ -43,11 +42,12 @@ $ %s tx ibc client create [client-id] [path/to/consensus_state.json] [trusting_p cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) clientID := args[0] + chainID := args[1] - var state exported.ConsensusState - if err := cdc.UnmarshalJSON([]byte(args[1]), &state); err != nil { + var state ibctmtypes.ConsensusState + if err := cdc.UnmarshalJSON([]byte(args[2]), &state); err != nil { // check for file path if JSON input is not provided - contents, err := ioutil.ReadFile(args[1]) + contents, err := ioutil.ReadFile(args[2]) if err != nil { return errors.New("neither JSON input nor path to .json file were provided") } @@ -56,18 +56,18 @@ $ %s tx ibc client create [client-id] [path/to/consensus_state.json] [trusting_p } } - trustingPeriod, err := time.ParseDuration(args[2]) + trustingPeriod, err := time.ParseDuration(args[3]) if err != nil { return err } - ubdPeriod, err := time.ParseDuration(args[3]) + ubdPeriod, err := time.ParseDuration(args[4]) if err != nil { return err } - msg := types.NewMsgCreateClient( - clientID, state.ClientType().String(), state, + msg := ibctmtypes.NewMsgCreateClient( + clientID, chainID, state, trustingPeriod, ubdPeriod, cliCtx.GetFromAddress(), ) @@ -101,7 +101,7 @@ $ %s tx ibc client update [client-id] [path/to/header.json] --from node0 --home clientID := args[0] - var header exported.Header + var header ibctmtypes.Header if err := cdc.UnmarshalJSON([]byte(args[1]), &header); err != nil { // check for file path if JSON input is not provided contents, err := ioutil.ReadFile(args[1]) @@ -113,7 +113,7 @@ $ %s tx ibc client update [client-id] [path/to/header.json] --from node0 --home } } - msg := types.NewMsgUpdateClient(clientID, header, cliCtx.GetFromAddress()) + msg := ibctmtypes.NewMsgUpdateClient(clientID, header, cliCtx.GetFromAddress()) if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/ibc/07-tendermint/client/rest/rest.go b/x/ibc/07-tendermint/client/rest/rest.go new file mode 100644 index 000000000000..c483329e14b2 --- /dev/null +++ b/x/ibc/07-tendermint/client/rest/rest.go @@ -0,0 +1,45 @@ +package rest + +import ( + "time" + + "github.com/gorilla/mux" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/types/rest" + evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +// REST client flags +const ( + RestClientID = "client-id" + RestRootHeight = "height" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) { + registerTxRoutes(cliCtx, r) +} + +// CreateClientReq defines the properties of a create client request's body. +type CreateClientReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + ClientID string `json:"client_id" yaml:"client_id"` + ChainID string `json:"chain_id" yaml:"chain_id"` + ConsensusState ibctmtypes.ConsensusState `json:"consensus_state" yaml:"consensus_state"` + TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` + UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"` +} + +// UpdateClientReq defines the properties of a update client request's body. +type UpdateClientReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Header ibctmtypes.Header `json:"header" yaml:"header"` +} + +// SubmitMisbehaviourReq defines the properties of a submit misbehaviour request's body. +type SubmitMisbehaviourReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Evidence evidenceexported.Evidence `json:"evidence" yaml:"evidence"` +} diff --git a/x/ibc/07-tendermint/client/rest/swagger.go b/x/ibc/07-tendermint/client/rest/swagger.go new file mode 100644 index 000000000000..34d5f30af8c7 --- /dev/null +++ b/x/ibc/07-tendermint/client/rest/swagger.go @@ -0,0 +1,31 @@ +package rest + +import ( + auth "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/evidence" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +// nolint +type ( + PostCreateClient struct { + Msgs []ibctmtypes.MsgCreateClient `json:"msg" yaml:"msg"` + Fee auth.StdFee `json:"fee" yaml:"fee"` + Signatures []auth.StdSignature `json:"signatures" yaml:"signatures"` + Memo string `json:"memo" yaml:"memo"` + } + + PostUpdateClient struct { + Msgs []ibctmtypes.MsgUpdateClient `json:"msg" yaml:"msg"` + Fee auth.StdFee `json:"fee" yaml:"fee"` + Signatures []auth.StdSignature `json:"signatures" yaml:"signatures"` + Memo string `json:"memo" yaml:"memo"` + } + + PostSubmitMisbehaviour struct { + Msgs []evidence.MsgSubmitEvidence `json:"msg" yaml:"msg"` + Fee auth.StdFee `json:"fee" yaml:"fee"` + Signatures []auth.StdSignature `json:"signatures" yaml:"signatures"` + Memo string `json:"memo" yaml:"memo"` + } +) diff --git a/x/ibc/02-client/client/rest/tx.go b/x/ibc/07-tendermint/client/rest/tx.go similarity index 96% rename from x/ibc/02-client/client/rest/tx.go rename to x/ibc/07-tendermint/client/rest/tx.go index f1cf87dd4d48..378bedcf9636 100644 --- a/x/ibc/02-client/client/rest/tx.go +++ b/x/ibc/07-tendermint/client/rest/tx.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/evidence" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" ) // RegisterRoutes - Central function to define routes that get registered by the main application @@ -50,9 +50,9 @@ func createClientHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } // create the message - msg := types.NewMsgCreateClient( + msg := ibctmtypes.NewMsgCreateClient( req.ClientID, - req.ConsensusState.ClientType().String(), + req.ChainID, req.ConsensusState, req.TrustingPeriod, req.UnbondingPeriod, fromAddr, @@ -101,7 +101,7 @@ func updateClientHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } // create the message - msg := types.NewMsgUpdateClient( + msg := ibctmtypes.NewMsgUpdateClient( clientID, req.Header, fromAddr, diff --git a/x/ibc/07-tendermint/misbehaviour.go b/x/ibc/07-tendermint/misbehaviour.go index 557d8f855e05..990412f78c9d 100644 --- a/x/ibc/07-tendermint/misbehaviour.go +++ b/x/ibc/07-tendermint/misbehaviour.go @@ -3,12 +3,12 @@ package tendermint import ( "errors" "fmt" - "math" "time" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -26,17 +26,23 @@ func CheckMisbehaviourAndUpdateState( ) (clientexported.ClientState, error) { // cast the interface to specific types before checking for misbehaviour - tmClientState, ok := clientState.(ClientState) + tmClientState, ok := clientState.(types.ClientState) if !ok { return nil, sdkerrors.Wrap(clienttypes.ErrInvalidClientType, "client state type is not Tendermint") } - tmConsensusState, ok := consensusState.(ConsensusState) + // If client is already frozen at earlier height than evidence, return with error + if tmClientState.IsFrozen() && tmClientState.FrozenHeight <= uint64(misbehaviour.GetHeight()) { + return nil, sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, + "client is already frozen at earlier height %d than misbehaviour height %d", tmClientState.FrozenHeight, misbehaviour.GetHeight()) + } + + tmConsensusState, ok := consensusState.(types.ConsensusState) if !ok { return nil, sdkerrors.Wrap(clienttypes.ErrInvalidClientType, "consensus state is not Tendermint") } - tmEvidence, ok := misbehaviour.(Evidence) + tmEvidence, ok := misbehaviour.(types.Evidence) if !ok { return nil, sdkerrors.Wrap(clienttypes.ErrInvalidClientType, "evidence type is not Tendermint") } @@ -47,29 +53,20 @@ func CheckMisbehaviourAndUpdateState( return nil, sdkerrors.Wrap(clienttypes.ErrInvalidEvidence, err.Error()) } - var newFrozenHeight uint64 - if tmClientState.IsFrozen() { - // freeze at an earlier height if another misbehaviour is discovered - newFrozenHeight = uint64(math.Min(float64(tmClientState.FrozenHeight), float64(tmEvidence.GetHeight()))) - } else { - newFrozenHeight = uint64(tmEvidence.GetHeight()) - } - - tmClientState.FrozenHeight = newFrozenHeight - + tmClientState.FrozenHeight = uint64(tmEvidence.GetHeight()) return tmClientState, nil } // checkMisbehaviour checks if the evidence provided is a valid light client misbehaviour func checkMisbehaviour( - clientState ClientState, consensusState ConsensusState, evidence Evidence, + clientState types.ClientState, consensusState types.ConsensusState, evidence types.Evidence, height uint64, currentTimestamp time.Time, ) error { // check if provided height matches the headers' height - if height != uint64(evidence.GetHeight()) { + if height > uint64(evidence.GetHeight()) { return sdkerrors.Wrapf( ibctypes.ErrInvalidHeight, - "height ≠ evidence header height (%d ≠ %d)", height, evidence.GetHeight(), + "height > evidence header height (%d > %d)", height, evidence.GetHeight(), ) } diff --git a/x/ibc/07-tendermint/misbehaviour_test.go b/x/ibc/07-tendermint/misbehaviour_test.go index 789795c97d94..ca72b5cc78d1 100644 --- a/x/ibc/07-tendermint/misbehaviour_test.go +++ b/x/ibc/07-tendermint/misbehaviour_test.go @@ -7,6 +7,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -31,19 +32,19 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() { testCases := []struct { name string - clientState tendermint.ClientState - consensusState tendermint.ConsensusState - evidence tendermint.Evidence + clientState ibctmtypes.ClientState + consensusState ibctmtypes.ConsensusState + evidence ibctmtypes.Evidence height uint64 expPass bool }{ { "valid misbehavior evidence", - tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: 0}, - tendermint.ConsensusState{Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, - tendermint.Evidence{ - Header1: tendermint.CreateTestHeader(chainID, height, suite.now, bothValset, suite.valSet, bothSigners), - Header2: tendermint.CreateTestHeader(chainID, height, suite.now, bothValset, bothValSet, bothSigners), + ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, suite.valSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), ChainID: chainID, ClientID: chainID, }, @@ -51,38 +52,38 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() { true, }, { - "height doesn't match provided evidence", - tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: 0}, - tendermint.ConsensusState{Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, - tendermint.Evidence{ - Header1: tendermint.CreateTestHeader(chainID, height, suite.now, bothValset, suite.valSet, bothSigners), - Header2: tendermint.CreateTestHeader(chainID, height, suite.now, bothValset, bothValSet, bothSigners), + "valid misbehavior at height greater than last consensusState", + ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + ibctmtypes.ConsensusState{Timestamp: suite.now, Height: height - 1, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, suite.valSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), ChainID: chainID, ClientID: chainID, }, - 0, - false, + height - 1, + true, }, { - "consensus state's valset hash different from evidence", - tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: 0}, - tendermint.ConsensusState{Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: suite.valSet}, - tendermint.Evidence{ - Header1: tendermint.CreateTestHeader(chainID, height, suite.now, bothValset, suite.valSet, bothSigners), - Header2: tendermint.CreateTestHeader(chainID, height, suite.now, bothValset, bothValSet, bothSigners), + "consensus state's valset hash different from evidence should still pass", + ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + ibctmtypes.ConsensusState{Timestamp: suite.now, Height: height - 1, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: suite.valSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, suite.valSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), ChainID: chainID, ClientID: chainID, }, - height, - false, + height - 1, + true, }, { "first valset has too much change", - tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: 0}, - tendermint.ConsensusState{Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, - tendermint.Evidence{ - Header1: tendermint.CreateTestHeader(chainID, height, suite.now, altValSet, bothValSet, altSigners), - Header2: tendermint.CreateTestHeader(chainID, height, suite.now, bothValset, bothValSet, bothSigners), + ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, altValSet, bothValSet, altSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), ChainID: chainID, ClientID: chainID, }, @@ -91,11 +92,11 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() { }, { "second valset has too much change", - tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: 0}, - tendermint.ConsensusState{Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, - tendermint.Evidence{ - Header1: tendermint.CreateTestHeader(chainID, height, suite.now, bothValset, bothValSet, bothSigners), - Header2: tendermint.CreateTestHeader(chainID, height, suite.now, altValSet, bothValSet, altSigners), + ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, altValSet, bothValSet, altSigners), ChainID: chainID, ClientID: chainID, }, @@ -104,11 +105,11 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() { }, { "both valsets have too much change", - tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: 0}, - tendermint.ConsensusState{Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, - tendermint.Evidence{ - Header1: tendermint.CreateTestHeader(chainID, height, suite.now, altValSet, altValSet, altSigners), - Header2: tendermint.CreateTestHeader(chainID, height, suite.now, altValSet, bothValSet, altSigners), + ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, altValSet, altValSet, altSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, altValSet, bothValSet, altSigners), ChainID: chainID, ClientID: chainID, }, diff --git a/x/ibc/07-tendermint/module.go b/x/ibc/07-tendermint/module.go new file mode 100644 index 000000000000..4f5b32cea681 --- /dev/null +++ b/x/ibc/07-tendermint/module.go @@ -0,0 +1,29 @@ +package tendermint + +import ( + "fmt" + + "github.com/gorilla/mux" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/client/cli" + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/client/rest" + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +// Name returns the IBC client name +func Name() string { + return types.SubModuleName +} + +// RegisterRESTRoutes registers the REST routes for the IBC client +func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router, queryRoute string) { + rest.RegisterRoutes(ctx, rtr, fmt.Sprintf("%s/%s", queryRoute, types.SubModuleName)) +} + +// GetTxCmd returns the root tx command for the IBC client +func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command { + return cli.GetTxCmd(cdc, fmt.Sprintf("%s/%s", storeKey, types.SubModuleName)) +} diff --git a/x/ibc/07-tendermint/tendermint_test.go b/x/ibc/07-tendermint/tendermint_test.go index 02090e6acd5e..9c846c50fb3a 100644 --- a/x/ibc/07-tendermint/tendermint_test.go +++ b/x/ibc/07-tendermint/tendermint_test.go @@ -9,7 +9,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/codec" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -23,24 +23,28 @@ const ( type TendermintTestSuite struct { suite.Suite - cdc *codec.Codec - privVal tmtypes.PrivValidator - valSet *tmtypes.ValidatorSet - header tendermint.Header - now time.Time + cdc *codec.Codec + privVal tmtypes.PrivValidator + valSet *tmtypes.ValidatorSet + header ibctmtypes.Header + now time.Time + clientTime time.Time + headerTime time.Time } func (suite *TendermintTestSuite) SetupTest() { suite.cdc = codec.New() codec.RegisterCrypto(suite.cdc) - tendermint.RegisterCodec(suite.cdc) + ibctmtypes.RegisterCodec(suite.cdc) commitment.RegisterCodec(suite.cdc) - suite.now = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + suite.now = time.Date(2020, 1, 3, 0, 0, 0, 0, time.UTC) + suite.clientTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) + suite.headerTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) suite.privVal = tmtypes.NewMockPV() val := tmtypes.NewValidator(suite.privVal.GetPubKey(), 10) suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val}) - suite.header = tendermint.CreateTestHeader(chainID, height, suite.now, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + suite.header = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) } func TestTendermintTestSuite(t *testing.T) { diff --git a/x/ibc/07-tendermint/client_state.go b/x/ibc/07-tendermint/types/client_state.go similarity index 93% rename from x/ibc/07-tendermint/client_state.go rename to x/ibc/07-tendermint/types/client_state.go index bb5c36b5d7fa..e681d8f7199f 100644 --- a/x/ibc/07-tendermint/client_state.go +++ b/x/ibc/07-tendermint/types/client_state.go @@ -1,4 +1,4 @@ -package tendermint +package types import ( "errors" @@ -23,6 +23,8 @@ var _ clientexported.ClientState = ClientState{} type ClientState struct { // Client ID ID string `json:"id" yaml:"id"` + // Chain ID for Tendermint chain, not guaranteed to be unique + ChainID string `json:"chain_id" yaml:"chain_id"` // Duration of the period since the LastestTimestamp during which the // submitted headers are valid for upgrade TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` @@ -36,34 +38,42 @@ type ClientState struct { FrozenHeight uint64 `json:"frozen_height" yaml:"frozen_height"` } +// InitializeFromMsg creates a tendermint client state from a CreateClientMsg +func InitializeFromMsg( + msg MsgCreateClient, +) (ClientState, error) { + return Initialize(msg.GetClientID(), msg.ChainID, msg.GetConsensusState(), msg.TrustingPeriod, msg.UnbondingPeriod) +} + // Initialize creates a client state and validates its contents, checking that // the provided consensus state is from the same client type. func Initialize( - id string, consensusState clientexported.ConsensusState, trustingPeriod, ubdPeriod time.Duration, - latestHeight uint64, + id string, chainID string, consensusState clientexported.ConsensusState, trustingPeriod, ubdPeriod time.Duration, ) (ClientState, error) { tmConsState, ok := consensusState.(ConsensusState) if !ok { return ClientState{}, errors.New("consensus state is not from Tendermint") } + latestHeight := tmConsState.GetHeight() if trustingPeriod >= ubdPeriod { return ClientState{}, errors.New("trusting period should be < unbonding period") } clientState := NewClientState( - id, trustingPeriod, ubdPeriod, latestHeight, tmConsState.Timestamp, + id, chainID, trustingPeriod, ubdPeriod, latestHeight, tmConsState.Timestamp, ) return clientState, nil } // NewClientState creates a new ClientState instance func NewClientState( - id string, trustingPeriod, ubdPeriod time.Duration, + id string, chainID string, trustingPeriod, ubdPeriod time.Duration, latestHeight uint64, latestTimestamp time.Time, ) ClientState { return ClientState{ ID: id, + ChainID: chainID, TrustingPeriod: trustingPeriod, UnbondingPeriod: ubdPeriod, LatestHeight: latestHeight, diff --git a/x/ibc/07-tendermint/client_state_test.go b/x/ibc/07-tendermint/types/client_state_test.go similarity index 69% rename from x/ibc/07-tendermint/client_state_test.go rename to x/ibc/07-tendermint/types/client_state_test.go index cd283a5ef381..cbb4c9c9e301 100644 --- a/x/ibc/07-tendermint/client_state_test.go +++ b/x/ibc/07-tendermint/types/client_state_test.go @@ -1,11 +1,11 @@ -package tendermint_test +package types_test import ( connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -19,16 +19,16 @@ const ( func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { testCases := []struct { name string - clientState tendermint.ClientState - consensusState tendermint.ConsensusState + clientState ibctmtypes.ClientState + consensusState ibctmtypes.ConsensusState prefix commitment.Prefix proof commitment.Proof expPass bool }{ // { // name: "successful verification", - // clientState: tendermint.NewClientState(chainID, height), - // consensusState: tendermint.ConsensusState{ + // clientState: ibctmtypes.NewClientState(chainID, chainID, height), + // consensusState: ibctmtypes.ConsensusState{ // Root: commitment.NewRoot(suite.header.AppHash), // }, // prefix: commitment.NewPrefix([]byte("ibc")), @@ -36,8 +36,8 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { // }, { name: "ApplyPrefix failed", - clientState: tendermint.NewClientState(chainID, height), - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.Prefix{}, @@ -45,8 +45,8 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { }, { name: "latest client height < height", - clientState: tendermint.NewClientState(chainID, height-1), - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -54,8 +54,8 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { }, { name: "client is frozen", - clientState: tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -63,8 +63,8 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { }, { name: "proof verification failed", - clientState: tendermint.NewClientState(chainID, height), - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.valSet, }, @@ -95,18 +95,18 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() { testCases := []struct { name string - clientState tendermint.ClientState + clientState ibctmtypes.ClientState connection connection.ConnectionEnd - consensusState tendermint.ConsensusState + consensusState ibctmtypes.ConsensusState prefix commitment.Prefix proof commitment.Proof expPass bool }{ // { // name: "successful verification", - // clientState: tendermint.NewClientState(chainID, height), + // clientState: ibctmtypes.NewClientState(chainID, chainID, height), // connection: conn, - // consensusState: tendermint.ConsensusState{ + // consensusState: ibctmtypes.ConsensusState{ // Root: commitment.NewRoot(suite.header.AppHash), // }, // prefix: commitment.NewPrefix([]byte("ibc")), @@ -114,9 +114,9 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() { // }, { name: "ApplyPrefix failed", - clientState: tendermint.NewClientState(chainID, height), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), connection: conn, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.Prefix{}, @@ -124,9 +124,9 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() { }, { name: "latest client height < height", - clientState: tendermint.NewClientState(chainID, height-1), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), connection: conn, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -134,9 +134,9 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() { }, { name: "client is frozen", - clientState: tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, connection: conn, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -144,9 +144,9 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() { }, { name: "proof verification failed", - clientState: tendermint.NewClientState(chainID, height), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), connection: conn, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.valSet, }, @@ -177,18 +177,18 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { testCases := []struct { name string - clientState tendermint.ClientState + clientState ibctmtypes.ClientState channel channel.Channel - consensusState tendermint.ConsensusState + consensusState ibctmtypes.ConsensusState prefix commitment.Prefix proof commitment.Proof expPass bool }{ // { // name: "successful verification", - // clientState: tendermint.NewClientState(chainID, height), + // clientState: ibctmtypes.NewClientState(chainID, height), // connection: conn, - // consensusState: tendermint.ConsensusState{ + // consensusState: ibctmtypes.ConsensusState{ // Root: commitment.NewRoot(suite.header.AppHash), // }, // prefix: commitment.NewPrefix([]byte("ibc")), @@ -196,9 +196,9 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { // }, { name: "ApplyPrefix failed", - clientState: tendermint.NewClientState(chainID, height), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), channel: ch, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.Prefix{}, @@ -206,9 +206,9 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { }, { name: "latest client height < height", - clientState: tendermint.NewClientState(chainID, height-1), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), channel: ch, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -216,9 +216,9 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { }, { name: "client is frozen", - clientState: tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, channel: ch, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -226,9 +226,9 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { }, { name: "proof verification failed", - clientState: tendermint.NewClientState(chainID, height), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), channel: ch, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.valSet, }, @@ -256,18 +256,18 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { testCases := []struct { name string - clientState tendermint.ClientState + clientState ibctmtypes.ClientState commitment []byte - consensusState tendermint.ConsensusState + consensusState ibctmtypes.ConsensusState prefix commitment.Prefix proof commitment.Proof expPass bool }{ // { // name: "successful verification", - // clientState: tendermint.NewClientState(chainID, height), + // clientState: ibctmtypes.NewClientState(chainID, height), // connection: conn, - // consensusState: tendermint.ConsensusState{ + // consensusState: ibctmtypes.ConsensusState{ // Root: commitment.NewRoot(suite.header.AppHash), // }, // prefix: commitment.NewPrefix([]byte("ibc")), @@ -275,9 +275,9 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { // }, { name: "ApplyPrefix failed", - clientState: tendermint.NewClientState(chainID, height), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), commitment: []byte{}, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.Prefix{}, @@ -285,9 +285,9 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { }, { name: "latest client height < height", - clientState: tendermint.NewClientState(chainID, height-1), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), commitment: []byte{}, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -295,9 +295,9 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { }, { name: "client is frozen", - clientState: tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, commitment: []byte{}, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -305,9 +305,9 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { }, { name: "proof verification failed", - clientState: tendermint.NewClientState(chainID, height), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), commitment: []byte{}, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.valSet, }, @@ -335,18 +335,18 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { testCases := []struct { name string - clientState tendermint.ClientState + clientState ibctmtypes.ClientState ack []byte - consensusState tendermint.ConsensusState + consensusState ibctmtypes.ConsensusState prefix commitment.Prefix proof commitment.Proof expPass bool }{ // { // name: "successful verification", - // clientState: tendermint.NewClientState(chainID, height), + // clientState: ibctmtypes.NewClientState(chainID, chainID, height), // connection: conn, - // consensusState: tendermint.ConsensusState{ + // consensusState: ibctmtypes.ConsensusState{ // Root: commitment.NewRoot(suite.header.AppHash), // }, // prefix: commitment.NewPrefix([]byte("ibc")), @@ -354,9 +354,9 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { // }, { name: "ApplyPrefix failed", - clientState: tendermint.NewClientState(chainID, height), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), ack: []byte{}, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.Prefix{}, @@ -364,9 +364,9 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { }, { name: "latest client height < height", - clientState: tendermint.NewClientState(chainID, height-1), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), ack: []byte{}, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -374,9 +374,9 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { }, { name: "client is frozen", - clientState: tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, ack: []byte{}, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -384,9 +384,9 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { }, { name: "proof verification failed", - clientState: tendermint.NewClientState(chainID, height), + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), ack: []byte{}, - consensusState: tendermint.ConsensusState{ + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.valSet, }, @@ -414,17 +414,17 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { testCases := []struct { name string - clientState tendermint.ClientState - consensusState tendermint.ConsensusState + clientState ibctmtypes.ClientState + consensusState ibctmtypes.ConsensusState prefix commitment.Prefix proof commitment.Proof expPass bool }{ // { // name: "successful verification", - // clientState: tendermint.NewClientState(chainID, height), + // clientState: ibctmtypes.NewClientState(chainID, chainID, height), // connection: conn, - // consensusState: tendermint.ConsensusState{ + // consensusState: ibctmtypes.ConsensusState{ // Root: commitment.NewRoot(suite.header.AppHash), // }, // prefix: commitment.NewPrefix([]byte("ibc")), @@ -432,8 +432,8 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { // }, { name: "ApplyPrefix failed", - clientState: tendermint.NewClientState(chainID, height), - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.Prefix{}, @@ -441,8 +441,8 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { }, { name: "latest client height < height", - clientState: tendermint.NewClientState(chainID, height-1), - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -450,8 +450,8 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { }, { name: "client is frozen", - clientState: tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -459,8 +459,8 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { }, { name: "proof verification failed", - clientState: tendermint.NewClientState(chainID, height), - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.valSet, }, @@ -488,17 +488,17 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { testCases := []struct { name string - clientState tendermint.ClientState - consensusState tendermint.ConsensusState + clientState ibctmtypes.ClientState + consensusState ibctmtypes.ConsensusState prefix commitment.Prefix proof commitment.Proof expPass bool }{ // { // name: "successful verification", - // clientState: tendermint.NewClientState(chainID, height), + // clientState: ibctmtypes.NewClientState(chainID, chainID, height), // connection: conn, - // consensusState: tendermint.ConsensusState{ + // consensusState: ibctmtypes.ConsensusState{ // Root: commitment.NewRoot(suite.header.AppHash), // }, // prefix: commitment.NewPrefix([]byte("ibc")), @@ -506,8 +506,8 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { // }, { name: "ApplyPrefix failed", - clientState: tendermint.NewClientState(chainID, height), - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.Prefix{}, @@ -515,8 +515,8 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { }, { name: "latest client height < height", - clientState: tendermint.NewClientState(chainID, height-1), - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -524,8 +524,8 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { }, { name: "client is frozen", - clientState: tendermint.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, prefix: commitment.NewPrefix([]byte("ibc")), @@ -533,8 +533,8 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { }, { name: "proof verification failed", - clientState: tendermint.NewClientState(chainID, height), - consensusState: tendermint.ConsensusState{ + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.valSet, }, diff --git a/x/ibc/07-tendermint/codec.go b/x/ibc/07-tendermint/types/codec.go similarity index 80% rename from x/ibc/07-tendermint/codec.go rename to x/ibc/07-tendermint/types/codec.go index 22c6d508ed6a..61e63c31f603 100644 --- a/x/ibc/07-tendermint/codec.go +++ b/x/ibc/07-tendermint/types/codec.go @@ -1,4 +1,4 @@ -package tendermint +package types import ( "github.com/cosmos/cosmos-sdk/codec" @@ -13,6 +13,8 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(ConsensusState{}, "ibc/client/tendermint/ConsensusState", nil) cdc.RegisterConcrete(Header{}, "ibc/client/tendermint/Header", nil) cdc.RegisterConcrete(Evidence{}, "ibc/client/tendermint/Evidence", nil) + cdc.RegisterConcrete(MsgCreateClient{}, "ibc/client/MsgCreateClient", nil) + cdc.RegisterConcrete(MsgUpdateClient{}, "ibc/client/MsgUpdateClient", nil) SetSubModuleCodec(cdc) } diff --git a/x/ibc/07-tendermint/consensus_state.go b/x/ibc/07-tendermint/types/consensus_state.go similarity index 83% rename from x/ibc/07-tendermint/consensus_state.go rename to x/ibc/07-tendermint/types/consensus_state.go index 01633b118104..cba067f9a918 100644 --- a/x/ibc/07-tendermint/consensus_state.go +++ b/x/ibc/07-tendermint/types/consensus_state.go @@ -1,4 +1,4 @@ -package tendermint +package types import ( "time" @@ -14,6 +14,7 @@ import ( type ConsensusState struct { Timestamp time.Time `json:"timestamp" yaml:"timestamp"` Root commitment.RootI `json:"root" yaml:"root"` + Height uint64 `json:"height" yaml:"height"` ValidatorSet *tmtypes.ValidatorSet `json:"validator_set" yaml:"validator_set"` } @@ -27,6 +28,11 @@ func (cs ConsensusState) GetRoot() commitment.RootI { return cs.Root } +// GetHeight returns the height for the specific consensus state +func (cs ConsensusState) GetHeight() uint64 { + return cs.Height +} + // GetTimestamp returns block time at which the consensus state was stored func (cs ConsensusState) GetTimestamp() time.Time { return cs.Timestamp @@ -40,6 +46,9 @@ func (cs ConsensusState) ValidateBasic() error { if cs.ValidatorSet == nil { return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "validator set cannot be nil") } + if cs.Height == 0 { + return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "height cannot be 0") + } if cs.Timestamp.IsZero() { return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "timestamp cannot be zero Unix time") } diff --git a/x/ibc/07-tendermint/consensus_state_test.go b/x/ibc/07-tendermint/types/consensus_state_test.go similarity index 74% rename from x/ibc/07-tendermint/consensus_state_test.go rename to x/ibc/07-tendermint/types/consensus_state_test.go index 9d7d92936eef..c50be3483e5f 100644 --- a/x/ibc/07-tendermint/consensus_state_test.go +++ b/x/ibc/07-tendermint/types/consensus_state_test.go @@ -1,57 +1,63 @@ -package tendermint_test +package types_test import ( "time" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) func (suite *TendermintTestSuite) TestConsensusStateValidateBasic() { testCases := []struct { msg string - consensusState tendermint.ConsensusState + consensusState ibctmtypes.ConsensusState expectPass bool }{ {"success", - tendermint.ConsensusState{ + ibctmtypes.ConsensusState{ Timestamp: suite.now, + Height: height, Root: commitment.NewRoot([]byte("app_hash")), ValidatorSet: suite.valSet, }, true}, {"root is nil", - tendermint.ConsensusState{ + ibctmtypes.ConsensusState{ Timestamp: suite.now, + Height: height, Root: nil, ValidatorSet: suite.valSet, }, false}, {"root is empty", - tendermint.ConsensusState{ + ibctmtypes.ConsensusState{ Timestamp: suite.now, + Height: height, Root: commitment.Root{}, ValidatorSet: suite.valSet, }, false}, - {"invalid client type", - tendermint.ConsensusState{ + {"valset is nil", + ibctmtypes.ConsensusState{ Timestamp: suite.now, + Height: height, Root: commitment.NewRoot([]byte("app_hash")), - ValidatorSet: suite.valSet, + ValidatorSet: nil, }, false}, - {"valset is nil", - tendermint.ConsensusState{ + {"height is 0", + ibctmtypes.ConsensusState{ Timestamp: suite.now, + Height: 0, Root: commitment.NewRoot([]byte("app_hash")), - ValidatorSet: nil, + ValidatorSet: suite.valSet, }, false}, - {"valset is nil", - tendermint.ConsensusState{ - Timestamp: time.Unix(0, 0), + {"timestamp is zero", + ibctmtypes.ConsensusState{ + Timestamp: time.Time{}, + Height: height, Root: commitment.NewRoot([]byte("app_hash")), ValidatorSet: suite.valSet, }, diff --git a/x/ibc/07-tendermint/types/errors.go b/x/ibc/07-tendermint/types/errors.go new file mode 100644 index 000000000000..1f2bcd48174b --- /dev/null +++ b/x/ibc/07-tendermint/types/errors.go @@ -0,0 +1,15 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const ( + SubModuleName = "tendermint" +) + +var ( + ErrInvalidTrustingPeriod = sdkerrors.Register(SubModuleName, 1, "invalid trusting period") + ErrInvalidUnbondingPeriod = sdkerrors.Register(SubModuleName, 2, "invalid unbonding period") + ErrInvalidChainID = sdkerrors.Register(SubModuleName, 3, "invalid chain ID") +) diff --git a/x/ibc/07-tendermint/evidence.go b/x/ibc/07-tendermint/types/evidence.go similarity index 99% rename from x/ibc/07-tendermint/evidence.go rename to x/ibc/07-tendermint/types/evidence.go index 49d8d3629a5a..d161c10ed5dc 100644 --- a/x/ibc/07-tendermint/evidence.go +++ b/x/ibc/07-tendermint/types/evidence.go @@ -1,4 +1,4 @@ -package tendermint +package types import ( "math" diff --git a/x/ibc/07-tendermint/evidence_test.go b/x/ibc/07-tendermint/types/evidence_test.go similarity index 73% rename from x/ibc/07-tendermint/evidence_test.go rename to x/ibc/07-tendermint/types/evidence_test.go index 4e6eb21f4828..2a7384224896 100644 --- a/x/ibc/07-tendermint/evidence_test.go +++ b/x/ibc/07-tendermint/types/evidence_test.go @@ -1,4 +1,4 @@ -package tendermint_test +package types_test import ( "bytes" @@ -8,15 +8,15 @@ import ( tmtypes "github.com/tendermint/tendermint/types" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" ) func (suite *TendermintTestSuite) TestEvidence() { signers := []tmtypes.PrivValidator{suite.privVal} - ev := tendermint.Evidence{ + ev := ibctmtypes.Evidence{ Header1: suite.header, - Header2: tendermint.CreateTestHeader(chainID, height, suite.now, suite.valSet, suite.valSet, signers), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, suite.valSet, suite.valSet, signers), ChainID: chainID, ClientID: "gaiamainnet", } @@ -25,7 +25,7 @@ func (suite *TendermintTestSuite) TestEvidence() { suite.Require().Equal(ev.GetClientID(), "gaiamainnet") suite.Require().Equal(ev.Route(), "client") suite.Require().Equal(ev.Type(), "client_misbehaviour") - suite.Require().Equal(ev.Hash(), tmbytes.HexBytes(tmhash.Sum(tendermint.SubModuleCdc.MustMarshalBinaryBare(ev)))) + suite.Require().Equal(ev.Hash(), tmbytes.HexBytes(tmhash.Sum(ibctmtypes.SubModuleCdc.MustMarshalBinaryBare(ev)))) suite.Require().Equal(ev.GetHeight(), int64(height)) } @@ -51,85 +51,85 @@ func (suite *TendermintTestSuite) TestEvidenceValidateBasic() { testCases := []struct { name string - evidence tendermint.Evidence - malleateEvidence func(ev *tendermint.Evidence) error + evidence ibctmtypes.Evidence + malleateEvidence func(ev *ibctmtypes.Evidence) error expPass bool }{ { "valid evidence", - tendermint.Evidence{ + ibctmtypes.Evidence{ Header1: suite.header, - Header2: tendermint.CreateTestHeader(chainID, height, suite.now, suite.valSet, bothValSet, signers), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, suite.valSet, bothValSet, signers), ChainID: chainID, ClientID: "gaiamainnet", }, - func(ev *tendermint.Evidence) error { return nil }, + func(ev *ibctmtypes.Evidence) error { return nil }, true, }, { "invalid client ID ", - tendermint.Evidence{ + ibctmtypes.Evidence{ Header1: suite.header, - Header2: tendermint.CreateTestHeader(chainID, height, suite.now, suite.valSet, bothValSet, signers), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, suite.valSet, bothValSet, signers), ChainID: chainID, ClientID: "GAIA", }, - func(ev *tendermint.Evidence) error { return nil }, + func(ev *ibctmtypes.Evidence) error { return nil }, false, }, { "wrong chainID on header1", - tendermint.Evidence{ + ibctmtypes.Evidence{ Header1: suite.header, - Header2: tendermint.CreateTestHeader("ethermint", height, suite.now, suite.valSet, bothValSet, signers), + Header2: ibctmtypes.CreateTestHeader("ethermint", height, suite.now, suite.valSet, bothValSet, signers), ChainID: "ethermint", ClientID: "gaiamainnet", }, - func(ev *tendermint.Evidence) error { return nil }, + func(ev *ibctmtypes.Evidence) error { return nil }, false, }, { "wrong chainID on header2", - tendermint.Evidence{ + ibctmtypes.Evidence{ Header1: suite.header, - Header2: tendermint.CreateTestHeader("ethermint", height, suite.now, suite.valSet, bothValSet, signers), + Header2: ibctmtypes.CreateTestHeader("ethermint", height, suite.now, suite.valSet, bothValSet, signers), ChainID: chainID, ClientID: "gaiamainnet", }, - func(ev *tendermint.Evidence) error { return nil }, + func(ev *ibctmtypes.Evidence) error { return nil }, false, }, { "mismatched heights", - tendermint.Evidence{ + ibctmtypes.Evidence{ Header1: suite.header, - Header2: tendermint.CreateTestHeader(chainID, 6, suite.now, suite.valSet, bothValSet, signers), + Header2: ibctmtypes.CreateTestHeader(chainID, 6, suite.now, suite.valSet, bothValSet, signers), ChainID: chainID, ClientID: "gaiamainnet", }, - func(ev *tendermint.Evidence) error { return nil }, + func(ev *ibctmtypes.Evidence) error { return nil }, false, }, { "same block id", - tendermint.Evidence{ + ibctmtypes.Evidence{ Header1: suite.header, Header2: suite.header, ChainID: chainID, ClientID: "gaiamainnet", }, - func(ev *tendermint.Evidence) error { return nil }, + func(ev *ibctmtypes.Evidence) error { return nil }, false, }, { "header 1 doesn't have 2/3 majority", - tendermint.Evidence{ - Header1: tendermint.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), + ibctmtypes.Evidence{ + Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), Header2: suite.header, ChainID: chainID, ClientID: "gaiamainnet", }, - func(ev *tendermint.Evidence) error { + func(ev *ibctmtypes.Evidence) error { // voteSet contains only altVal which is less than 2/3 of total power (height/1height) wrongVoteSet := tmtypes.NewVoteSet(chainID, ev.Header1.Height, 1, tmtypes.PrecommitType, altValSet) var err error @@ -140,13 +140,13 @@ func (suite *TendermintTestSuite) TestEvidenceValidateBasic() { }, { "header 2 doesn't have 2/3 majority", - tendermint.Evidence{ + ibctmtypes.Evidence{ Header1: suite.header, - Header2: tendermint.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), ChainID: chainID, ClientID: "gaiamainnet", }, - func(ev *tendermint.Evidence) error { + func(ev *ibctmtypes.Evidence) error { // voteSet contains only altVal which is less than 2/3 of total power (height/1height) wrongVoteSet := tmtypes.NewVoteSet(chainID, ev.Header2.Height, 1, tmtypes.PrecommitType, altValSet) var err error @@ -157,14 +157,14 @@ func (suite *TendermintTestSuite) TestEvidenceValidateBasic() { }, { "validators sign off on wrong commit", - tendermint.Evidence{ + ibctmtypes.Evidence{ Header1: suite.header, - Header2: tendermint.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), + Header2: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), ChainID: chainID, ClientID: "gaiamainnet", }, - func(ev *tendermint.Evidence) error { - ev.Header2.Commit.BlockID = tendermint.MakeBlockID(tmhash.Sum([]byte("other_hash")), 3, tmhash.Sum([]byte("other_partset"))) + func(ev *ibctmtypes.Evidence) error { + ev.Header2.Commit.BlockID = ibctmtypes.MakeBlockID(tmhash.Sum([]byte("other_hash")), 3, tmhash.Sum([]byte("other_partset"))) return nil }, false, diff --git a/x/ibc/07-tendermint/header.go b/x/ibc/07-tendermint/types/header.go similarity index 99% rename from x/ibc/07-tendermint/header.go rename to x/ibc/07-tendermint/types/header.go index 306e4fb9dabd..bc426a24ac5b 100644 --- a/x/ibc/07-tendermint/header.go +++ b/x/ibc/07-tendermint/types/header.go @@ -1,4 +1,4 @@ -package tendermint +package types import ( abci "github.com/tendermint/tendermint/abci/types" diff --git a/x/ibc/07-tendermint/header_test.go b/x/ibc/07-tendermint/types/header_test.go similarity index 80% rename from x/ibc/07-tendermint/header_test.go rename to x/ibc/07-tendermint/types/header_test.go index e88362d230d3..c5c004028a7f 100644 --- a/x/ibc/07-tendermint/header_test.go +++ b/x/ibc/07-tendermint/types/header_test.go @@ -1,20 +1,20 @@ -package tendermint_test +package types_test import ( clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" ) func (suite *TendermintTestSuite) TestHeaderValidateBasic() { testCases := []struct { name string - header tendermint.Header + header ibctmtypes.Header chainID string expPass bool }{ {"valid header", suite.header, chainID, true}, {"signed header basic validation failed", suite.header, "chainID", false}, - {"validator set nil", tendermint.Header{suite.header.SignedHeader, nil}, chainID, false}, + {"validator set nil", ibctmtypes.Header{suite.header.SignedHeader, nil}, chainID, false}, } suite.Require().Equal(clientexported.Tendermint, suite.header.ClientType()) diff --git a/x/ibc/02-client/types/msgs.go b/x/ibc/07-tendermint/types/msgs.go similarity index 60% rename from x/ibc/02-client/types/msgs.go rename to x/ibc/07-tendermint/types/msgs.go index ba9fe9169ec5..cc065a6ec308 100644 --- a/x/ibc/02-client/types/msgs.go +++ b/x/ibc/07-tendermint/types/msgs.go @@ -1,11 +1,13 @@ package types import ( + "strings" "time" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -17,26 +19,27 @@ const ( TypeClientMisbehaviour string = "client_misbehaviour" ) -var _ sdk.Msg = MsgCreateClient{} +var _ clientexported.MsgCreateClient = MsgCreateClient{} +var _ clientexported.MsgUpdateClient = MsgUpdateClient{} // MsgCreateClient defines a message to create an IBC client type MsgCreateClient struct { - ClientID string `json:"client_id" yaml:"client_id"` - ClientType string `json:"client_type" yaml:"client_type"` - ConsensusState exported.ConsensusState `json:"consensus_state" yaml:"consensus_address"` - TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` - UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"` - Signer sdk.AccAddress `json:"address" yaml:"address"` + ClientID string `json:"client_id" yaml:"client_id"` + ChainID string `json:"chain_id" yaml:"chain_id"` + ConsensusState ConsensusState `json:"consensus_state" yaml:"consensus_state"` + TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` + UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"` + Signer sdk.AccAddress `json:"address" yaml:"address"` } // NewMsgCreateClient creates a new MsgCreateClient instance func NewMsgCreateClient( - id, clientType string, consensusState exported.ConsensusState, + id string, chainID string, consensusState ConsensusState, trustingPeriod, unbondingPeriod time.Duration, signer sdk.AccAddress, ) MsgCreateClient { return MsgCreateClient{ ClientID: id, - ClientType: clientType, + ChainID: chainID, ConsensusState: consensusState, TrustingPeriod: trustingPeriod, UnbondingPeriod: unbondingPeriod, @@ -56,11 +59,8 @@ func (msg MsgCreateClient) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgCreateClient) ValidateBasic() error { - if clientType := exported.ClientTypeFromString(msg.ClientType); clientType == 0 { - return sdkerrors.Wrap(ErrInvalidClientType, msg.ClientType) - } - if msg.ConsensusState == nil { - return ErrInvalidConsensus + if strings.TrimSpace(msg.ChainID) == "" { + return sdkerrors.Wrap(ErrInvalidChainID, "cannot have empty chain-id") } if err := msg.ConsensusState.ValidateBasic(); err != nil { return err @@ -87,17 +87,30 @@ func (msg MsgCreateClient) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } -var _ sdk.Msg = MsgUpdateClient{} +// GetClientID implements clientexported.MsgCreateClient +func (msg MsgCreateClient) GetClientID() string { + return msg.ClientID +} + +// GetClientType implements clientexported.MsgCreateClient +func (msg MsgCreateClient) GetClientType() string { + return clientexported.ClientTypeTendermint +} + +// GetConsensusState implements clientexported.MsgCreateClient +func (msg MsgCreateClient) GetConsensusState() clientexported.ConsensusState { + return msg.ConsensusState +} // MsgUpdateClient defines a message to update an IBC client type MsgUpdateClient struct { - ClientID string `json:"client_id" yaml:"client_id"` - Header exported.Header `json:"header" yaml:"header"` - Signer sdk.AccAddress `json:"address" yaml:"address"` + ClientID string `json:"client_id" yaml:"client_id"` + Header Header `json:"header" yaml:"header"` + Signer sdk.AccAddress `json:"address" yaml:"address"` } // NewMsgUpdateClient creates a new MsgUpdateClient instance -func NewMsgUpdateClient(id string, header exported.Header, signer sdk.AccAddress) MsgUpdateClient { +func NewMsgUpdateClient(id string, header Header, signer sdk.AccAddress) MsgUpdateClient { return MsgUpdateClient{ ClientID: id, Header: header, @@ -117,9 +130,6 @@ func (msg MsgUpdateClient) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgUpdateClient) ValidateBasic() error { - if msg.Header == nil { - return ErrInvalidHeader - } if msg.Signer.Empty() { return sdkerrors.ErrInvalidAddress } @@ -135,3 +145,13 @@ func (msg MsgUpdateClient) GetSignBytes() []byte { func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Signer} } + +// GetClientID implements clientexported.MsgUpdateClient +func (msg MsgUpdateClient) GetClientID() string { + return msg.ClientID +} + +// GetHeader implements clientexported.MsgUpdateClient +func (msg MsgUpdateClient) GetHeader() clientexported.Header { + return msg.Header +} diff --git a/x/ibc/07-tendermint/types/msgs_test.go b/x/ibc/07-tendermint/types/msgs_test.go new file mode 100644 index 000000000000..6ea7eac33828 --- /dev/null +++ b/x/ibc/07-tendermint/types/msgs_test.go @@ -0,0 +1,80 @@ +package types_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/crypto/secp256k1" + tmtypes "github.com/tendermint/tendermint/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +func TestMsgCreateClientValidateBasic(t *testing.T) { + validator := tmtypes.NewValidator(tmtypes.NewMockPV().GetPubKey(), 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + + now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + cs := ibctmtypes.ConsensusState{ + Height: height, + Timestamp: now, + Root: commitment.NewRoot([]byte("root")), + ValidatorSet: valSet, + } + privKey := secp256k1.GenPrivKey() + signer := sdk.AccAddress(privKey.PubKey().Address()) + chainID := "gaia" + + cases := []struct { + msg ibctmtypes.MsgCreateClient + expPass bool + errMsg string + }{ + {ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, chainID, cs, trustingPeriod, ubdPeriod, signer), true, "success msg should pass"}, + {ibctmtypes.NewMsgCreateClient("BADCHAIN", chainID, cs, trustingPeriod, ubdPeriod, signer), false, "invalid client id passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", chainID, cs, trustingPeriod, ubdPeriod, signer), false, "unregistered client type passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", chainID, ibctmtypes.ConsensusState{}, trustingPeriod, ubdPeriod, signer), false, "invalid Consensus State in msg passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", chainID, cs, 0, ubdPeriod, signer), false, "zero trusting period passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", chainID, cs, trustingPeriod, 0, signer), false, "zero unbonding period passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", chainID, cs, trustingPeriod, ubdPeriod, nil), false, "Empty address passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", "", cs, trustingPeriod, ubdPeriod, nil), false, "Empty chain ID"}, + } + + for i, tc := range cases { + err := tc.msg.ValidateBasic() + if tc.expPass { + require.NoError(t, err, "Msg %d failed: %v", i, err) + } else { + require.Error(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} + +func TestMsgUpdateClient(t *testing.T) { + privKey := secp256k1.GenPrivKey() + signer := sdk.AccAddress(privKey.PubKey().Address()) + + cases := []struct { + msg ibctmtypes.MsgUpdateClient + expPass bool + errMsg string + }{ + {ibctmtypes.NewMsgUpdateClient(exported.ClientTypeTendermint, ibctmtypes.Header{}, signer), true, "success msg should pass"}, + {ibctmtypes.NewMsgUpdateClient("badClient", ibctmtypes.Header{}, signer), false, "invalid client id passed"}, + {ibctmtypes.NewMsgUpdateClient(exported.ClientTypeTendermint, ibctmtypes.Header{}, nil), false, "Empty address passed"}, + } + + for i, tc := range cases { + err := tc.msg.ValidateBasic() + if tc.expPass { + require.NoError(t, err, "Msg %d failed: %v", i, err) + } else { + require.Error(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) + } + } +} diff --git a/x/ibc/07-tendermint/types/tendermint_test.go b/x/ibc/07-tendermint/types/tendermint_test.go new file mode 100644 index 000000000000..d4d71cc91ce2 --- /dev/null +++ b/x/ibc/07-tendermint/types/tendermint_test.go @@ -0,0 +1,48 @@ +package types_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" +) + +const ( + chainID = "gaia" + height = 4 + trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 + ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 +) + +type TendermintTestSuite struct { + suite.Suite + + cdc *codec.Codec + privVal tmtypes.PrivValidator + valSet *tmtypes.ValidatorSet + header ibctmtypes.Header + now time.Time +} + +func (suite *TendermintTestSuite) SetupTest() { + suite.cdc = codec.New() + codec.RegisterCrypto(suite.cdc) + ibctmtypes.RegisterCodec(suite.cdc) + commitment.RegisterCodec(suite.cdc) + + suite.now = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + suite.privVal = tmtypes.NewMockPV() + val := tmtypes.NewValidator(suite.privVal.GetPubKey(), 10) + suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val}) + suite.header = ibctmtypes.CreateTestHeader(chainID, height, suite.now, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) +} + +func TestTendermintTestSuite(t *testing.T) { + suite.Run(t, new(TendermintTestSuite)) +} diff --git a/x/ibc/07-tendermint/test_utils.go b/x/ibc/07-tendermint/types/test_utils.go similarity index 99% rename from x/ibc/07-tendermint/test_utils.go rename to x/ibc/07-tendermint/types/test_utils.go index 9ae1d86069bb..bd538bc4871b 100644 --- a/x/ibc/07-tendermint/test_utils.go +++ b/x/ibc/07-tendermint/types/test_utils.go @@ -1,4 +1,4 @@ -package tendermint +package types import ( "math" diff --git a/x/ibc/07-tendermint/update.go b/x/ibc/07-tendermint/update.go index c3530d461e02..b9bfebca401c 100644 --- a/x/ibc/07-tendermint/update.go +++ b/x/ibc/07-tendermint/update.go @@ -7,6 +7,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) @@ -20,24 +21,24 @@ import ( // Tendermint client validity checking uses the bisection algorithm described // in the [Tendermint spec](https://github.com/tendermint/spec/blob/master/spec/consensus/light-client.md). func CheckValidityAndUpdateState( - clientState clientexported.ClientState, header clientexported.Header, chainID string, + clientState clientexported.ClientState, header clientexported.Header, currentTimestamp time.Time, ) (clientexported.ClientState, clientexported.ConsensusState, error) { - tmClientState, ok := clientState.(ClientState) + tmClientState, ok := clientState.(types.ClientState) if !ok { return nil, nil, sdkerrors.Wrap( clienttypes.ErrInvalidClientType, "light client is not from Tendermint", ) } - tmHeader, ok := header.(Header) + tmHeader, ok := header.(types.Header) if !ok { return nil, nil, sdkerrors.Wrap( clienttypes.ErrInvalidHeader, "header is not from Tendermint", ) } - if err := checkValidity(tmClientState, tmHeader, chainID, currentTimestamp); err != nil { + if err := checkValidity(tmClientState, tmHeader, currentTimestamp); err != nil { return nil, nil, err } @@ -49,7 +50,7 @@ func CheckValidityAndUpdateState( // // CONTRACT: assumes header.Height > consensusState.Height func checkValidity( - clientState ClientState, header Header, chainID string, currentTimestamp time.Time, + clientState types.ClientState, header types.Header, currentTimestamp time.Time, ) error { // assert trusting period has not yet passed if currentTimestamp.Sub(clientState.LatestTimestamp) >= clientState.TrustingPeriod { @@ -82,7 +83,7 @@ func checkValidity( } // basic consistency check - if err := header.ValidateBasic(chainID); err != nil { + if err := header.ValidateBasic(clientState.ChainID); err != nil { return err } @@ -90,9 +91,9 @@ func checkValidity( } // update the consensus state from a new header -func update(clientState ClientState, header Header) (ClientState, ConsensusState) { +func update(clientState types.ClientState, header types.Header) (types.ClientState, types.ConsensusState) { clientState.LatestHeight = header.GetHeight() - consensusState := ConsensusState{ + consensusState := types.ConsensusState{ Timestamp: header.Time, Root: commitment.NewRoot(header.AppHash), ValidatorSet: header.ValidatorSet, diff --git a/x/ibc/07-tendermint/update_test.go b/x/ibc/07-tendermint/update_test.go index 7b9bb3a74a16..5c465c398335 100644 --- a/x/ibc/07-tendermint/update_test.go +++ b/x/ibc/07-tendermint/update_test.go @@ -2,32 +2,29 @@ package tendermint_test import ( tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) func (suite *TendermintTestSuite) TestCheckValidity() { testCases := []struct { name string - clientState tendermint.ClientState - chainID string + clientState ibctmtypes.ClientState expPass bool }{ { name: "successful update", - clientState: tendermint.NewClientState(chainID, trustingPeriod, ubdPeriod, height, suite.now), - chainID: chainID, + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.clientTime), expPass: true, }, { name: "header basic validation failed", - clientState: tendermint.NewClientState(chainID, trustingPeriod, ubdPeriod, height, suite.now), - chainID: "cosmoshub", + clientState: ibctmtypes.NewClientState(chainID, "cosmoshub", trustingPeriod, ubdPeriod, height, suite.clientTime), expPass: false, }, { name: "header height < latest client height", - clientState: tendermint.NewClientState(chainID, height+1), - chainID: chainID, + clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height+1, suite.clientTime), expPass: false, }, } @@ -35,12 +32,13 @@ func (suite *TendermintTestSuite) TestCheckValidity() { for i, tc := range testCases { tc := tc - expectedConsensus := tendermint.ConsensusState{ + expectedConsensus := ibctmtypes.ConsensusState{ + Timestamp: suite.headerTime, Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.header.ValidatorSet, } - clientState, consensusState, err := tendermint.CheckValidityAndUpdateState(tc.clientState, suite.header, tc.chainID, suite.now) + clientState, consensusState, err := tendermint.CheckValidityAndUpdateState(tc.clientState, suite.header, suite.now) if tc.expPass { suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) diff --git a/x/ibc/20-transfer/handler_test.go b/x/ibc/20-transfer/handler_test.go index bfb8af5442f0..e792a9eded06 100644 --- a/x/ibc/20-transfer/handler_test.go +++ b/x/ibc/20-transfer/handler_test.go @@ -17,7 +17,7 @@ import ( connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" @@ -87,12 +87,14 @@ func (suite *HandlerTestSuite) createClient() { suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) - consensusState := tendermint.ConsensusState{ + consensusState := ibctmtypes.ConsensusState{ Root: commitment.NewRoot(commitID.Hash), ValidatorSet: suite.valSet, } - _, err := suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, testClient, testClientType, consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(testClient, testClient, consensusState, trustingPeriod, ubdPeriod) + suite.NoError(err) + _, err = suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientState, consensusState) suite.NoError(err) } @@ -104,7 +106,7 @@ func (suite *HandlerTestSuite) updateClient() { suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) - state := tendermint.ConsensusState{ + state := ibctmtypes.ConsensusState{ Root: commitment.NewRoot(commitID.Hash), } diff --git a/x/ibc/20-transfer/keeper/relay_test.go b/x/ibc/20-transfer/keeper/relay_test.go index d404f35324bc..31357c6637e3 100644 --- a/x/ibc/20-transfer/keeper/relay_test.go +++ b/x/ibc/20-transfer/keeper/relay_test.go @@ -10,7 +10,7 @@ import ( connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" @@ -24,12 +24,14 @@ func (suite *KeeperTestSuite) createClient() { suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) - consensusState := tendermint.ConsensusState{ + consensusState := ibctmtypes.ConsensusState{ Root: commitment.NewRoot(commitID.Hash), ValidatorSet: suite.valSet, } - _, err := suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, testClient, testClientType, consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(testClient, testClient, consensusState, trustingPeriod, ubdPeriod) + suite.NoError(err) + _, err = suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientState, consensusState) suite.NoError(err) } @@ -41,7 +43,7 @@ func (suite *KeeperTestSuite) updateClient() { suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) - state := tendermint.ConsensusState{ + state := ibctmtypes.ConsensusState{ Root: commitment.NewRoot(commitID.Hash), } diff --git a/x/ibc/ante/ante.go b/x/ibc/ante/ante.go index 1873c2edf612..4301e95c5a10 100644 --- a/x/ibc/ante/ante.go +++ b/x/ibc/ante/ante.go @@ -3,6 +3,7 @@ package ante import ( sdk "github.com/cosmos/cosmos-sdk/types" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" ) @@ -28,8 +29,8 @@ func (pvr ProofVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim for _, msg := range tx.GetMsgs() { var err error switch msg := msg.(type) { - case client.MsgUpdateClient: - err = pvr.clientKeeper.UpdateClient(ctx, msg.ClientID, msg.Header) + case clientexported.MsgUpdateClient: + err = pvr.clientKeeper.UpdateClient(ctx, msg.GetClientID(), msg.GetHeader()) case channel.MsgPacket: _, err = pvr.channelKeeper.RecvPacket(ctx, msg.Packet, msg.Proof, msg.ProofHeight) case channel.MsgAcknowledgement: diff --git a/x/ibc/ante/ante_test.go b/x/ibc/ante/ante_test.go index f65a50e00523..3c350a198c6c 100644 --- a/x/ibc/ante/ante_test.go +++ b/x/ibc/ante/ante_test.go @@ -19,7 +19,8 @@ import ( channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/ante" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" @@ -76,14 +77,15 @@ func (suite *HandlerTestSuite) createClient() { suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1, Time: now2}}) suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) - consensusState := tendermint.ConsensusState{ + consensusState := ibctmtypes.ConsensusState{ Timestamp: suite.now, Root: commitment.NewRoot(commitID.Hash), ValidatorSet: suite.valSet, } - _, err := suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, testClient, testClientType, consensusState, trustingPeriod, ubdPeriod) - suite.app.IBCKeeper.ClientKeeper.SetClientConsensusState(suite.ctx, testClient, uint64(suite.app.LastBlockHeight()), consensusState) + clientState, err := ibctmtypes.Initialize(testClient, testClient, consensusState, trustingPeriod, ubdPeriod) + suite.NoError(err) + _, err = suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientState, consensusState) suite.NoError(err) } @@ -98,13 +100,13 @@ func (suite *HandlerTestSuite) updateClient() { suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: height, Time: suite.now}}) suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) - state := tendermint.ConsensusState{ + state := ibctmtypes.ConsensusState{ Root: commitment.NewRoot(commitID.Hash), } suite.app.IBCKeeper.ClientKeeper.SetClientConsensusState(suite.ctx, testClient, uint64(height-1), state) csi, _ := suite.app.IBCKeeper.ClientKeeper.GetClientState(suite.ctx, testClient) - cs, _ := csi.(tendermint.ClientState) + cs, _ := csi.(ibctmtypes.ClientState) cs.LatestHeight = uint64(height - 1) suite.app.IBCKeeper.ClientKeeper.SetClientState(suite.ctx, cs) } diff --git a/x/ibc/client/cli/cli.go b/x/ibc/client/cli/cli.go index 6a98669c858e..c42fbc8aa98e 100644 --- a/x/ibc/client/cli/cli.go +++ b/x/ibc/client/cli/cli.go @@ -9,6 +9,7 @@ import ( ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/02-client" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + tmclient "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -23,7 +24,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command { } ibcTxCmd.AddCommand(flags.PostCommands( - ibcclient.GetTxCmd(cdc, storeKey), + tmclient.GetTxCmd(cdc, storeKey), connection.GetTxCmd(cdc, storeKey), channel.GetTxCmd(cdc, storeKey), )...) diff --git a/x/ibc/handler.go b/x/ibc/handler.go index eb6705888f81..1a3f5843f01f 100644 --- a/x/ibc/handler.go +++ b/x/ibc/handler.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" ) @@ -14,11 +15,11 @@ func NewHandler(k Keeper) sdk.Handler { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { - // IBC client msgs - case client.MsgCreateClient: + // IBC client msg interface types + case clientexported.MsgCreateClient: return client.HandleMsgCreateClient(ctx, k.ClientKeeper, msg) - case client.MsgUpdateClient: + case clientexported.MsgUpdateClient: return &sdk.Result{}, nil // IBC connection msgs diff --git a/x/ibc/module.go b/x/ibc/module.go index 65f03954cd1d..17a58c8d9c9d 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -15,7 +15,7 @@ import ( client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" - tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc/client/rest" @@ -43,7 +43,7 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { client.RegisterCodec(cdc) connection.RegisterCodec(cdc) channel.RegisterCodec(cdc) - tendermint.RegisterCodec(cdc) + ibctmtypes.RegisterCodec(cdc) commitment.RegisterCodec(cdc) }