From 0fffaf589b3015ec40cd64ad2bc9a73859d6be79 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 1 Sep 2020 12:40:31 +0200 Subject: [PATCH] ibc: modular client messages (#7160) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ibc: modular client messages * more updates * remove client messages * fixes * fix tests * lint * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * codec.go tests * cleanup exported * MsgCreateClient test * msg tests * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix tests * proto files update * errors * address comments * spec changes * add sanity check test cases * add additional sanity check * fix expPass * fix build and remove unnecessary test since validatebasic is checked in the msg Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya Sripal Co-authored-by: Colin Axner --- proto/ibc/client/client.proto | 65 +- types/errors/errors.go | 6 + x/ibc/02-client/exported/exported.go | 41 +- x/ibc/02-client/exported/exported_test.go | 6 +- x/ibc/02-client/handler.go | 61 +- x/ibc/02-client/handler_test.go | 47 - x/ibc/02-client/keeper/client.go | 4 - x/ibc/02-client/keeper/client_test.go | 17 - x/ibc/02-client/types/client.pb.go | 1015 ++++++++++++++++- x/ibc/02-client/types/codec.go | 108 +- x/ibc/02-client/types/codec_test.go | 211 +++- x/ibc/02-client/types/msgs.go | 197 ++++ x/ibc/02-client/types/msgs_test.go | 316 +++++ x/ibc/07-tendermint/client/cli/tx.go | 31 +- x/ibc/07-tendermint/types/codec.go | 4 + x/ibc/07-tendermint/types/header.go | 4 +- x/ibc/07-tendermint/types/header_test.go | 16 +- x/ibc/07-tendermint/types/misbehaviour.go | 6 +- .../types/misbehaviour_handle_test.go | 14 + .../07-tendermint/types/misbehaviour_test.go | 11 + x/ibc/07-tendermint/types/msgs.go | 231 ---- x/ibc/07-tendermint/types/msgs_test.go | 78 -- x/ibc/07-tendermint/types/update_test.go | 10 + x/ibc/09-localhost/client/cli/cli.go | 23 - x/ibc/09-localhost/client/cli/tx.go | 44 - x/ibc/09-localhost/module.go | 8 - x/ibc/09-localhost/types/codec.go | 5 - x/ibc/09-localhost/types/msgs.go | 69 -- x/ibc/client/cli/cli.go | 4 +- x/ibc/handler.go | 8 +- .../solomachine/client/cli/tx.go | 19 +- .../solomachine/types/client_state.go | 3 + .../solomachine/types/client_state_test.go | 5 + .../light-clients/solomachine/types/codec.go | 15 +- .../solomachine/types/misbehaviour.go | 2 +- x/ibc/light-clients/solomachine/types/msgs.go | 165 --- .../solomachine/types/msgs_test.go | 56 - x/ibc/spec/04_messages.md | 133 ++- x/ibc/testing/chain.go | 41 +- 39 files changed, 2113 insertions(+), 986 deletions(-) delete mode 100644 x/ibc/02-client/handler_test.go create mode 100644 x/ibc/02-client/types/msgs.go create mode 100644 x/ibc/02-client/types/msgs_test.go delete mode 100644 x/ibc/07-tendermint/types/msgs.go delete mode 100644 x/ibc/07-tendermint/types/msgs_test.go delete mode 100644 x/ibc/09-localhost/client/cli/cli.go delete mode 100644 x/ibc/09-localhost/client/cli/tx.go delete mode 100644 x/ibc/09-localhost/types/msgs.go delete mode 100644 x/ibc/light-clients/solomachine/types/msgs.go delete mode 100644 x/ibc/light-clients/solomachine/types/msgs_test.go diff --git a/proto/ibc/client/client.proto b/proto/ibc/client/client.proto index 12b311d080..0104bcf343 100644 --- a/proto/ibc/client/client.proto +++ b/proto/ibc/client/client.proto @@ -6,30 +6,75 @@ option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; -// IdentifiedClientState defines a client state with additional client identifier field. +// IdentifiedClientState defines a client state with additional client +// identifier field. message IdentifiedClientState { // client identifier string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; // client state - google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""]; + google.protobuf.Any client_state = 2 + [(gogoproto.moretags) = "yaml:\"client_state\""]; } -// ClientConsensusStates defines all the stored consensus states for a given client. +// ClientConsensusStates defines all the stored consensus states for a given +// client. message ClientConsensusStates { // client identifier string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; // consensus states associated with the client - repeated google.protobuf.Any consensus_states = 2 [(gogoproto.moretags) = "yaml:\"consensus_states\""]; + repeated google.protobuf.Any consensus_states = 2 + [(gogoproto.moretags) = "yaml:\"consensus_states\""]; +} + +// MsgCreateClient defines a message to create an IBC client +message MsgCreateClient { + // client unique identifier + string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + // light client state + google.protobuf.Any client_state = 2 + [(gogoproto.moretags) = "yaml:\"client_state\""]; + // consensus state associated with the client that corresponds to a given + // height. + google.protobuf.Any consensus_state = 3 + [(gogoproto.moretags) = "yaml:\"consensus_state\""]; + // signer address + bytes signer = 4 + [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; +} + +// MsgUpdateClient defines an sdk.Msg to update a IBC client state using +// the given header. +message MsgUpdateClient { + // client unique identifier + string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + // header to update the light client + google.protobuf.Any header = 2; + // signer address + bytes signer = 3 + [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; +} + +// MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for +// light client misbehaviour. +message MsgSubmitMisbehaviour { + // client unique identifier + string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + // misbehaviour used for freezing the light client + google.protobuf.Any misbehaviour = 2; + // signer address + bytes signer = 3 + [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; } // Height is a monotonically increasing data type -// that can be compared against another Height for the purposes of updating and freezing clients +// that can be compared against another Height for the purposes of updating and +// freezing clients // -// Normally the EpochHeight is incremented at each height while keeping epoch number the same -// However some consensus algorithms may choose to reset the height in certain conditions -// e.g. hard forks, state-machine breaking changes -// In these cases, the epoch number is incremented so that height continues to be monitonically increasing -// even as the EpochHeight gets reset +// Normally the EpochHeight is incremented at each height while keeping epoch +// number the same However some consensus algorithms may choose to reset the +// height in certain conditions e.g. hard forks, state-machine breaking changes +// In these cases, the epoch number is incremented so that height continues to +// be monitonically increasing even as the EpochHeight gets reset message Height { option (gogoproto.goproto_stringer) = false; diff --git a/types/errors/errors.go b/types/errors/errors.go index ed0f625010..6607bc98c0 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -117,6 +117,12 @@ var ( // the signer info doesn't match the account's actual sequence number. ErrWrongSequence = Register(RootCodespace, 32, "incorrect account sequence") + // ErrPackAny defines an error when packing a protobuf message to Any fails. + ErrPackAny = Register(RootCodespace, 33, "failed packing protobuf message to Any") + + // ErrUnpackAny defines an error when unpacking a protobuf message from Any fails. + ErrUnpackAny = Register(RootCodespace, 34, "failed unpacking protobuf message from Any") + // ErrPanic is only set when we recover from a panic, so we know to // redact potentially sensitive system info ErrPanic = Register(UndefinedCodespace, 111222, "panic") diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 2e1d4b3152..2a1e85cae7 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -132,6 +132,9 @@ type ConsensusState interface { ValidateBasic() error } +// TypeClientMisbehaviour is the shared evidence misbehaviour type +const TypeClientMisbehaviour string = "client_misbehaviour" + // Misbehaviour defines counterparty misbehaviour for a specific consensus type type Misbehaviour interface { ClientType() ClientType @@ -147,39 +150,7 @@ type Misbehaviour interface { type Header interface { ClientType() ClientType GetHeight() uint64 -} - -// message and evidence types for the IBC client -const ( - TypeMsgCreateClient string = "create_client" - TypeMsgUpdateClient string = "update_client" - TypeMsgSubmitClientMisbehaviour string = "submit_client_misbehaviour" - TypeEvidenceClientMisbehaviour string = "client_misbehaviour" -) - -// MsgCreateClient defines the msg interface that the -// CreateClient Handler expects -type MsgCreateClient interface { - sdk.Msg - GetClientID() string - GetClientType() string - GetConsensusState() ConsensusState - InitializeClientState() ClientState -} - -// MsgUpdateClient defines the msg interface that the -// UpdateClient Handler expects -type MsgUpdateClient interface { - sdk.Msg - GetClientID() string - GetHeader() Header -} - -// MsgSubmitMisbehaviour defines the msg interface that the -// SubmitMisbehaviour Handler expects -type MsgSubmitMisbehaviour interface { - sdk.Msg - GetMisbehaviour() Misbehaviour + ValidateBasic() error } // Height is a wrapper interface over clienttypes.Height @@ -212,6 +183,8 @@ const ( func (ct ClientType) String() string { switch ct { + case SoloMachine: + return ClientTypeSoloMachine case Tendermint: return ClientTypeTendermint case Localhost: @@ -247,6 +220,8 @@ func (ct *ClientType) UnmarshalJSON(data []byte) error { // type. It returns 0 if the type is not found/registered. func ClientTypeFromString(clientType string) ClientType { switch clientType { + case ClientTypeSoloMachine: + return SoloMachine case ClientTypeTendermint: return Tendermint case ClientTypeLocalHost: diff --git a/x/ibc/02-client/exported/exported_test.go b/x/ibc/02-client/exported/exported_test.go index f0eb1fc4d1..624b607a8e 100644 --- a/x/ibc/02-client/exported/exported_test.go +++ b/x/ibc/02-client/exported/exported_test.go @@ -12,7 +12,9 @@ func TestClientTypeString(t *testing.T) { name string clientType ClientType }{ + {"solomachine client", ClientTypeSoloMachine, SoloMachine}, {"tendermint client", ClientTypeTendermint, Tendermint}, + {"localhost client", ClientTypeLocalHost, Localhost}, {"empty type", "", 0}, } @@ -30,7 +32,9 @@ func TestClientTypeMarshalJSON(t *testing.T) { clientType ClientType expectPass bool }{ - {"tendermint client should have passed", ClientTypeTendermint, Tendermint, true}, + {"solomachine client", ClientTypeSoloMachine, SoloMachine, true}, + {"tendermint client", ClientTypeTendermint, Tendermint, true}, + {"localhost client", ClientTypeLocalHost, Localhost, true}, {"empty type should have failed", "", 0, false}, } diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index 66e08bf392..98b4c779d5 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -5,37 +5,23 @@ import ( 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/keeper" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types" ) // HandleMsgCreateClient defines the sdk.Handler for MsgCreateClient -func HandleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg exported.MsgCreateClient) (*sdk.Result, error) { - var ( - consensusHeight uint64 - clientState exported.ClientState - ) - - switch msg.(type) { - // localhost is a special case that must initialize client state - // from context and not from msg - case *localhosttypes.MsgCreateClient: - selfHeight := types.NewHeight(0, uint64(ctx.BlockHeight())) - clientState = localhosttypes.NewClientState(ctx.ChainID(), selfHeight) - // Localhost consensus height is chain's blockheight - consensusHeight = uint64(ctx.BlockHeight()) - default: - clientState = msg.InitializeClientState() - if consState := msg.GetConsensusState(); consState != nil { - consensusHeight = consState.GetHeight() - } +func HandleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg *types.MsgCreateClient) (*sdk.Result, error) { + clientState, err := types.UnpackClientState(msg.ClientState) + if err != nil { + return nil, err } - _, err := k.CreateClient( - ctx, msg.GetClientID(), clientState, msg.GetConsensusState(), - ) + consensusState, err := types.UnpackConsensusState(msg.ConsensusState) + if err != nil { + return nil, err + } + + _, err = k.CreateClient(ctx, msg.ClientId, clientState, consensusState) if err != nil { return nil, err } @@ -43,9 +29,9 @@ func HandleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg exported.MsgCre ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeCreateClient, - sdk.NewAttribute(types.AttributeKeyClientID, msg.GetClientID()), - sdk.NewAttribute(types.AttributeKeyClientType, msg.GetClientType()), - sdk.NewAttribute(types.AttributeKeyConsensusHeight, fmt.Sprintf("%d", consensusHeight)), + sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientId), + sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType().String()), + sdk.NewAttribute(types.AttributeKeyConsensusHeight, fmt.Sprintf("%d", consensusState.GetHeight())), ), sdk.NewEvent( sdk.EventTypeMessage, @@ -59,8 +45,13 @@ func HandleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg exported.MsgCre } // HandleMsgUpdateClient defines the sdk.Handler for MsgUpdateClient -func HandleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg exported.MsgUpdateClient) (*sdk.Result, error) { - _, err := k.UpdateClient(ctx, msg.GetClientID(), msg.GetHeader()) +func HandleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg *types.MsgUpdateClient) (*sdk.Result, error) { + header, err := types.UnpackHeader(msg.Header) + if err != nil { + return nil, err + } + + _, err = k.UpdateClient(ctx, msg.ClientId, header) if err != nil { return nil, err } @@ -79,13 +70,9 @@ func HandleMsgUpdateClient(ctx sdk.Context, k keeper.Keeper, msg exported.MsgUpd // HandleMsgSubmitMisbehaviour defines the Evidence module handler for submitting a // light client misbehaviour. -func HandleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg exported.MsgSubmitMisbehaviour) (*sdk.Result, error) { - misbehaviour := msg.GetMisbehaviour() - if misbehaviour == nil { - return nil, sdkerrors.Wrapf(types.ErrInvalidMisbehaviour, "misbehaviour is nil") - } - - if err := misbehaviour.ValidateBasic(); err != nil { +func HandleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg *types.MsgSubmitMisbehaviour) (*sdk.Result, error) { + misbehaviour, err := types.UnpackMisbehaviour(msg.Misbehaviour) + if err != nil { return nil, err } @@ -96,7 +83,7 @@ func HandleMsgSubmitMisbehaviour(ctx sdk.Context, k keeper.Keeper, msg exported. ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeSubmitMisbehaviour, - sdk.NewAttribute(types.AttributeKeyClientID, misbehaviour.GetClientID()), + sdk.NewAttribute(types.AttributeKeyClientID, msg.ClientId), sdk.NewAttribute(types.AttributeKeyClientType, misbehaviour.ClientType().String()), sdk.NewAttribute(types.AttributeKeyConsensusHeight, fmt.Sprintf("%d", misbehaviour.GetHeight())), ), diff --git a/x/ibc/02-client/handler_test.go b/x/ibc/02-client/handler_test.go deleted file mode 100644 index eec25ff364..0000000000 --- a/x/ibc/02-client/handler_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package client_test - -import ( - client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types" -) - -func (suite *ClientTestSuite) TestHandleCreateClientLocalHost() { - cases := []struct { - name string - clientID string - msg exported.MsgCreateClient - expPass bool - }{ - { - "tendermint client", - "gaiamainnet", - suite.chainA.ConstructMsgCreateClient(suite.chainB, "gaiamainnet"), - true, - }, - { - "client already exists", - exported.ClientTypeLocalHost, - &localhosttypes.MsgCreateClient{suite.chainA.SenderAccount.GetAddress()}, - false, - }, - } - - for _, tc := range cases { - _, err := client.HandleMsgCreateClient( - suite.chainA.GetContext(), - suite.chainA.App.IBCKeeper.ClientKeeper, - tc.msg, - ) - - if tc.expPass { - suite.Require().NoError(err, "expected test case %s to pass, got error %v", tc.name, err) - - clientState, ok := suite.chainA.App.IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), tc.clientID) - suite.Require().True(ok, "could not retrieve clientState") - suite.Require().NotNil(clientState, "clientstate is nil") - } else { - suite.Require().Error(err, "invalid test case %s passed", tc.name) - } - } -} diff --git a/x/ibc/02-client/keeper/client.go b/x/ibc/02-client/keeper/client.go index c795c0cc51..201ba13161 100644 --- a/x/ibc/02-client/keeper/client.go +++ b/x/ibc/02-client/keeper/client.go @@ -102,12 +102,8 @@ func (k Keeper) CheckMisbehaviourAndUpdateState(ctx sdk.Context, misbehaviour ex if !found { return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot check misbehaviour for client with ID %s", misbehaviour.GetClientID()) } - if err := misbehaviour.ValidateBasic(); err != nil { - return sdkerrors.Wrap(err, "IBC misbehaviour failed validate basic") - } clientState, err := clientState.CheckMisbehaviourAndUpdateState(ctx, k.cdc, k.ClientStore(ctx, misbehaviour.GetClientID()), misbehaviour) - if err != nil { return err } diff --git a/x/ibc/02-client/keeper/client_test.go b/x/ibc/02-client/keeper/client_test.go index 5056ad1a8a..f654efd3c1 100644 --- a/x/ibc/02-client/keeper/client_test.go +++ b/x/ibc/02-client/keeper/client_test.go @@ -346,23 +346,6 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, true, }, - { - "misbehaviour fails validatebasic", - &ibctmtypes.Misbehaviour{ - Header1: ibctmtypes.CreateTestHeader(testChainID, height+1, height, altTime, bothValSet, bothValSet, bothSigners), - Header2: ibctmtypes.CreateTestHeader(testChainID, height, height, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), - ChainId: testChainID, - ClientId: testClientID, - }, - func() error { - suite.consensusState.NextValidatorsHash = bothValsHash - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs()) - _, err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) - - return err - }, - false, - }, { "trusted ConsensusState1 not found", &ibctmtypes.Misbehaviour{ diff --git a/x/ibc/02-client/types/client.pb.go b/x/ibc/02-client/types/client.pb.go index 639a9e52f6..d4ebfe57cb 100644 --- a/x/ibc/02-client/types/client.pb.go +++ b/x/ibc/02-client/types/client.pb.go @@ -6,6 +6,7 @@ package types import ( fmt "fmt" types "github.com/cosmos/cosmos-sdk/codec/types" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -24,7 +25,8 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// IdentifiedClientState defines a client state with additional client identifier field. +// IdentifiedClientState defines a client state with additional client +// identifier field. type IdentifiedClientState struct { // client identifier ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` @@ -79,7 +81,8 @@ func (m *IdentifiedClientState) GetClientState() *types.Any { return nil } -// ClientConsensusStates defines all the stored consensus states for a given client. +// ClientConsensusStates defines all the stored consensus states for a given +// client. type ClientConsensusStates struct { // client identifier ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` @@ -134,14 +137,219 @@ func (m *ClientConsensusStates) GetConsensusStates() []*types.Any { return nil } +// MsgCreateClient defines a message to create an IBC client +type MsgCreateClient struct { + // client unique identifier + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` + // light client state + ClientState *types.Any `protobuf:"bytes,2,opt,name=client_state,json=clientState,proto3" json:"client_state,omitempty" yaml:"client_state"` + // consensus state associated with the client that corresponds to a given + // height. + ConsensusState *types.Any `protobuf:"bytes,3,opt,name=consensus_state,json=consensusState,proto3" json:"consensus_state,omitempty" yaml:"consensus_state"` + // signer address + Signer github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,4,opt,name=signer,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"signer,omitempty"` +} + +func (m *MsgCreateClient) Reset() { *m = MsgCreateClient{} } +func (m *MsgCreateClient) String() string { return proto.CompactTextString(m) } +func (*MsgCreateClient) ProtoMessage() {} +func (*MsgCreateClient) Descriptor() ([]byte, []int) { + return fileDescriptor_226f80e576f20abd, []int{2} +} +func (m *MsgCreateClient) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreateClient) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreateClient.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgCreateClient) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreateClient.Merge(m, src) +} +func (m *MsgCreateClient) XXX_Size() int { + return m.Size() +} +func (m *MsgCreateClient) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreateClient.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreateClient proto.InternalMessageInfo + +func (m *MsgCreateClient) GetClientId() string { + if m != nil { + return m.ClientId + } + return "" +} + +func (m *MsgCreateClient) GetClientState() *types.Any { + if m != nil { + return m.ClientState + } + return nil +} + +func (m *MsgCreateClient) GetConsensusState() *types.Any { + if m != nil { + return m.ConsensusState + } + return nil +} + +func (m *MsgCreateClient) GetSigner() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.Signer + } + return nil +} + +// MsgUpdateClient defines an sdk.Msg to update a IBC client state using +// the given header. +type MsgUpdateClient struct { + // client unique identifier + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` + // header to update the light client + Header *types.Any `protobuf:"bytes,2,opt,name=header,proto3" json:"header,omitempty"` + // signer address + Signer github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,3,opt,name=signer,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"signer,omitempty"` +} + +func (m *MsgUpdateClient) Reset() { *m = MsgUpdateClient{} } +func (m *MsgUpdateClient) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateClient) ProtoMessage() {} +func (*MsgUpdateClient) Descriptor() ([]byte, []int) { + return fileDescriptor_226f80e576f20abd, []int{3} +} +func (m *MsgUpdateClient) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateClient) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateClient.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateClient) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateClient.Merge(m, src) +} +func (m *MsgUpdateClient) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateClient) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateClient.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateClient proto.InternalMessageInfo + +func (m *MsgUpdateClient) GetClientId() string { + if m != nil { + return m.ClientId + } + return "" +} + +func (m *MsgUpdateClient) GetHeader() *types.Any { + if m != nil { + return m.Header + } + return nil +} + +func (m *MsgUpdateClient) GetSigner() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.Signer + } + return nil +} + +// MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for +// light client misbehaviour. +type MsgSubmitMisbehaviour struct { + // client unique identifier + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` + // misbehaviour used for freezing the light client + Misbehaviour *types.Any `protobuf:"bytes,2,opt,name=misbehaviour,proto3" json:"misbehaviour,omitempty"` + // signer address + Signer github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,3,opt,name=signer,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"signer,omitempty"` +} + +func (m *MsgSubmitMisbehaviour) Reset() { *m = MsgSubmitMisbehaviour{} } +func (m *MsgSubmitMisbehaviour) String() string { return proto.CompactTextString(m) } +func (*MsgSubmitMisbehaviour) ProtoMessage() {} +func (*MsgSubmitMisbehaviour) Descriptor() ([]byte, []int) { + return fileDescriptor_226f80e576f20abd, []int{4} +} +func (m *MsgSubmitMisbehaviour) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSubmitMisbehaviour) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSubmitMisbehaviour.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSubmitMisbehaviour) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSubmitMisbehaviour.Merge(m, src) +} +func (m *MsgSubmitMisbehaviour) XXX_Size() int { + return m.Size() +} +func (m *MsgSubmitMisbehaviour) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSubmitMisbehaviour.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSubmitMisbehaviour proto.InternalMessageInfo + +func (m *MsgSubmitMisbehaviour) GetClientId() string { + if m != nil { + return m.ClientId + } + return "" +} + +func (m *MsgSubmitMisbehaviour) GetMisbehaviour() *types.Any { + if m != nil { + return m.Misbehaviour + } + return nil +} + +func (m *MsgSubmitMisbehaviour) GetSigner() github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.Signer + } + return nil +} + // Height is a monotonically increasing data type -// that can be compared against another Height for the purposes of updating and freezing clients +// that can be compared against another Height for the purposes of updating and +// freezing clients // -// Normally the EpochHeight is incremented at each height while keeping epoch number the same -// However some consensus algorithms may choose to reset the height in certain conditions -// e.g. hard forks, state-machine breaking changes -// In these cases, the epoch number is incremented so that height continues to be monitonically increasing -// even as the EpochHeight gets reset +// Normally the EpochHeight is incremented at each height while keeping epoch +// number the same However some consensus algorithms may choose to reset the +// height in certain conditions e.g. hard forks, state-machine breaking changes +// In these cases, the epoch number is incremented so that height continues to +// be monitonically increasing even as the EpochHeight gets reset type Height struct { // the epoch that the client is currently on EpochNumber uint64 `protobuf:"varint,1,opt,name=epoch_number,json=epochNumber,proto3" json:"epoch_number,omitempty" yaml:"epoch_number"` @@ -152,7 +360,7 @@ type Height struct { func (m *Height) Reset() { *m = Height{} } func (*Height) ProtoMessage() {} func (*Height) Descriptor() ([]byte, []int) { - return fileDescriptor_226f80e576f20abd, []int{2} + return fileDescriptor_226f80e576f20abd, []int{5} } func (m *Height) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -198,37 +406,49 @@ func (m *Height) GetEpochHeight() uint64 { func init() { proto.RegisterType((*IdentifiedClientState)(nil), "ibc.client.IdentifiedClientState") proto.RegisterType((*ClientConsensusStates)(nil), "ibc.client.ClientConsensusStates") + proto.RegisterType((*MsgCreateClient)(nil), "ibc.client.MsgCreateClient") + proto.RegisterType((*MsgUpdateClient)(nil), "ibc.client.MsgUpdateClient") + proto.RegisterType((*MsgSubmitMisbehaviour)(nil), "ibc.client.MsgSubmitMisbehaviour") proto.RegisterType((*Height)(nil), "ibc.client.Height") } func init() { proto.RegisterFile("ibc/client/client.proto", fileDescriptor_226f80e576f20abd) } var fileDescriptor_226f80e576f20abd = []byte{ - // 378 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcf, 0x4c, 0x4a, 0xd6, - 0x4f, 0xce, 0xc9, 0x4c, 0xcd, 0x2b, 0x81, 0x52, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x5c, - 0x99, 0x49, 0xc9, 0x7a, 0x10, 0x11, 0x29, 0x91, 0xf4, 0xfc, 0xf4, 0x7c, 0xb0, 0xb0, 0x3e, 0x88, - 0x05, 0x51, 0x21, 0x25, 0x99, 0x9e, 0x9f, 0x9f, 0x9e, 0x93, 0xaa, 0x0f, 0xe6, 0x25, 0x95, 0xa6, - 0xe9, 0x27, 0xe6, 0x55, 0x42, 0xa4, 0x94, 0xe6, 0x30, 0x72, 0x89, 0x7a, 0xa6, 0xa4, 0xe6, 0x95, - 0x64, 0xa6, 0x65, 0xa6, 0xa6, 0x38, 0x83, 0x4d, 0x09, 0x2e, 0x49, 0x2c, 0x49, 0x15, 0x32, 0xe4, - 0xe2, 0x84, 0x18, 0x1a, 0x9f, 0x99, 0x22, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0xe9, 0x24, 0xf2, 0xe9, - 0x9e, 0xbc, 0x40, 0x65, 0x62, 0x6e, 0x8e, 0x95, 0x12, 0x5c, 0x4a, 0x29, 0x88, 0x03, 0xc2, 0xf6, - 0x4c, 0x11, 0x0a, 0xe0, 0xe2, 0x81, 0x8a, 0x17, 0x83, 0x8c, 0x90, 0x60, 0x52, 0x60, 0xd4, 0xe0, - 0x36, 0x12, 0xd1, 0x83, 0x58, 0xaf, 0x07, 0xb3, 0x5e, 0xcf, 0x31, 0xaf, 0xd2, 0x49, 0xfc, 0xd3, - 0x3d, 0x79, 0x61, 0x14, 0xb3, 0xc0, 0x7a, 0x94, 0x82, 0xb8, 0x93, 0x11, 0x8e, 0x50, 0x5a, 0xc1, - 0xc8, 0x25, 0x0a, 0x71, 0x94, 0x73, 0x7e, 0x5e, 0x71, 0x6a, 0x5e, 0x71, 0x69, 0x31, 0x58, 0xa2, - 0x98, 0x1c, 0xe7, 0xc5, 0x70, 0x09, 0x24, 0xc3, 0x4c, 0x81, 0xd8, 0x56, 0x2c, 0xc1, 0xa4, 0xc0, - 0x8c, 0xd3, 0x89, 0xd2, 0x9f, 0xee, 0xc9, 0x8b, 0x43, 0xcd, 0x43, 0xd3, 0xa7, 0x14, 0xc4, 0x9f, - 0x8c, 0xea, 0x20, 0xa5, 0x36, 0x46, 0x2e, 0x36, 0x8f, 0xd4, 0xcc, 0xf4, 0x8c, 0x12, 0x21, 0x2b, - 0x2e, 0x9e, 0xd4, 0x82, 0xfc, 0xe4, 0x8c, 0xf8, 0xbc, 0xd2, 0xdc, 0xa4, 0xd4, 0x22, 0xb0, 0xf3, - 0x58, 0x90, 0x7d, 0x8c, 0x2c, 0xab, 0x14, 0xc4, 0x0d, 0xe6, 0xfa, 0x81, 0x79, 0x08, 0xbd, 0x19, - 0x60, 0xb3, 0xc0, 0x61, 0x88, 0x45, 0x2f, 0x44, 0x16, 0xa6, 0x17, 0x62, 0xaf, 0x15, 0xcb, 0x8c, - 0x05, 0xf2, 0x0c, 0x4e, 0x3e, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, - 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, - 0x94, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x9f, 0x9c, 0x5f, 0x9c, 0x9b, - 0x5f, 0x0c, 0xa5, 0x74, 0x8b, 0x53, 0xb2, 0xf5, 0x2b, 0xf4, 0x41, 0x29, 0xcc, 0xc0, 0x48, 0x17, - 0x9a, 0xc8, 0x4a, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0x41, 0x62, 0x0c, 0x08, 0x00, 0x00, - 0xff, 0xff, 0x55, 0xfb, 0xf5, 0xfb, 0x7f, 0x02, 0x00, 0x00, + // 520 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0x3f, 0x8f, 0x12, 0x41, + 0x1c, 0x65, 0x80, 0x10, 0x6f, 0x20, 0x72, 0x59, 0x41, 0x10, 0x93, 0x5d, 0x32, 0x15, 0x85, 0xec, + 0x7a, 0xd8, 0x18, 0x3a, 0xa0, 0x91, 0x44, 0x8c, 0xd9, 0x8b, 0x85, 0xc6, 0xe4, 0xb2, 0x3b, 0x3b, + 0xb7, 0x3b, 0x91, 0xdd, 0x21, 0x3b, 0xb3, 0x46, 0xbe, 0x80, 0xb5, 0xa5, 0x85, 0x85, 0xa5, 0x1f, + 0x42, 0x7b, 0x3b, 0xaf, 0xb4, 0xda, 0x18, 0xf8, 0x06, 0x94, 0x56, 0x86, 0x99, 0xc5, 0x83, 0xcb, + 0x49, 0x71, 0x67, 0x71, 0xd5, 0xcc, 0xef, 0xdf, 0xfb, 0xbd, 0xf7, 0x32, 0x19, 0xd8, 0xa0, 0x2e, + 0xb6, 0xf0, 0x94, 0x92, 0x48, 0x64, 0x87, 0x39, 0x8b, 0x99, 0x60, 0x1a, 0xa4, 0x2e, 0x36, 0x55, + 0xa6, 0x55, 0xf3, 0x99, 0xcf, 0x64, 0xda, 0x5a, 0xdf, 0x54, 0x47, 0xeb, 0x9e, 0xcf, 0x98, 0x3f, + 0x25, 0x96, 0x8c, 0xdc, 0xe4, 0xd4, 0x72, 0xa2, 0xb9, 0x2a, 0xa1, 0x4f, 0x00, 0xd6, 0xc7, 0x1e, + 0x89, 0x04, 0x3d, 0xa5, 0xc4, 0x1b, 0x49, 0x94, 0x63, 0xe1, 0x08, 0xa2, 0x1d, 0xc1, 0x03, 0x05, + 0x7a, 0x42, 0xbd, 0x26, 0x68, 0x83, 0xce, 0xc1, 0xb0, 0xb6, 0x4a, 0x8d, 0xc3, 0xb9, 0x13, 0x4e, + 0xfb, 0xe8, 0x6f, 0x09, 0xd9, 0xb7, 0xd4, 0x7d, 0xec, 0x69, 0xcf, 0x61, 0x25, 0xcb, 0xf3, 0x35, + 0x44, 0x33, 0xdf, 0x06, 0x9d, 0x72, 0xaf, 0x66, 0xaa, 0xf5, 0xe6, 0x66, 0xbd, 0x39, 0x88, 0xe6, + 0xc3, 0xc6, 0x2a, 0x35, 0xee, 0xec, 0x60, 0xc9, 0x19, 0x64, 0x97, 0xf1, 0x39, 0x09, 0xf4, 0x05, + 0xc0, 0xba, 0x22, 0x35, 0x62, 0x11, 0x27, 0x11, 0x4f, 0xb8, 0x2c, 0xf0, 0xab, 0xd0, 0x7b, 0x0d, + 0x0f, 0xf1, 0x06, 0x45, 0x6d, 0xe3, 0xcd, 0x7c, 0xbb, 0xf0, 0x4f, 0x8a, 0xf7, 0x57, 0xa9, 0xd1, + 0xc8, 0xf0, 0x2e, 0xcc, 0x21, 0xbb, 0x8a, 0x77, 0x09, 0xa1, 0xaf, 0x79, 0x58, 0x9d, 0x70, 0x7f, + 0x14, 0x13, 0x47, 0x10, 0xc5, 0xf9, 0x46, 0x78, 0xa8, 0xbd, 0x84, 0xd5, 0x0b, 0xf4, 0x9b, 0x85, + 0x3d, 0xa0, 0xad, 0x55, 0x6a, 0xdc, 0xbd, 0x54, 0x35, 0xb2, 0x6f, 0xef, 0x8a, 0xd6, 0xc6, 0xb0, + 0xc4, 0xa9, 0x1f, 0x91, 0xb8, 0x59, 0x6c, 0x83, 0x4e, 0x65, 0x78, 0xf4, 0x3b, 0x35, 0xba, 0x3e, + 0x15, 0x41, 0xe2, 0x9a, 0x98, 0x85, 0x16, 0x66, 0x3c, 0x64, 0x3c, 0x3b, 0xba, 0xdc, 0x7b, 0x63, + 0x89, 0xf9, 0x8c, 0x70, 0x73, 0x80, 0xf1, 0xc0, 0xf3, 0x62, 0xc2, 0xb9, 0x9d, 0x01, 0xa0, 0x6f, + 0x40, 0xda, 0xf7, 0x62, 0xe6, 0x5d, 0xcb, 0xbe, 0x07, 0xb0, 0x14, 0x10, 0xc7, 0x23, 0xf1, 0x3e, + 0xe3, 0xec, 0xac, 0x67, 0x8b, 0x7f, 0xe1, 0xba, 0xfc, 0x7f, 0x00, 0x58, 0x9f, 0x70, 0xff, 0x38, + 0x71, 0x43, 0x2a, 0x26, 0x94, 0xbb, 0x24, 0x70, 0xde, 0x52, 0x96, 0xc4, 0x57, 0x51, 0xf1, 0x18, + 0x56, 0xc2, 0x2d, 0x88, 0xbd, 0x5a, 0x76, 0x3a, 0xff, 0xa7, 0xa2, 0xf7, 0x00, 0x96, 0x9e, 0x10, + 0xea, 0x07, 0x42, 0xeb, 0xc3, 0x0a, 0x99, 0x31, 0x1c, 0x9c, 0x44, 0x49, 0xe8, 0x92, 0x58, 0xaa, + 0x28, 0x6e, 0x3f, 0xbf, 0xed, 0x2a, 0xb2, 0xcb, 0x32, 0x7c, 0x26, 0xa3, 0xf3, 0xd9, 0x40, 0x62, + 0x49, 0x2d, 0x97, 0xcc, 0xaa, 0xea, 0x66, 0x56, 0xed, 0xed, 0x17, 0x3f, 0x7e, 0x36, 0x72, 0xc3, + 0xa7, 0xdf, 0x17, 0x3a, 0x38, 0x5b, 0xe8, 0xe0, 0xd7, 0x42, 0x07, 0x1f, 0x96, 0x7a, 0xee, 0x6c, + 0xa9, 0xe7, 0x7e, 0x2e, 0xf5, 0xdc, 0xab, 0xde, 0x5e, 0x65, 0xef, 0xac, 0xf5, 0x97, 0xf9, 0xb0, + 0xd7, 0xcd, 0x7e, 0x4d, 0xa9, 0xd4, 0x2d, 0x49, 0xf7, 0x1e, 0xfd, 0x09, 0x00, 0x00, 0xff, 0xff, + 0xec, 0xf5, 0xcc, 0x58, 0x50, 0x05, 0x00, 0x00, } func (m *IdentifiedClientState) Marshal() (dAtA []byte, err error) { @@ -317,6 +537,165 @@ func (m *ClientConsensusStates) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MsgCreateClient) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgCreateClient) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreateClient) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintClient(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x22 + } + if m.ConsensusState != nil { + { + size, err := m.ConsensusState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintClient(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.ClientState != nil { + { + size, err := m.ClientState.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintClient(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.ClientId) > 0 { + i -= len(m.ClientId) + copy(dAtA[i:], m.ClientId) + i = encodeVarintClient(dAtA, i, uint64(len(m.ClientId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateClient) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateClient) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateClient) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintClient(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x1a + } + if m.Header != nil { + { + size, err := m.Header.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintClient(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.ClientId) > 0 { + i -= len(m.ClientId) + copy(dAtA[i:], m.ClientId) + i = encodeVarintClient(dAtA, i, uint64(len(m.ClientId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSubmitMisbehaviour) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSubmitMisbehaviour) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSubmitMisbehaviour) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintClient(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x1a + } + if m.Misbehaviour != nil { + { + size, err := m.Misbehaviour.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintClient(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.ClientId) > 0 { + i -= len(m.ClientId) + copy(dAtA[i:], m.ClientId) + i = encodeVarintClient(dAtA, i, uint64(len(m.ClientId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Height) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -397,6 +776,73 @@ func (m *ClientConsensusStates) Size() (n int) { return n } +func (m *MsgCreateClient) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ClientId) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + if m.ClientState != nil { + l = m.ClientState.Size() + n += 1 + l + sovClient(uint64(l)) + } + if m.ConsensusState != nil { + l = m.ConsensusState.Size() + n += 1 + l + sovClient(uint64(l)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + return n +} + +func (m *MsgUpdateClient) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ClientId) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + if m.Header != nil { + l = m.Header.Size() + n += 1 + l + sovClient(uint64(l)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + return n +} + +func (m *MsgSubmitMisbehaviour) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ClientId) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + if m.Misbehaviour != nil { + l = m.Misbehaviour.Size() + n += 1 + l + sovClient(uint64(l)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovClient(uint64(l)) + } + return n +} + func (m *Height) Size() (n int) { if m == nil { return 0 @@ -658,6 +1104,507 @@ func (m *ClientConsensusStates) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgCreateClient) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgCreateClient: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgCreateClient: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ClientState == nil { + m.ClientState = &types.Any{} + } + if err := m.ClientState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsensusState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ConsensusState == nil { + m.ConsensusState = &types.Any{} + } + if err := m.ConsensusState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = append(m.Signer[:0], dAtA[iNdEx:postIndex]...) + if m.Signer == nil { + m.Signer = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipClient(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthClient + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthClient + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateClient) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateClient: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateClient: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Header", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Header == nil { + m.Header = &types.Any{} + } + if err := m.Header.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = append(m.Signer[:0], dAtA[iNdEx:postIndex]...) + if m.Signer == nil { + m.Signer = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipClient(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthClient + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthClient + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSubmitMisbehaviour) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSubmitMisbehaviour: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitMisbehaviour: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Misbehaviour", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Misbehaviour == nil { + m.Misbehaviour = &types.Any{} + } + if err := m.Misbehaviour.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowClient + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthClient + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthClient + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = append(m.Signer[:0], dAtA[iNdEx:postIndex]...) + if m.Signer == nil { + m.Signer = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipClient(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthClient + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthClient + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Height) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/ibc/02-client/types/codec.go b/x/ibc/02-client/types/codec.go index 671be5445e..6b4f29ab01 100644 --- a/x/ibc/02-client/types/codec.go +++ b/x/ibc/02-client/types/codec.go @@ -1,12 +1,12 @@ package types import ( - "fmt" - proto "github.com/gogo/protobuf/proto" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + 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" ) @@ -24,6 +24,16 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { "cosmos_sdk.ibc.v1.client.Header", (*exported.Header)(nil), ) + registry.RegisterInterface( + "cosmos_sdk.ibc.v1.client.Misbehaviour", + (*exported.Misbehaviour)(nil), + ) + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgCreateClient{}, + &MsgUpdateClient{}, + &MsgSubmitMisbehaviour{}, + ) } var ( @@ -41,33 +51,27 @@ var ( func PackClientState(clientState exported.ClientState) (*codectypes.Any, error) { msg, ok := clientState.(proto.Message) if !ok { - return nil, fmt.Errorf("cannot proto marshal %T", clientState) + return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", clientState) } anyClientState, err := codectypes.NewAnyWithValue(msg) if err != nil { - return nil, err + return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error()) } return anyClientState, nil } -// MustPackClientState calls PackClientState and panics on error. -func MustPackClientState(clientState exported.ClientState) *codectypes.Any { - anyClientState, err := PackClientState(clientState) - if err != nil { - panic(err) - } - - return anyClientState -} - // UnpackClientState unpacks an Any into a ClientState. It returns an error if the // client state can't be unpacked into a ClientState. func UnpackClientState(any *codectypes.Any) (exported.ClientState, error) { + if any == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil") + } + clientState, ok := any.GetCachedValue().(exported.ClientState) if !ok { - return nil, fmt.Errorf("cannot unpack Any into ClientState %T", any) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into ClientState %T", any) } return clientState, nil @@ -79,12 +83,12 @@ func UnpackClientState(any *codectypes.Any) (exported.ClientState, error) { func PackConsensusState(consensusState exported.ConsensusState) (*codectypes.Any, error) { msg, ok := consensusState.(proto.Message) if !ok { - return nil, fmt.Errorf("cannot proto marshal %T", consensusState) + return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", consensusState) } anyConsensusState, err := codectypes.NewAnyWithValue(msg) if err != nil { - return nil, err + return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error()) } return anyConsensusState, nil @@ -103,10 +107,78 @@ func MustPackConsensusState(consensusState exported.ConsensusState) *codectypes. // UnpackConsensusState unpacks an Any into a ConsensusState. It returns an error if the // consensus state can't be unpacked into a ConsensusState. func UnpackConsensusState(any *codectypes.Any) (exported.ConsensusState, error) { + if any == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil") + } + consensusState, ok := any.GetCachedValue().(exported.ConsensusState) if !ok { - return nil, fmt.Errorf("cannot unpack Any into ConsensusState %T", any) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into ConsensusState %T", any) } return consensusState, nil } + +// PackHeader constructs a new Any packed with the given header value. It returns +// an error if the header can't be casted to a protobuf message or if the concrete +// implemention is not registered to the protobuf codec. +func PackHeader(header exported.Header) (*codectypes.Any, error) { + msg, ok := header.(proto.Message) + if !ok { + return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", header) + } + + anyHeader, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error()) + } + + return anyHeader, nil +} + +// UnpackHeader unpacks an Any into a Header. It returns an error if the +// consensus state can't be unpacked into a Header. +func UnpackHeader(any *codectypes.Any) (exported.Header, error) { + if any == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil") + } + + header, ok := any.GetCachedValue().(exported.Header) + if !ok { + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into Header %T", any) + } + + return header, nil +} + +// PackMisbehaviour constructs a new Any packed with the given misbehaviour value. It returns +// an error if the misbehaviour can't be casted to a protobuf message or if the concrete +// implemention is not registered to the protobuf codec. +func PackMisbehaviour(misbehaviour exported.Misbehaviour) (*codectypes.Any, error) { + msg, ok := misbehaviour.(proto.Message) + if !ok { + return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", misbehaviour) + } + + anyMisbhaviour, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error()) + } + + return anyMisbhaviour, nil +} + +// UnpackMisbehaviour unpacks an Any into a Misbehaviour. It returns an error if the +// Any can't be unpacked into a Misbehaviour. +func UnpackMisbehaviour(any *codectypes.Any) (exported.Misbehaviour, error) { + if any == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil") + } + + misbehaviour, ok := any.GetCachedValue().(exported.Misbehaviour) + if !ok { + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into Misbehaviour %T", any) + } + + return misbehaviour, nil +} diff --git a/x/ibc/02-client/types/codec_test.go b/x/ibc/02-client/types/codec_test.go index d0de10127f..1bb9912c52 100644 --- a/x/ibc/02-client/types/codec_test.go +++ b/x/ibc/02-client/types/codec_test.go @@ -2,41 +2,218 @@ package types_test import ( "testing" - "time" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "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" localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types" commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" + "github.com/stretchr/testify/require" ) +type caseAny struct { + name string + any *codectypes.Any + expPass bool +} + func TestPackClientState(t *testing.T) { - clientState := localhosttypes.NewClientState(chainID, clientHeight) + testCases := []struct { + name string + clientState exported.ClientState + expPass bool + }{ + { + "solo machine client", + ibctesting.NewSolomachine(t, "solomachine").ClientState(), + true, + }, + { + "tendermint client", + ibctmtypes.NewClientState(chainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs()), + true, + }, + { + "localhost client", + localhosttypes.NewClientState(chainID, clientHeight), + true, + }, + { + "nil", + nil, + false, + }, + } - clientAny, err := types.PackClientState(clientState) - require.NoError(t, err, "pack clientstate should not return error") + testCasesAny := []caseAny{} - cs, err := types.UnpackClientState(clientAny) - require.NoError(t, err, "unpack clientstate should not return error") + for _, tc := range testCases { + clientAny, err := types.PackClientState(tc.clientState) + if tc.expPass { + require.NoError(t, err, tc.name) + } else { + require.Error(t, err, tc.name) + } - require.Equal(t, clientState, cs, "client states are not equal after packing and unpacking") + testCasesAny = append(testCasesAny, caseAny{tc.name, clientAny, tc.expPass}) + } - _, err = types.PackClientState(nil) - require.Error(t, err, "did not error after packing nil") + for i, tc := range testCasesAny { + cs, err := types.UnpackClientState(tc.any) + if tc.expPass { + require.NoError(t, err, tc.name) + require.Equal(t, testCases[i].clientState, cs, tc.name) + } else { + require.Error(t, err, tc.name) + } + } } func TestPackConsensusState(t *testing.T) { - consensusState := ibctmtypes.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("root")), clientHeight, []byte("nextvalshash")) + chain := ibctesting.NewTestChain(t, "cosmoshub") - consensusAny, err := types.PackConsensusState(consensusState) - require.NoError(t, err, "pack consensusstate should not return error") + testCases := []struct { + name string + consensusState exported.ConsensusState + expPass bool + }{ + { + "solo machine consensus", + ibctesting.NewSolomachine(t, "solomachine").ConsensusState(), + true, + }, + { + "tendermint consensus", + chain.LastHeader.ConsensusState(), + true, + }, + { + "nil", + nil, + false, + }, + } - cs, err := types.UnpackConsensusState(consensusAny) - require.NoError(t, err, "unpack consensusstate should not return error") + testCasesAny := []caseAny{} - require.Equal(t, consensusState, cs, "consensus states are not equal after packing and unpacking") + for _, tc := range testCases { + clientAny, err := types.PackConsensusState(tc.consensusState) + if tc.expPass { + require.NoError(t, err, tc.name) + } else { + require.Error(t, err, tc.name) + } + testCasesAny = append(testCasesAny, caseAny{tc.name, clientAny, tc.expPass}) + } - _, err = types.PackConsensusState(nil) - require.Error(t, err, "did not error after packing nil") + for i, tc := range testCasesAny { + cs, err := types.UnpackConsensusState(tc.any) + if tc.expPass { + require.NoError(t, err, tc.name) + require.Equal(t, testCases[i].consensusState, cs, tc.name) + } else { + require.Error(t, err, tc.name) + } + } +} + +func TestPackHeader(t *testing.T) { + chain := ibctesting.NewTestChain(t, "cosmoshub") + + testCases := []struct { + name string + header exported.Header + expPass bool + }{ + { + "solo machine header", + ibctesting.NewSolomachine(t, "solomachine").CreateHeader(), + true, + }, + { + "tendermint header", + chain.LastHeader, + true, + }, + { + "nil", + nil, + false, + }, + } + + testCasesAny := []caseAny{} + + for _, tc := range testCases { + clientAny, err := types.PackHeader(tc.header) + if tc.expPass { + require.NoError(t, err, tc.name) + } else { + require.Error(t, err, tc.name) + } + + testCasesAny = append(testCasesAny, caseAny{tc.name, clientAny, tc.expPass}) + } + + for i, tc := range testCasesAny { + cs, err := types.UnpackHeader(tc.any) + if tc.expPass { + require.NoError(t, err, tc.name) + require.Equal(t, testCases[i].header, cs, tc.name) + } else { + require.Error(t, err, tc.name) + } + } +} + +func TestPackMisbehaviour(t *testing.T) { + chain := ibctesting.NewTestChain(t, "cosmoshub") + + testCases := []struct { + name string + misbehaviour exported.Misbehaviour + expPass bool + }{ + { + "solo machine misbehaviour", + ibctesting.NewSolomachine(t, "solomachine").CreateMisbehaviour(), + true, + }, + { + "tendermint misbehaviour", + ibctmtypes.NewMisbehaviour("tendermint", chain.ChainID, chain.LastHeader, chain.LastHeader), + true, + }, + { + "nil", + nil, + false, + }, + } + + testCasesAny := []caseAny{} + + for _, tc := range testCases { + clientAny, err := types.PackMisbehaviour(tc.misbehaviour) + if tc.expPass { + require.NoError(t, err, tc.name) + } else { + require.Error(t, err, tc.name) + } + + testCasesAny = append(testCasesAny, caseAny{tc.name, clientAny, tc.expPass}) + } + + for i, tc := range testCasesAny { + cs, err := types.UnpackMisbehaviour(tc.any) + if tc.expPass { + require.NoError(t, err, tc.name) + require.Equal(t, testCases[i].misbehaviour, cs, tc.name) + } else { + require.Error(t, err, tc.name) + } + } } diff --git a/x/ibc/02-client/types/msgs.go b/x/ibc/02-client/types/msgs.go new file mode 100644 index 0000000000..6344a5b57b --- /dev/null +++ b/x/ibc/02-client/types/msgs.go @@ -0,0 +1,197 @@ +package types + +import ( + 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" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" +) + +// message types for the IBC client +const ( + TypeMsgCreateClient string = "create_client" + TypeMsgUpdateClient string = "update_client" + TypeMsgSubmitMisbehaviour string = "submit_misbehaviour" +) + +var ( + _ sdk.Msg = &MsgCreateClient{} + _ sdk.Msg = &MsgUpdateClient{} + _ sdk.Msg = &MsgSubmitMisbehaviour{} +) + +// NewMsgCreateClient creates a new MsgCreateClient instance +func NewMsgCreateClient( + id string, clientState exported.ClientState, consensusState exported.ConsensusState, signer sdk.AccAddress, +) (*MsgCreateClient, error) { + + anyClientState, err := PackClientState(clientState) + if err != nil { + return nil, err + } + + anyConsensusState, err := PackConsensusState(consensusState) + if err != nil { + return nil, err + } + + return &MsgCreateClient{ + ClientId: id, + ClientState: anyClientState, + ConsensusState: anyConsensusState, + Signer: signer, + }, nil +} + +// Route implements sdk.Msg +func (msg MsgCreateClient) Route() string { + return host.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgCreateClient) Type() string { + return TypeMsgCreateClient +} + +// ValidateBasic implements sdk.Msg +func (msg MsgCreateClient) ValidateBasic() error { + if msg.Signer.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "signer address cannot be empty") + } + clientState, err := UnpackClientState(msg.ClientState) + if err != nil { + return err + } + if err := clientState.Validate(); err != nil { + return err + } + if clientState.ClientType() == exported.Localhost || msg.ClientId == exported.ClientTypeLocalHost { + return sdkerrors.Wrap(ErrInvalidClient, "localhost client can only be created on chain initialization") + } + consensusState, err := UnpackConsensusState(msg.ConsensusState) + if err != nil { + return err + } + if err := consensusState.ValidateBasic(); err != nil { + return err + } + return host.ClientIdentifierValidator(msg.ClientId) +} + +// GetSignBytes implements sdk.Msg +func (msg MsgCreateClient) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgCreateClient) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +// NewMsgUpdateClient creates a new MsgUpdateClient instance +func NewMsgUpdateClient(id string, header exported.Header, signer sdk.AccAddress) (*MsgUpdateClient, error) { + anyHeader, err := PackHeader(header) + if err != nil { + return nil, err + } + + return &MsgUpdateClient{ + ClientId: id, + Header: anyHeader, + Signer: signer, + }, nil +} + +// Route implements sdk.Msg +func (msg MsgUpdateClient) Route() string { + return host.RouterKey +} + +// Type implements sdk.Msg +func (msg MsgUpdateClient) Type() string { + return TypeMsgUpdateClient +} + +// ValidateBasic implements sdk.Msg +func (msg MsgUpdateClient) ValidateBasic() error { + if msg.Signer.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "signer address cannot be empty") + } + header, err := UnpackHeader(msg.Header) + if err != nil { + return err + } + if err := header.ValidateBasic(); err != nil { + return err + } + if msg.ClientId == exported.ClientTypeLocalHost { + return sdkerrors.Wrap(ErrInvalidClient, "localhost client is only updated on ABCI BeginBlock") + } + return host.ClientIdentifierValidator(msg.ClientId) +} + +// GetSignBytes implements sdk.Msg +func (msg MsgUpdateClient) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg)) +} + +// GetSigners implements sdk.Msg +func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} + +// NewMsgSubmitMisbehaviour creates a new MsgSubmitMisbehaviour instance. +func NewMsgSubmitMisbehaviour(clientID string, misbehaviour exported.Misbehaviour, signer sdk.AccAddress) (*MsgSubmitMisbehaviour, error) { + anyMisbehaviour, err := PackMisbehaviour(misbehaviour) + if err != nil { + return nil, err + } + + return &MsgSubmitMisbehaviour{ + ClientId: clientID, + Misbehaviour: anyMisbehaviour, + Signer: signer, + }, nil +} + +// Route returns the MsgSubmitClientMisbehaviour's route. +func (msg MsgSubmitMisbehaviour) Route() string { return host.RouterKey } + +// Type returns the MsgSubmitMisbehaviour's type. +func (msg MsgSubmitMisbehaviour) Type() string { + return TypeMsgSubmitMisbehaviour +} + +// ValidateBasic performs basic (non-state-dependant) validation on a MsgSubmitMisbehaviour. +func (msg MsgSubmitMisbehaviour) ValidateBasic() error { + if msg.Signer.Empty() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "signer address cannot be empty") + } + misbehaviour, err := UnpackMisbehaviour(msg.Misbehaviour) + if err != nil { + return err + } + if err := misbehaviour.ValidateBasic(); err != nil { + return err + } + if misbehaviour.GetClientID() != msg.ClientId { + return sdkerrors.Wrapf( + ErrInvalidMisbehaviour, + "misbehaviour client-id doesn't match client-id from message (%s ≠ %s)", + misbehaviour.GetClientID(), msg.ClientId, + ) + } + + return host.ClientIdentifierValidator(msg.ClientId) +} + +// GetSignBytes returns the raw bytes a signer is expected to sign when submitting +// a MsgSubmitMisbehaviour message. +func (msg MsgSubmitMisbehaviour) GetSignBytes() []byte { + return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg)) +} + +// GetSigners returns the single expected signer for a MsgSubmitMisbehaviour. +func (msg MsgSubmitMisbehaviour) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.Signer} +} diff --git a/x/ibc/02-client/types/msgs_test.go b/x/ibc/02-client/types/msgs_test.go new file mode 100644 index 0000000000..b35f4de0f1 --- /dev/null +++ b/x/ibc/02-client/types/msgs_test.go @@ -0,0 +1,316 @@ +package types_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + "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" + localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" + solomachinetypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine/types" + ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" +) + +type TypesTestSuite struct { + suite.Suite + + chain *ibctesting.TestChain +} + +func (suite *TypesTestSuite) SetupTest() { + coordinator := ibctesting.NewCoordinator(suite.T(), 1) + suite.chain = coordinator.GetChain(ibctesting.GetChainID(0)) +} + +func TestTypesTestSuite(t *testing.T) { + suite.Run(t, new(TypesTestSuite)) +} + +func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { + var ( + msg = &types.MsgCreateClient{} + err error + ) + + cases := []struct { + name string + malleate func() + expPass bool + }{ + { + "invalid client-id", + func() { + msg.ClientId = "" + }, + false, + }, + { + "valid - tendermint client", + func() { + tendermintClient := ibctmtypes.NewClientState(suite.chain.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs()) + msg, err = types.NewMsgCreateClient("tendermint", tendermintClient, suite.chain.CreateTMClientHeader().ConsensusState(), suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + true, + }, + { + "invalid tendermint client", + func() { + msg, err = types.NewMsgCreateClient("tendermint", &ibctmtypes.ClientState{}, suite.chain.CreateTMClientHeader().ConsensusState(), suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + false, + }, + { + "failed to unpack client", + func() { + msg.ClientState = nil + }, + false, + }, + { + "failed to unpack consensus state", + func() { + tendermintClient := ibctmtypes.NewClientState(suite.chain.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs()) + msg, err = types.NewMsgCreateClient("tendermint", tendermintClient, suite.chain.CreateTMClientHeader().ConsensusState(), suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + msg.ConsensusState = nil + }, + false, + }, + { + "invalid signer", + func() { + msg.Signer = nil + }, + false, + }, + { + "valid - solomachine client", + func() { + soloMachine := ibctesting.NewSolomachine(suite.T(), "solomachine") + msg, err = types.NewMsgCreateClient(soloMachine.ClientID, soloMachine.ClientState(), soloMachine.ConsensusState(), suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + true, + }, + { + "invalid solomachine client", + func() { + soloMachine := ibctesting.NewSolomachine(suite.T(), "solomachine") + msg, err = types.NewMsgCreateClient(soloMachine.ClientID, &solomachinetypes.ClientState{}, soloMachine.ConsensusState(), suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + false, + }, + { + "invalid solomachine consensus state", + func() { + soloMachine := ibctesting.NewSolomachine(suite.T(), "solomachine") + msg, err = types.NewMsgCreateClient(soloMachine.ClientID, soloMachine.ClientState(), &solomachinetypes.ConsensusState{}, suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + false, + }, + { + "unsupported - localhost client", + func() { + localhostClient := localhosttypes.NewClientState(suite.chain.ChainID, types.NewHeight(0, uint64(suite.chain.LastHeader.Header.Height))) + msg, err = types.NewMsgCreateClient("localhost", localhostClient, suite.chain.LastHeader.ConsensusState(), suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + false, + }, + } + + for _, tc := range cases { + tc.malleate() + err = msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + } +} + +func (suite *TypesTestSuite) TestMsgUpdateClient_ValidateBasic() { + var ( + msg = &types.MsgUpdateClient{} + err error + ) + + cases := []struct { + name string + malleate func() + expPass bool + }{ + { + "invalid client-id", + func() { + msg.ClientId = "" + }, + false, + }, + { + "valid - tendermint header", + func() { + msg, err = types.NewMsgUpdateClient("tendermint", suite.chain.CreateTMClientHeader(), suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + true, + }, + { + "invalid tendermint header", + func() { + msg, err = types.NewMsgUpdateClient("tendermint", &ibctmtypes.Header{}, suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + false, + }, + { + "failed to unpack header", + func() { + msg.Header = nil + }, + false, + }, + { + "invalid signer", + func() { + msg.Signer = nil + }, + false, + }, + { + "valid - solomachine header", + func() { + soloMachine := ibctesting.NewSolomachine(suite.T(), "solomachine") + msg, err = types.NewMsgUpdateClient(soloMachine.ClientID, soloMachine.CreateHeader(), suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + true, + }, + { + "invalid solomachine header", + func() { + msg, err = types.NewMsgUpdateClient("solomachine", &solomachinetypes.Header{}, suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + false, + }, + { + "unsupported - localhost", + func() { + msg, err = types.NewMsgUpdateClient(exported.ClientTypeLocalHost, suite.chain.CreateTMClientHeader(), suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + false, + }, + } + + for _, tc := range cases { + tc.malleate() + err = msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + } +} + +func (suite *TypesTestSuite) TestMsgSubmitMisbehaviour_ValidateBasic() { + var ( + msg = &types.MsgSubmitMisbehaviour{} + err error + ) + + cases := []struct { + name string + malleate func() + expPass bool + }{ + { + "invalid client-id", + func() { + msg.ClientId = "" + }, + false, + }, + { + "valid - tendermint misbehaviour", + func() { + header1 := ibctmtypes.CreateTestHeader(suite.chain.ChainID, suite.chain.CurrentHeader.Height, suite.chain.CurrentHeader.Height-1, suite.chain.CurrentHeader.Time, suite.chain.Vals, suite.chain.Vals, suite.chain.Signers) + header2 := ibctmtypes.CreateTestHeader(suite.chain.ChainID, suite.chain.CurrentHeader.Height, suite.chain.CurrentHeader.Height-1, suite.chain.CurrentHeader.Time.Add(time.Minute), suite.chain.Vals, suite.chain.Vals, suite.chain.Signers) + + misbehaviour := ibctmtypes.NewMisbehaviour("tendermint", suite.chain.ChainID, header1, header2) + msg, err = types.NewMsgSubmitMisbehaviour("tendermint", misbehaviour, suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + true, + }, + { + "invalid tendermint misbehaviour", + func() { + msg, err = types.NewMsgSubmitMisbehaviour("tendermint", &ibctmtypes.Misbehaviour{}, suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + false, + }, + { + "failed to unpack misbehaviourt", + func() { + msg.Misbehaviour = nil + }, + false, + }, + { + "invalid signer", + func() { + msg.Signer = nil + }, + false, + }, + { + "valid - solomachine misbehaviour", + func() { + soloMachine := ibctesting.NewSolomachine(suite.T(), "solomachine") + msg, err = types.NewMsgSubmitMisbehaviour(soloMachine.ClientID, soloMachine.CreateMisbehaviour(), suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + true, + }, + { + "invalid solomachine misbehaviour", + func() { + msg, err = types.NewMsgSubmitMisbehaviour("solomachine", &solomachinetypes.Misbehaviour{}, suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + false, + }, + { + "client-id mismatch", + func() { + soloMachineMisbehaviour := ibctesting.NewSolomachine(suite.T(), "solomachine").CreateMisbehaviour() + msg, err = types.NewMsgSubmitMisbehaviour("external", soloMachineMisbehaviour, suite.chain.SenderAccount.GetAddress()) + suite.Require().NoError(err) + }, + false, + }, + } + + for _, tc := range cases { + tc.malleate() + err = msg.ValidateBasic() + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + } +} diff --git a/x/ibc/07-tendermint/client/cli/tx.go b/x/ibc/07-tendermint/client/cli/tx.go index d34794f10c..7c9ab3e661 100644 --- a/x/ibc/07-tendermint/client/cli/tx.go +++ b/x/ibc/07-tendermint/client/cli/tx.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/version" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" ) @@ -110,10 +111,24 @@ func NewCreateClientCmd() *cobra.Command { } } - msg := types.NewMsgCreateClient( - clientID, header, trustLevel, trustingPeriod, ubdPeriod, maxClockDrift, specs, clientCtx.GetFromAddress(), + // validate header + if err := header.ValidateBasic(); err != nil { + return err + } + + clientState := types.NewClientState( + header.GetHeader().GetChainID(), trustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(0, header.GetHeight()), specs, ) + consensusState := header.ConsensusState() + + msg, err := clienttypes.NewMsgCreateClient( + clientID, clientState, consensusState, clientCtx.GetFromAddress(), + ) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { return err } @@ -164,7 +179,11 @@ func NewUpdateClientCmd() *cobra.Command { } } - msg := types.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress()) + msg, err := clienttypes.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { return err } @@ -212,7 +231,11 @@ func NewSubmitMisbehaviourCmd() *cobra.Command { } } - msg := types.NewMsgSubmitClientMisbehaviour(m, clientCtx.GetFromAddress()) + msg, err := clienttypes.NewMsgSubmitMisbehaviour(m.ClientId, m, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/ibc/07-tendermint/types/codec.go b/x/ibc/07-tendermint/types/codec.go index 85eaee89a2..9a8028006e 100644 --- a/x/ibc/07-tendermint/types/codec.go +++ b/x/ibc/07-tendermint/types/codec.go @@ -21,6 +21,10 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { (*clientexported.Misbehaviour)(nil), &Misbehaviour{}, ) + registry.RegisterImplementations( + (*clientexported.Misbehaviour)(nil), + &Misbehaviour{}, + ) } var ( diff --git a/x/ibc/07-tendermint/types/header.go b/x/ibc/07-tendermint/types/header.go index bfd8eb070a..533e227bb0 100644 --- a/x/ibc/07-tendermint/types/header.go +++ b/x/ibc/07-tendermint/types/header.go @@ -55,7 +55,7 @@ func (h Header) GetTime() time.Time { // that validatorsets are not nil. // NOTE: TrustedHeight and TrustedValidators may be empty when creating client // with MsgCreateClient -func (h Header) ValidateBasic(chainID string) error { +func (h Header) ValidateBasic() error { if h.SignedHeader == nil { return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "tendermint signed header cannot be nil") } @@ -66,7 +66,7 @@ func (h Header) ValidateBasic(chainID string) error { if err != nil { return sdkerrors.Wrap(err, "header is not a tendermint header") } - if err := tmSignedHeader.ValidateBasic(chainID); err != nil { + if err := tmSignedHeader.ValidateBasic(h.Header.GetChainID()); err != nil { return sdkerrors.Wrap(err, "header failed basic validation") } diff --git a/x/ibc/07-tendermint/types/header_test.go b/x/ibc/07-tendermint/types/header_test.go index 833191e084..58b1854103 100644 --- a/x/ibc/07-tendermint/types/header_test.go +++ b/x/ibc/07-tendermint/types/header_test.go @@ -3,6 +3,8 @@ package types_test import ( "time" + tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" + 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" @@ -26,8 +28,7 @@ func (suite *TendermintTestSuite) TestGetTime() { func (suite *TendermintTestSuite) TestHeaderValidateBasic() { var ( - header *types.Header - chainID string + header *types.Header ) testCases := []struct { name string @@ -41,9 +42,12 @@ func (suite *TendermintTestSuite) TestHeaderValidateBasic() { {"signed header is nil", func() { header.SignedHeader = nil }, false}, + {"SignedHeaderFromProto failed", func() { + header.SignedHeader.Commit.Height = -1 + }, false}, {"signed header failed tendermint ValidateBasic", func() { header = suite.chainA.LastHeader - chainID = "chainid" + header.SignedHeader.Commit = nil }, false}, {"trusted height is greater than header height", func() { header.TrustedHeight = clienttypes.NewHeight(0, header.GetHeight()+1) @@ -51,6 +55,9 @@ func (suite *TendermintTestSuite) TestHeaderValidateBasic() { {"validator set nil", func() { header.ValidatorSet = nil }, false}, + {"ValidatorSetFromProto failed", func() { + header.ValidatorSet.Validators[0].PubKey = tmprotocrypto.PublicKey{} + }, false}, {"header validator hash does not equal hash of validator set", func() { // use chainB's randomly generated validator set header.ValidatorSet = suite.chainB.LastHeader.ValidatorSet @@ -65,12 +72,11 @@ func (suite *TendermintTestSuite) TestHeaderValidateBasic() { suite.Run(tc.name, func() { suite.SetupTest() - chainID = suite.chainA.ChainID // must be explicitly changed in malleate header = suite.chainA.LastHeader // must be explicitly changed in malleate tc.malleate() - err := header.ValidateBasic(chainID) + err := header.ValidateBasic() if tc.expPass { suite.Require().NoError(err) diff --git a/x/ibc/07-tendermint/types/misbehaviour.go b/x/ibc/07-tendermint/types/misbehaviour.go index 2bf6b9beb0..83ca08d7af 100644 --- a/x/ibc/07-tendermint/types/misbehaviour.go +++ b/x/ibc/07-tendermint/types/misbehaviour.go @@ -91,13 +91,13 @@ func (misbehaviour Misbehaviour) ValidateBasic() error { } // ValidateBasic on both validators - if err := misbehaviour.Header1.ValidateBasic(misbehaviour.ChainId); err != nil { + if err := misbehaviour.Header1.ValidateBasic(); err != nil { return sdkerrors.Wrap( clienttypes.ErrInvalidMisbehaviour, sdkerrors.Wrap(err, "header 1 failed validation").Error(), ) } - if err := misbehaviour.Header2.ValidateBasic(misbehaviour.ChainId); err != nil { + if err := misbehaviour.Header2.ValidateBasic(); err != nil { return sdkerrors.Wrap( clienttypes.ErrInvalidMisbehaviour, sdkerrors.Wrap(err, "header 2 failed validation").Error(), @@ -119,7 +119,7 @@ func (misbehaviour Misbehaviour) ValidateBasic() error { // Ensure that Commit Hashes are different if blockID1.Equals(*blockID2) { - return sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "headers blockIDs are not equal") + return sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "headers blockIDs are equal") } if err := ValidCommit(misbehaviour.ChainId, misbehaviour.Header1.Commit, misbehaviour.Header1.ValidatorSet); err != nil { return err diff --git a/x/ibc/07-tendermint/types/misbehaviour_handle_test.go b/x/ibc/07-tendermint/types/misbehaviour_handle_test.go index b5b662844d..ddc0bc1281 100644 --- a/x/ibc/07-tendermint/types/misbehaviour_handle_test.go +++ b/x/ibc/07-tendermint/types/misbehaviour_handle_test.go @@ -75,6 +75,20 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { suite.now, true, }, + { + "invalid misbehavior misbehaviour from different chain", + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, bothValsHash), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, bothValsHash), + &types.Misbehaviour{ + Header1: types.CreateTestHeader("ethermint", int64(height.EpochHeight), int64(height.EpochHeight), suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader("ethermint", int64(height.EpochHeight), int64(height.EpochHeight), suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + ChainId: "ethermint", + ClientId: chainID, + }, + suite.now, + false, + }, { "valid misbehavior misbehaviour with different trusted heights", types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), diff --git a/x/ibc/07-tendermint/types/misbehaviour_test.go b/x/ibc/07-tendermint/types/misbehaviour_test.go index 8eb23ac033..9e2df19061 100644 --- a/x/ibc/07-tendermint/types/misbehaviour_test.go +++ b/x/ibc/07-tendermint/types/misbehaviour_test.go @@ -166,6 +166,17 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { func(misbehaviour *types.Misbehaviour) error { return nil }, false, }, + { + "wrong chainID in misbehaviour", + &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader(chainID, int64(height.EpochHeight), int64(height.EpochHeight-1), suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers), + ChainId: "ethermint", + ClientId: clientID, + }, + func(misbehaviour *types.Misbehaviour) error { return nil }, + false, + }, { "mismatched heights", &types.Misbehaviour{ diff --git a/x/ibc/07-tendermint/types/msgs.go b/x/ibc/07-tendermint/types/msgs.go deleted file mode 100644 index c01e07618a..0000000000 --- a/x/ibc/07-tendermint/types/msgs.go +++ /dev/null @@ -1,231 +0,0 @@ -package types - -import ( - "time" - - ics23 "github.com/confio/ics23/go" - "github.com/tendermint/tendermint/light" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" - commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" - host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" -) - -var ( - _ clientexported.MsgCreateClient = (*MsgCreateClient)(nil) - _ clientexported.MsgUpdateClient = (*MsgUpdateClient)(nil) - _ clientexported.MsgSubmitMisbehaviour = (*MsgSubmitClientMisbehaviour)(nil) -) - -// NewMsgCreateClient creates a new MsgCreateClient instance -func NewMsgCreateClient( - id string, header *Header, trustLevel Fraction, - trustingPeriod, unbondingPeriod, maxClockDrift time.Duration, - specs []*ics23.ProofSpec, signer sdk.AccAddress, -) *MsgCreateClient { - - return &MsgCreateClient{ - ClientId: id, - Header: header, - TrustLevel: trustLevel, - TrustingPeriod: trustingPeriod, - UnbondingPeriod: unbondingPeriod, - MaxClockDrift: maxClockDrift, - ProofSpecs: specs, - Signer: signer, - } -} - -// Route implements sdk.Msg -func (msg MsgCreateClient) Route() string { - return host.RouterKey -} - -// Type implements sdk.Msg -func (msg MsgCreateClient) Type() string { - return clientexported.TypeMsgCreateClient -} - -// ValidateBasic implements sdk.Msg -func (msg MsgCreateClient) ValidateBasic() error { - if msg.TrustingPeriod == 0 { - return sdkerrors.Wrap(ErrInvalidTrustingPeriod, "duration cannot be 0") - } - if err := light.ValidateTrustLevel(msg.TrustLevel.ToTendermint()); err != nil { - return sdkerrors.Wrap(err, "invalid trust level for tendermint light client") - } - if msg.UnbondingPeriod == 0 { - return sdkerrors.Wrap(ErrInvalidUnbondingPeriod, "duration cannot be 0") - } - if msg.Signer.Empty() { - return sdkerrors.ErrInvalidAddress - } - - if msg.Header == nil || msg.Header.SignedHeader == nil || msg.Header.SignedHeader.Header == nil { - return sdkerrors.Wrap(ErrInvalidHeader, "header cannot be nil") - } - // ValidateBasic of provided header with self-attested chain-id - if err := msg.Header.ValidateBasic(msg.Header.Header.GetChainID()); err != nil { - return sdkerrors.Wrapf(ErrInvalidHeader, "header failed validatebasic with its own chain-id: %v", err) - } - if msg.TrustingPeriod >= msg.UnbondingPeriod { - return sdkerrors.Wrapf( - ErrInvalidTrustingPeriod, - "trusting period (%s) should be < unbonding period (%s)", msg.TrustingPeriod, msg.UnbondingPeriod, - ) - } - // Validate ProofSpecs - if msg.ProofSpecs == nil { - return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof specs cannot be nil") - } - for _, spec := range msg.ProofSpecs { - if spec == nil { - return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof spec cannot be nil") - } - } - return host.ClientIdentifierValidator(msg.ClientId) -} - -// GetSignBytes implements sdk.Msg -func (msg MsgCreateClient) GetSignBytes() []byte { - return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg)) -} - -// GetSigners implements sdk.Msg -func (msg MsgCreateClient) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -// 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 { - // Construct initial consensus state from provided Header - root := commitmenttypes.NewMerkleRoot(msg.Header.Header.GetAppHash()) - // NOTE: Using 0 for epoch number for now - // TODO: Use clienttypes.Height in Header once Header.GetHeight returns *clienttypes.Height - return &ConsensusState{ - Timestamp: msg.Header.GetTime(), - Root: root, - Height: clienttypes.NewHeight(0, msg.Header.GetHeight()), - NextValidatorsHash: msg.Header.Header.NextValidatorsHash, - } -} - -// InitializeFromMsg creates a tendermint client state from a CreateClientMsg -func (msg MsgCreateClient) InitializeClientState() clientexported.ClientState { - return NewClientState(msg.Header.Header.GetChainID(), msg.TrustLevel, - msg.TrustingPeriod, msg.UnbondingPeriod, msg.MaxClockDrift, - clienttypes.NewHeight(0, msg.Header.GetHeight()), msg.ProofSpecs, - ) -} - -// NewMsgUpdateClient creates a new MsgUpdateClient instance -func NewMsgUpdateClient(id string, header *Header, signer sdk.AccAddress) *MsgUpdateClient { - return &MsgUpdateClient{ - ClientId: id, - Header: header, - Signer: signer, - } -} - -// Route implements sdk.Msg -func (msg MsgUpdateClient) Route() string { - return host.RouterKey -} - -// Type implements sdk.Msg -func (msg MsgUpdateClient) Type() string { - return clientexported.TypeMsgUpdateClient -} - -// ValidateBasic implements sdk.Msg -func (msg MsgUpdateClient) ValidateBasic() error { - if msg.Signer.Empty() { - return sdkerrors.ErrInvalidAddress - } - if msg.Header == nil || msg.Header.SignedHeader == nil || msg.Header.Header == nil { - return sdkerrors.Wrap(ErrInvalidHeader, "header cannot be nil") - } - // ValidateBasic of provided header with self-attested chain-id - if err := msg.Header.ValidateBasic(msg.Header.Header.GetChainID()); err != nil { - return err - } - return host.ClientIdentifierValidator(msg.ClientId) -} - -// GetSignBytes implements sdk.Msg -func (msg MsgUpdateClient) GetSignBytes() []byte { - return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg)) -} - -// GetSigners implements sdk.Msg -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 -} - -// NewMsgSubmitClientMisbehaviour creates a new MsgSubmitClientMisbehaviour -// instance. -func NewMsgSubmitClientMisbehaviour(m *Misbehaviour, s sdk.AccAddress) *MsgSubmitClientMisbehaviour { - return &MsgSubmitClientMisbehaviour{Misbehaviour: m, Signer: s} -} - -// Route returns the MsgSubmitClientMisbehaviour's route. -func (msg MsgSubmitClientMisbehaviour) Route() string { return host.RouterKey } - -// Type returns the MsgSubmitClientMisbehaviour's type. -func (msg MsgSubmitClientMisbehaviour) Type() string { - return clientexported.TypeMsgSubmitClientMisbehaviour -} - -// ValidateBasic performs basic (non-state-dependant) validation on a MsgSubmitClientMisbehaviour. -func (msg MsgSubmitClientMisbehaviour) ValidateBasic() error { - if msg.Misbehaviour == nil { - return sdkerrors.Wrap(evidencetypes.ErrInvalidEvidence, "missing evidence") - } - if err := msg.Misbehaviour.ValidateBasic(); err != nil { - return err - } - if msg.Signer.Empty() { - return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Signer.String()) - } - - return nil -} - -// GetSignBytes returns the raw bytes a signer is expected to sign when submitting -// a MsgSubmitClientMisbehaviour message. -func (msg MsgSubmitClientMisbehaviour) GetSignBytes() []byte { - return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg)) -} - -// GetSigners returns the single expected signer for a MsgSubmitClientMisbehaviour. -func (msg MsgSubmitClientMisbehaviour) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -func (msg MsgSubmitClientMisbehaviour) GetMisbehaviour() clientexported.Misbehaviour { - return msg.Misbehaviour -} diff --git a/x/ibc/07-tendermint/types/msgs_test.go b/x/ibc/07-tendermint/types/msgs_test.go deleted file mode 100644 index 7d22b8b247..0000000000 --- a/x/ibc/07-tendermint/types/msgs_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package types_test - -import ( - ics23 "github.com/confio/ics23/go" - tmtypes "github.com/tendermint/tendermint/types" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - types "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" - commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" -) - -func (suite *TendermintTestSuite) TestMsgCreateClientValidateBasic() { - privKey := secp256k1.GenPrivKey() - signer := sdk.AccAddress(privKey.PubKey().Address()) - invalidHeader := types.CreateTestHeader(suite.header.Header.GetChainID(), int64(height.EpochHeight), 0, suite.now, suite.valSet, nil, []tmtypes.PrivValidator{suite.privVal}) - invalidHeader.ValidatorSet = nil - - cases := []struct { - msg *types.MsgCreateClient - expPass bool - errMsg string - }{ - {types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), true, "success msg should pass"}, - {types.NewMsgCreateClient("(BADCHAIN)", suite.header, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "invalid client id passed"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "invalid trust level"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "zero trusting period passed"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "zero unbonding period passed"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), nil), false, "Empty address passed"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, &types.Header{}, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "empty header"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, nil, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "nil header"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, &types.Header{SignedHeader: nil}, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "nil header"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, &types.Header{SignedHeader: &tmproto.SignedHeader{Header: nil}}, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "nil header"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, invalidHeader, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "invalid header"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, []*ics23.ProofSpec{nil}, signer), false, "invalid proof specs"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, nil, signer), false, "nil proof specs"}, - {types.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, types.DefaultTrustLevel, ubdPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "trusting period not less than unbonding period"}, - } - - for i, tc := range cases { - err := tc.msg.ValidateBasic() - if tc.expPass { - suite.Require().NoError(err, "Msg %d failed: %v", i, tc.errMsg) - } else { - suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) - } - } -} - -func (suite *TendermintTestSuite) TestMsgUpdateClient() { - privKey := secp256k1.GenPrivKey() - signer := sdk.AccAddress(privKey.PubKey().Address()) - - cases := []struct { - msg *types.MsgUpdateClient - expPass bool - errMsg string - }{ - {types.NewMsgUpdateClient(exported.ClientTypeTendermint, suite.header, signer), true, "success msg should pass"}, - {types.NewMsgUpdateClient("(badClient)", &types.Header{}, signer), false, "invalid client id passed"}, - {types.NewMsgUpdateClient(exported.ClientTypeTendermint, suite.header, nil), false, "Empty address passed"}, - {types.NewMsgUpdateClient(exported.ClientTypeTendermint, &types.Header{}, nil), false, "empty Header"}, - {types.NewMsgUpdateClient(exported.ClientTypeTendermint, nil, nil), false, "nil header"}, - {types.NewMsgUpdateClient(exported.ClientTypeTendermint, &types.Header{SignedHeader: nil}, nil), false, "nil signed header"}, - {types.NewMsgUpdateClient(exported.ClientTypeTendermint, &types.Header{SignedHeader: &tmproto.SignedHeader{Header: nil}}, nil), false, "nil tendermint header"}, - } - - for i, tc := range cases { - err := tc.msg.ValidateBasic() - if tc.expPass { - suite.Require().NoError(err, "Msg %d failed: %v", i, err) - } else { - suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) - } - } -} diff --git a/x/ibc/07-tendermint/types/update_test.go b/x/ibc/07-tendermint/types/update_test.go index de80166b23..4fdc6fa760 100644 --- a/x/ibc/07-tendermint/types/update_test.go +++ b/x/ibc/07-tendermint/types/update_test.go @@ -87,6 +87,16 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { }, expPass: true, }, + { + name: "unsuccessful update with incorrect header chain-id", + setup: func() { + clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()) + consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), height, suite.valsHash) + newHeader = types.CreateTestHeader("ethermint", int64(height.EpochHeight+1), int64(height.EpochHeight), suite.headerTime, suite.valSet, suite.valSet, signers) + currentTime = suite.now + }, + expPass: false, + }, { name: "unsuccessful update with next height: update header mismatches nextValSetHash", setup: func() { diff --git a/x/ibc/09-localhost/client/cli/cli.go b/x/ibc/09-localhost/client/cli/cli.go deleted file mode 100644 index 5ab6d0f23b..0000000000 --- a/x/ibc/09-localhost/client/cli/cli.go +++ /dev/null @@ -1,23 +0,0 @@ -package cli - -import ( - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types" -) - -// NewTxCmd returns a root CLI command handler for all ibc localhost transaction commands. -func NewTxCmd() *cobra.Command { - txCmd := &cobra.Command{ - Use: types.SubModuleName, - Short: "Localhost client transaction subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - } - - txCmd.AddCommand( - NewCreateClientCmd(), - ) - - return txCmd -} diff --git a/x/ibc/09-localhost/client/cli/tx.go b/x/ibc/09-localhost/client/cli/tx.go deleted file mode 100644 index 0e29c67c19..0000000000 --- a/x/ibc/09-localhost/client/cli/tx.go +++ /dev/null @@ -1,44 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types" - host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" -) - -// NewCreateClientCmd defines the command to create a new IBC Loopback Client as defined -// in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create -func NewCreateClientCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "create", - Short: "create new localhost client", - Long: "create new localhost (loopback) client", - Example: fmt.Sprintf("%s tx %s %s create --from node0 --home ../node0/cli --chain-id $CID", version.AppName, host.ModuleName, types.SubModuleName), - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, _ []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags()) - if err != nil { - return err - } - - msg := types.NewMsgCreateClient(clientCtx.GetFromAddress()) - if err := msg.ValidateBasic(); err != nil { - return err - } - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/x/ibc/09-localhost/module.go b/x/ibc/09-localhost/module.go index 8a94b73a58..33a5876c01 100644 --- a/x/ibc/09-localhost/module.go +++ b/x/ibc/09-localhost/module.go @@ -1,9 +1,6 @@ package localhost import ( - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/client/cli" "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types" ) @@ -11,8 +8,3 @@ import ( func Name() string { return types.SubModuleName } - -// GetTxCmd returns the root tx command for the IBC localhost client -func GetTxCmd() *cobra.Command { - return cli.NewTxCmd() -} diff --git a/x/ibc/09-localhost/types/codec.go b/x/ibc/09-localhost/types/codec.go index 7cac129d52..61da5ed952 100644 --- a/x/ibc/09-localhost/types/codec.go +++ b/x/ibc/09-localhost/types/codec.go @@ -3,17 +3,12 @@ package types import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - sdk "github.com/cosmos/cosmos-sdk/types" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ) // RegisterInterfaces register the ibc interfaces submodule implementations to protobuf // Any. func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterImplementations( - (*sdk.Msg)(nil), - &MsgCreateClient{}, - ) registry.RegisterImplementations( (*clientexported.ClientState)(nil), &ClientState{}, diff --git a/x/ibc/09-localhost/types/msgs.go b/x/ibc/09-localhost/types/msgs.go deleted file mode 100644 index b43d02c0ea..0000000000 --- a/x/ibc/09-localhost/types/msgs.go +++ /dev/null @@ -1,69 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" -) - -var ( - _ clientexported.MsgCreateClient = (*MsgCreateClient)(nil) -) - -// NewMsgCreateClient creates a new MsgCreateClient instance -func NewMsgCreateClient(signer sdk.AccAddress) *MsgCreateClient { - return &MsgCreateClient{ - Signer: signer, - } -} - -// Route implements sdk.Msg -func (msg MsgCreateClient) Route() string { - return host.RouterKey -} - -// Type implements sdk.Msg -func (msg MsgCreateClient) Type() string { - return clientexported.TypeMsgCreateClient -} - -// ValidateBasic implements sdk.Msg -func (msg MsgCreateClient) ValidateBasic() error { - if msg.Signer.Empty() { - return sdkerrors.ErrInvalidAddress - } - return nil -} - -// GetSignBytes implements sdk.Msg -func (msg MsgCreateClient) GetSignBytes() []byte { - return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg)) -} - -// GetSigners implements sdk.Msg -func (msg MsgCreateClient) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -// GetClientID implements clientexported.MsgCreateClient -func (msg MsgCreateClient) GetClientID() string { - return clientexported.ClientTypeLocalHost -} - -// GetClientType implements clientexported.MsgCreateClient -func (msg MsgCreateClient) GetClientType() string { - return clientexported.ClientTypeLocalHost -} - -// GetConsensusState implements clientexported.MsgCreateClient -func (msg MsgCreateClient) GetConsensusState() clientexported.ConsensusState { - return nil -} - -// InitializeClientState implements clientexported.MsgCreateClient -// localhost is a special case that require the running chain's context to initialize -// the client state, thus this function is a no-op -func (msg MsgCreateClient) InitializeClientState() clientexported.ClientState { - return nil -} diff --git a/x/ibc/client/cli/cli.go b/x/ibc/client/cli/cli.go index 0f35ea0da4..90fdfdf75f 100644 --- a/x/ibc/client/cli/cli.go +++ b/x/ibc/client/cli/cli.go @@ -8,8 +8,8 @@ import ( 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" - localhost "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" + "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine" ) // GetTxCmd returns the transaction commands for this module @@ -23,8 +23,8 @@ func GetTxCmd() *cobra.Command { } ibcTxCmd.AddCommand( + solomachine.GetTxCmd(), tendermint.GetTxCmd(), - localhost.GetTxCmd(), connection.GetTxCmd(), channel.GetTxCmd(), ) diff --git a/x/ibc/handler.go b/x/ibc/handler.go index d26a730c72..f173d8b77d 100644 --- a/x/ibc/handler.go +++ b/x/ibc/handler.go @@ -4,7 +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" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" @@ -20,13 +20,13 @@ func NewHandler(k keeper.Keeper) sdk.Handler { switch msg := msg.(type) { // IBC client msg interface types - case clientexported.MsgCreateClient: + case *clienttypes.MsgCreateClient: return client.HandleMsgCreateClient(ctx, k.ClientKeeper, msg) - case clientexported.MsgUpdateClient: + case *clienttypes.MsgUpdateClient: return client.HandleMsgUpdateClient(ctx, k.ClientKeeper, msg) - case clientexported.MsgSubmitMisbehaviour: + case *clienttypes.MsgSubmitMisbehaviour: return client.HandleMsgSubmitMisbehaviour(ctx, k.ClientKeeper, msg) // IBC connection msgs diff --git a/x/ibc/light-clients/solomachine/client/cli/tx.go b/x/ibc/light-clients/solomachine/client/cli/tx.go index 99b41200f2..0d8350424d 100644 --- a/x/ibc/light-clients/solomachine/client/cli/tx.go +++ b/x/ibc/light-clients/solomachine/client/cli/tx.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/version" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine/types" ) @@ -46,7 +47,11 @@ func NewCreateClientCmd() *cobra.Command { } } - msg := types.NewMsgCreateClient(clientID, consensusState) + clientState := types.NewClientState(consensusState) + msg, err := clienttypes.NewMsgCreateClient(clientID, clientState, consensusState, clientCtx.GetFromAddress()) + if err != nil { + return err + } if err := msg.ValidateBasic(); err != nil { return err @@ -88,7 +93,11 @@ func NewUpdateClientCmd() *cobra.Command { } } - msg := types.NewMsgUpdateClient(clientID, header) + msg, err := clienttypes.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { return err } @@ -128,7 +137,11 @@ func NewSubmitMisbehaviourCmd() *cobra.Command { } } - msg := types.NewMsgSubmitClientMisbehaviour(m, clientCtx.GetFromAddress()) + msg, err := clienttypes.NewMsgSubmitMisbehaviour(m.ClientId, m, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/ibc/light-clients/solomachine/types/client_state.go b/x/ibc/light-clients/solomachine/types/client_state.go index 39c1cbbe48..6ad4501044 100644 --- a/x/ibc/light-clients/solomachine/types/client_state.go +++ b/x/ibc/light-clients/solomachine/types/client_state.go @@ -57,6 +57,9 @@ func (cs ClientState) GetProofSpecs() []*ics23.ProofSpec { // Validate performs basic validation of the client state fields. func (cs ClientState) Validate() error { + if cs.ConsensusState == nil { + return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be nil") + } return cs.ConsensusState.ValidateBasic() } diff --git a/x/ibc/light-clients/solomachine/types/client_state_test.go b/x/ibc/light-clients/solomachine/types/client_state_test.go index 95cd4f6947..15ab08f365 100644 --- a/x/ibc/light-clients/solomachine/types/client_state_test.go +++ b/x/ibc/light-clients/solomachine/types/client_state_test.go @@ -33,6 +33,11 @@ func (suite *SoloMachineTestSuite) TestClientStateValidateBasic() { suite.solomachine.ClientState(), true, }, + { + "empty ClientState", + &types.ClientState{}, + false, + }, { "sequence is zero", types.NewClientState(&types.ConsensusState{0, suite.solomachine.ConsensusState().PublicKey, suite.solomachine.Time}), diff --git a/x/ibc/light-clients/solomachine/types/codec.go b/x/ibc/light-clients/solomachine/types/codec.go index 7fd02e59e6..396069dd8b 100644 --- a/x/ibc/light-clients/solomachine/types/codec.go +++ b/x/ibc/light-clients/solomachine/types/codec.go @@ -3,19 +3,12 @@ package types import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - sdk "github.com/cosmos/cosmos-sdk/types" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ) // RegisterInterfaces register the ibc channel submodule interfaces to protobuf // Any. func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterImplementations( - (*sdk.Msg)(nil), - &MsgCreateClient{}, - &MsgUpdateClient{}, - &MsgSubmitClientMisbehaviour{}, - ) registry.RegisterImplementations( (*clientexported.ClientState)(nil), &ClientState{}, @@ -24,6 +17,14 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { (*clientexported.ConsensusState)(nil), &ConsensusState{}, ) + registry.RegisterImplementations( + (*clientexported.Header)(nil), + &Header{}, + ) + registry.RegisterImplementations( + (*clientexported.Misbehaviour)(nil), + &Misbehaviour{}, + ) } var ( diff --git a/x/ibc/light-clients/solomachine/types/misbehaviour.go b/x/ibc/light-clients/solomachine/types/misbehaviour.go index 01734c6d32..4148abf166 100644 --- a/x/ibc/light-clients/solomachine/types/misbehaviour.go +++ b/x/ibc/light-clients/solomachine/types/misbehaviour.go @@ -27,7 +27,7 @@ func (misbehaviour Misbehaviour) GetClientID() string { // Type implements Evidence interface. func (misbehaviour Misbehaviour) Type() string { - return clientexported.TypeEvidenceClientMisbehaviour + return clientexported.TypeClientMisbehaviour } // String implements Evidence interface. diff --git a/x/ibc/light-clients/solomachine/types/msgs.go b/x/ibc/light-clients/solomachine/types/msgs.go deleted file mode 100644 index 40d09803e0..0000000000 --- a/x/ibc/light-clients/solomachine/types/msgs.go +++ /dev/null @@ -1,165 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - 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" - host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" -) - -var ( - _ clientexported.MsgCreateClient = &MsgCreateClient{} - _ clientexported.MsgUpdateClient = &MsgUpdateClient{} - _ clientexported.MsgSubmitMisbehaviour = &MsgSubmitClientMisbehaviour{} -) - -// NewMsgCreateClient creates a new MsgCreateClient instance -func NewMsgCreateClient(id string, consensusState *ConsensusState) *MsgCreateClient { - return &MsgCreateClient{ - ClientId: id, - ConsensusState: consensusState, - } -} - -// Route implements sdk.Msg -func (msg MsgCreateClient) Route() string { - return host.RouterKey -} - -// Type implements sdk.Msg -func (msg MsgCreateClient) Type() string { - return clientexported.TypeMsgCreateClient -} - -// ValidateBasic implements sdk.Msg -func (msg MsgCreateClient) ValidateBasic() error { - if msg.ConsensusState == nil { - return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "consensus state cannot be nil") - } - if err := msg.ConsensusState.ValidateBasic(); err != nil { - return err - } - - return host.ClientIdentifierValidator(msg.ClientId) -} - -// GetSignBytes implements sdk.Msg -func (msg MsgCreateClient) GetSignBytes() []byte { - return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg)) -} - -// GetSigners implements sdk.Msg -func (msg MsgCreateClient) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{sdk.AccAddress(msg.ConsensusState.GetPubKey().Address())} -} - -// GetClientID implements clientexported.MsgCreateClient -func (msg MsgCreateClient) GetClientID() string { - return msg.ClientId -} - -// GetClientType implements clientexported.MsgCreateClient -func (msg MsgCreateClient) GetClientType() string { - return clientexported.ClientTypeSoloMachine -} - -// GetConsensusState implements clientexported.MsgCreateClient -func (msg MsgCreateClient) GetConsensusState() clientexported.ConsensusState { - return msg.ConsensusState -} - -// InitializeFromMsg creates a solo machine client state from a MsgCreateClient -func (msg MsgCreateClient) InitializeClientState() clientexported.ClientState { - return NewClientState(msg.ConsensusState) -} - -// NewMsgUpdateClient creates a new MsgUpdateClient instance -func NewMsgUpdateClient(id string, header *Header) *MsgUpdateClient { - return &MsgUpdateClient{ - ClientId: id, - Header: header, - } -} - -// Route implements sdk.Msg -func (msg MsgUpdateClient) Route() string { - return host.RouterKey -} - -// Type implements sdk.Msg -func (msg MsgUpdateClient) Type() string { - return clientexported.TypeMsgUpdateClient -} - -// ValidateBasic implements sdk.Msg -func (msg MsgUpdateClient) ValidateBasic() error { - if msg.Header == nil { - return sdkerrors.Wrap(ErrInvalidHeader, "header cannot be nil") - } - if err := msg.Header.ValidateBasic(); err != nil { - return err - } - return host.ClientIdentifierValidator(msg.ClientId) -} - -// GetSignBytes implements sdk.Msg -func (msg MsgUpdateClient) GetSignBytes() []byte { - return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg)) -} - -// GetSigners implements sdk.Msg -func (msg MsgUpdateClient) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{sdk.AccAddress(msg.Header.GetPubKey().Address())} -} - -// 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 -} - -// NewMsgSubmitClientMisbehaviour creates a new MsgSubmitClientMisbehaviour -// instance. -func NewMsgSubmitClientMisbehaviour(m *Misbehaviour, s sdk.AccAddress) *MsgSubmitClientMisbehaviour { - return &MsgSubmitClientMisbehaviour{Misbehaviour: m, Signer: s} -} - -// Route returns the MsgSubmitClientMisbehaviour's route. -func (msg MsgSubmitClientMisbehaviour) Route() string { return host.RouterKey } - -// Type returns the MsgSubmitClientMisbehaviour's type. -func (msg MsgSubmitClientMisbehaviour) Type() string { - return clientexported.TypeMsgSubmitClientMisbehaviour -} - -// ValidateBasic performs basic (non-state-dependent) validation on a MsgSubmitClientMisbehaviour. -func (msg MsgSubmitClientMisbehaviour) ValidateBasic() error { - if err := msg.Misbehaviour.ValidateBasic(); err != nil { - return err - } - if msg.Signer.Empty() { - return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "signer address cannot be empty") - } - - return nil -} - -// GetSignBytes returns the raw bytes a signer is expected to sign when submitting -// a MsgSubmitClientMisbehaviour message. -func (msg MsgSubmitClientMisbehaviour) GetSignBytes() []byte { - return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(&msg)) -} - -// GetSigners returns the single expected signer for a MsgSubmitClientMisbehaviour. -func (msg MsgSubmitClientMisbehaviour) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Signer} -} - -func (msg MsgSubmitClientMisbehaviour) GetMisbehaviour() clientexported.Misbehaviour { - return msg.Misbehaviour -} diff --git a/x/ibc/light-clients/solomachine/types/msgs_test.go b/x/ibc/light-clients/solomachine/types/msgs_test.go deleted file mode 100644 index 69bb501548..0000000000 --- a/x/ibc/light-clients/solomachine/types/msgs_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package types_test - -import ( - "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine/types" -) - -func (suite *SoloMachineTestSuite) TestMsgCreateClientValidateBasic() { - cases := []struct { - name string - msg *types.MsgCreateClient - expPass bool - }{ - {"valid msg", types.NewMsgCreateClient(suite.solomachine.ClientID, suite.solomachine.ConsensusState()), true}, - {"invalid client id", types.NewMsgCreateClient("(BADCLIENTID)", suite.solomachine.ConsensusState()), false}, - {"nil consensus state", types.NewMsgCreateClient(suite.solomachine.ClientID, nil), false}, - {"invalid consensus state with zero sequence", types.NewMsgCreateClient(suite.solomachine.ClientID, &types.ConsensusState{0, suite.solomachine.ConsensusState().PublicKey, suite.solomachine.Time}), false}, - {"invalid consensus state with zero timestamp", types.NewMsgCreateClient(suite.solomachine.ClientID, &types.ConsensusState{1, suite.solomachine.ConsensusState().PublicKey, 0}), false}, - {"invalid consensus state with nil pubkey", types.NewMsgCreateClient(suite.solomachine.ClientID, &types.ConsensusState{suite.solomachine.Sequence, nil, suite.solomachine.Time}), false}, - } - - for i, tc := range cases { - err := tc.msg.ValidateBasic() - if tc.expPass { - suite.Require().NoError(err, "Msg %d failed: %v", i, tc.name) - } else { - suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.name) - } - } -} - -func (suite *SoloMachineTestSuite) TestMsgUpdateClientValidateBasic() { - header := suite.solomachine.CreateHeader() - - cases := []struct { - name string - msg *types.MsgUpdateClient - expPass bool - }{ - {"valid msg", types.NewMsgUpdateClient(suite.solomachine.ClientID, header), true}, - {"invalid client id", types.NewMsgUpdateClient("(BADCLIENTID)", header), false}, - {"nil header", types.NewMsgUpdateClient(suite.solomachine.ClientID, nil), false}, - {"invalid header - sequence is zero", types.NewMsgUpdateClient(suite.solomachine.ClientID, &types.Header{0, header.Signature, header.NewPublicKey}), false}, - {"invalid header - signature is empty", types.NewMsgUpdateClient(suite.solomachine.ClientID, &types.Header{header.Sequence, []byte{}, header.NewPublicKey}), false}, - {"invalid header - pubkey is empty", types.NewMsgUpdateClient(suite.solomachine.ClientID, &types.Header{header.Sequence, header.Signature, nil}), false}, - } - - for i, tc := range cases { - err := tc.msg.ValidateBasic() - if tc.expPass { - suite.Require().NoError(err, "Msg %d failed: %v", i, tc.name) - } else { - suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.name) - } - } - -} diff --git a/x/ibc/spec/04_messages.md b/x/ibc/spec/04_messages.md index d77ca02642..9949650714 100644 --- a/x/ibc/spec/04_messages.md +++ b/x/ibc/spec/04_messages.md @@ -15,17 +15,17 @@ A light client is created using the `MsgCreateClient`. ```go type MsgCreateClient struct { ClientId string - ClientType string - ConsensusState ConsensusState + ClientState *types.Any // proto-packed client state + ConsensusState *types.Any // proto-packed consensus state Signer sdk.AccAddress } ``` This message is expected to fail if: -- `ClientId` is invalid (not alphanumeric or not within 10-20 characters) -- `ClientType` is not registered -- `ConsensusState` is empty +- `ClientId` is invalid (see naming requirements) +- `ClientState` is empty or invalid +- `ConsensusState` is empty or invalid - `Signer` is empty - A light client with the provided id and type already exist @@ -40,7 +40,7 @@ A light client is updated with a new header using the `MsgUpdateClient`. ```go type MsgUpdateClient struct { ClientId string - Header Header + Header *types.Any // proto-packed header Signer sdk.AccAddress } ``` @@ -48,15 +48,38 @@ type MsgUpdateClient struct { This message is expected to fail if: - `ClientId` is invalid (not alphanumeric or not within 10-20 characters) -- `Header` is empty +- `Header` is empty or invalid - `Signer` is empty -- A Client hasn't been created for the given ID +- A `ClientState` hasn't been created for the given ID - the header's client type is different from the registered one - the client is frozen due to misbehaviour and cannot be updated The message validates the header and updates the consensus state with the new height, commitment root and validator sets, which are then stored. +### MsgSubmitMisbehaviour + +Submit a evidence of light client misbehaviour to freeze the client state and prevent additional packets from being relayed. + +```go +type MsgSubmitMisbehaviour struct { + ClientId string + Misbehaviour *types.Any // proto-packed misbehaviour + Signer sdk.AccAddress +} +``` + +This message is expected to fail if: + +- `ClientId` is invalid (not alphanumeric or not within 10-20 characters) +- `Misbehaviour` is empty or invalid +- `Signer` is empty +- A `ClientState` hasn't been created for the given ID +- `Misbehaviour` check failed + +The message validates the header and updates the consensus state with the new +height, commitment root and validator sets, which are then stored. + ## ICS 03 - Connection ### MsgConnectionOpenInit @@ -89,26 +112,27 @@ using the `MsgConnectionOpenTry`. ```go type MsgConnectionOpenTry struct { - ClientId string - ConnectionId string + ClientId string + ConnectionId string ClientState *types.Any // proto-packed counterparty client - Counterparty Counterparty - CounterpartyVersions []string - ProofHeight uint64 - ProofInit []byte + Counterparty Counterparty + CounterpartyVersions []string + ProofHeight uint64 + ProofInit []byte ProofClient []byte - ProofConsensus []byte + ProofConsensus []byte ConsensusHeight uint64 - Signer sdk.AccAddress + Signer sdk.AccAddress } ``` This message is expected to fail if: + - `ClientId` is invalid (see naming requirements) - `ConnectionId` is invalid (see naming requirements) - `ClientState` is not a valid client of the executing chain - `Counterparty` is empty -- `CounterpartyVersions` is empty +- `CounterpartyVersions` is empty - `ProofHeight` is zero - `ProofInit` is empty - `ProofClient` is empty @@ -130,19 +154,20 @@ using the `MsgConnectionOpenAck`. ```go type MsgConnectionOpenAck struct { - ConnectionId string - Version string + ConnectionId string + Version string ClientState *types.Any // proto-packed counterparty client - ProofHeight uint64 - ProofTry []byte + ProofHeight uint64 + ProofTry []byte ProofClient []byte - ProofConsensus []byte - ConsensusHeight uint64 - Signer sdk.AccAddress + ProofConsensus []byte + ConsensusHeight uint64 + Signer sdk.AccAddress } ``` This message is expected to fail if: + - `ConnectionId` is invalid (see naming requirements) - `Version` is empty - `ClientState` is not a valid client of the executing chain @@ -165,14 +190,15 @@ the `MsgConnectionOpenConfirm`. ```go type MsgConnectionOpenConfirm struct { - ConnectionId string - ProofAck []byte - ProofHeight uint64 - Signer sdk.AccAddress + ConnectionId string + ProofAck []byte + ProofHeight uint64 + Signer sdk.AccAddress } ``` This message is expected to fail if: + - `ConnectionId` is invalid (see naming requirements) - `ProofAck` is empty - `ProofHeight` is zero @@ -199,18 +225,19 @@ type MsgChannelOpenInit struct { ``` This message is expected to fail if: + - `PortId` is invalid (see naming requirements) - `ChannelId` is invalid (see naming requirements) - `Channel` is empty - `Signer` is empty - A Channel End exists for the given Channel ID and Port ID -The message creates a channel on chain A with an INIT state for the given Channel ID +The message creates a channel on chain A with an INIT state for the given Channel ID and Port ID. ### MsgChannelOpenTry -A channel handshake initialization attempt is acknowledged by a chain B using +A channel handshake initialization attempt is acknowledged by a chain B using the `MsgChannelOpenTry` message. ```go @@ -226,6 +253,7 @@ type MsgChannelOpenTry struct { ``` This message is expected to fail if: + - `PortId` is invalid (see naming requirements) - `ChannelId` is invalid (see naming requirements) - `Channel` is empty @@ -245,16 +273,17 @@ A channel handshake is opened by a chain A using the `MsgChannelOpenAck` message ```go type MsgChannelOpenAck struct { - PortId string - ChannelId string - CounterpartyVersion string + PortId string + ChannelId string + CounterpartyVersion string ProofTry []byte ProofHeight uint64 - Signer sdk.AccAddress + Signer sdk.AccAddress } ``` This message is expected to fail if: + - `PortId` is invalid (see naming requirements) - `ChannelId` is invalid (see naming requirements) - `CounterpartyVersion` is empty @@ -272,15 +301,16 @@ message. ```go type MsgChannelOpenConfirm struct { - PortId string - ChannelId string + PortId string + ChannelId string ProofAck []byte ProofHeight uint64 - Signer sdk.AccAddress + Signer sdk.AccAddress } ``` This message is expected to fail if: + - `PortId` is invalid (see naming requirements) - `ChannelId` is invalid (see naming requirements) - `ProofAck` is empty @@ -296,13 +326,14 @@ A channel is closed on chain A using the `MsgChannelCloseInit`. ```go type MsgChannelCloseInit struct { - PortId string - ChannelId string - Signer sdk.AccAddress + PortId string + ChannelId string + Signer sdk.AccAddress } ``` This message is expected to fail if: + - `PortId` is invalid (see naming requirements) - `ChannelId` is invalid (see naming requirements) - `Signer` is empty @@ -316,15 +347,16 @@ A channel is closed on chain B using the `MsgChannelCloseConfirm`. ```go type MsgChannelCloseConfirm struct { - PortId string - ChannelId string + PortId string + ChannelId string ProofInit []byte - ProofHeight uint64 - Signer sdk.AccAddress + ProofHeight uint64 + Signer sdk.AccAddress } ``` This message is expected to fail if: + - `PortId` is invalid (see naming requirements) - `ChannelId` is invalid (see naming requirements) - `ProofInit` is empty @@ -344,11 +376,12 @@ type MsgRecvPacket struct { Packet Packet Proof []byte ProofHeight uint64 - Signer sdk.AccAddress + Signer sdk.AccAddress } ``` This message is expected to fail if: + - `Proof` is empty - `ProofHeight` is zero - `Signer` is empty @@ -363,7 +396,7 @@ A packet is timed out on chain A using the `MsgTimeout`. ```go type MsgTimeout struct { - Packet Packet + Packet Packet Proof []byte ProofHeight uint64 NextSequenceRecv uint64 @@ -372,6 +405,7 @@ type MsgTimeout struct { ``` This message is expected to fail if: + - `Proof` is empty - `ProofHeight` is zero - `NextSequenceRecv` is zero @@ -388,7 +422,7 @@ the `MsgTimeoutOnClose`. ```go type MsgTimeoutOnClose struct { - Packet Packet + Packet Packet Proof []byte ProofClose []byte ProofHeight uint64 @@ -398,6 +432,7 @@ type MsgTimeoutOnClose struct { ``` This message is expected to fail if: + - `Proof` is empty - `ProofClose` is empty - `ProofHeight` is zero @@ -413,7 +448,7 @@ The message times out a packet on chain B. A packet is acknowledged on chain A using the `MsgAcknowledgement`. -```go +```go type MsgAcknowledgement struct { Packet Packet Acknowledgement []byte @@ -424,6 +459,7 @@ type MsgAcknowledgement struct { ``` This message is expected to fail if: + - `Proof` is empty - `ProofHeight` is zero - `Signer` is empty @@ -432,4 +468,3 @@ This message is expected to fail if: - `Proof` does not prove that the counterparty received the `Packet`. The message receives a packet on chain A. - diff --git a/x/ibc/testing/chain.go b/x/ibc/testing/chain.go index 534cd3dfc6..56721f971f 100644 --- a/x/ibc/testing/chain.go +++ b/x/ibc/testing/chain.go @@ -123,8 +123,9 @@ func NewTestChain(t *testing.T, chainID string) *TestChain { // create current header and call begin block header := tmproto.Header{ - Height: 1, - Time: globalStartTime, + ChainID: chainID, + Height: 1, + Time: globalStartTime, } txConfig := simapp.MakeEncodingConfig().TxConfig @@ -367,19 +368,40 @@ func (chain *TestChain) GetFirstTestConnection(clientID, counterpartyClientID st return chain.ConstructNextTestConnection(clientID, counterpartyClientID) } -func (chain *TestChain) ConstructMsgCreateClient(counterparty *TestChain, clientID string) clientexported.MsgCreateClient { - return ibctmtypes.NewMsgCreateClient( - clientID, counterparty.LastHeader, - DefaultTrustLevel, TrustingPeriod, UnbondingPeriod, MaxClockDrift, - commitmenttypes.GetSDKSpecs(), chain.SenderAccount.GetAddress(), +// ConstructMsgCreateClient constructs a message to create a new client state (tendermint or solomachine). +func (chain *TestChain) ConstructMsgCreateClient(counterparty *TestChain, clientID string, clientType string) *clienttypes.MsgCreateClient { + var ( + clientState clientexported.ClientState + consensusState clientexported.ConsensusState ) + + switch clientType { + case clientexported.ClientTypeTendermint: + clientState = ibctmtypes.NewClientState( + counterparty.ChainID, DefaultTrustLevel, TrustingPeriod, UnbondingPeriod, MaxClockDrift, + clienttypes.NewHeight(0, counterparty.LastHeader.GetHeight()), commitmenttypes.GetSDKSpecs(), + ) + consensusState = counterparty.LastHeader.ConsensusState() + case clientexported.ClientTypeSoloMachine: + solo := NewSolomachine(chain.t, clientID) + clientState = solo.ClientState() + consensusState = solo.ConsensusState() + default: + chain.t.Fatalf("unsupported client state type %s", clientType) + } + + msg, err := clienttypes.NewMsgCreateClient( + clientID, clientState, consensusState, chain.SenderAccount.GetAddress(), + ) + require.NoError(chain.t, err) + return msg } // CreateTMClient will construct and execute a 07-tendermint MsgCreateClient. A counterparty // client will be created on the (target) chain. func (chain *TestChain) CreateTMClient(counterparty *TestChain, clientID string) error { // construct MsgCreateClient using counterparty - msg := chain.ConstructMsgCreateClient(counterparty, clientID) + msg := chain.ConstructMsgCreateClient(counterparty, clientID, clientexported.ClientTypeTendermint) return chain.sendMsgs(msg) } @@ -420,10 +442,11 @@ func (chain *TestChain) UpdateTMClient(counterparty *TestChain, clientID string) } header.TrustedValidators = trustedVals - msg := ibctmtypes.NewMsgUpdateClient( + msg, err := clienttypes.NewMsgUpdateClient( clientID, header, chain.SenderAccount.GetAddress(), ) + require.NoError(chain.t, err) return chain.sendMsgs(msg) }