diff --git a/client/grpc/reflection/reflection.pb.go b/client/grpc/reflection/reflection.pb.go index d5851ed119..eaa329a0a5 100644 --- a/client/grpc/reflection/reflection.pb.go +++ b/client/grpc/reflection/reflection.pb.go @@ -214,7 +214,7 @@ func init() { } var fileDescriptor_d48c054165687f5c = []byte{ - // 393 bytes of a gzipped FileDescriptorProto + // 395 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4f, 0xce, 0x2f, 0xce, 0xcd, 0x2f, 0xd6, 0x4f, 0x4a, 0x2c, 0x4e, 0xd5, 0x2f, 0x4a, 0x4d, 0xcb, 0x49, 0x4d, 0x2e, 0xc9, 0xcc, 0xcf, 0xd3, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0x44, 0x12, 0xd2, 0x2b, 0x28, 0xca, @@ -228,18 +228,18 @@ var fileDescriptor_d48c054165687f5c = []byte{ 0x0b, 0x72, 0x52, 0x73, 0x53, 0xf3, 0xa0, 0xd6, 0x43, 0xed, 0x10, 0x52, 0xe5, 0xe2, 0x43, 0x35, 0x46, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x88, 0x17, 0xc5, 0x14, 0xa5, 0x78, 0x2e, 0x69, 0xac, 0x86, 0x40, 0x1d, 0xe3, 0xc0, 0x25, 0x93, 0x89, 0x22, 0x15, 0x9f, 0x9b, 0x5a, 0x5c, 0x9c, 0x98, - 0x8e, 0xea, 0x32, 0x29, 0x54, 0x35, 0xbe, 0x10, 0x25, 0x60, 0x57, 0x1a, 0xad, 0x65, 0xe6, 0x12, + 0x8e, 0xea, 0x32, 0x29, 0x54, 0x35, 0xbe, 0x10, 0x25, 0x60, 0x57, 0x1a, 0xed, 0x60, 0xe6, 0x12, 0x0c, 0x82, 0x07, 0x5e, 0x70, 0x6a, 0x51, 0x59, 0x66, 0x72, 0xaa, 0xd0, 0x1e, 0x46, 0x2e, 0x41, 0x8c, 0x20, 0x10, 0xb2, 0xd0, 0xc3, 0x1f, 0xe4, 0x7a, 0xb8, 0x42, 0x54, 0xca, 0x92, 0x0c, 0x9d, 0x10, 0x2f, 0x2a, 0x19, 0x35, 0x5d, 0x7e, 0x32, 0x99, 0x49, 0x47, 0x48, 0x8b, 0x50, 0x02, 0xc9, - 0x44, 0x38, 0xf4, 0x06, 0x23, 0x97, 0x30, 0x96, 0x60, 0x13, 0xb2, 0x22, 0xc6, 0x19, 0xd8, 0x23, - 0x4c, 0xca, 0x9a, 0x2c, 0xbd, 0x50, 0x4f, 0x78, 0x80, 0x3d, 0xe1, 0x24, 0xe4, 0x40, 0xd0, 0x13, - 0xa8, 0x06, 0xe8, 0x57, 0xa3, 0x26, 0x92, 0x5a, 0x27, 0xdf, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, - 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, - 0x3c, 0x96, 0x63, 0x88, 0x32, 0x4e, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0x85, - 0xd9, 0x02, 0xa1, 0x74, 0x8b, 0x53, 0xb2, 0xf5, 0x93, 0x73, 0x32, 0x53, 0xf3, 0x4a, 0xf4, 0xd3, - 0x8b, 0x0a, 0x92, 0x91, 0xec, 0x4d, 0x62, 0x03, 0xe7, 0x06, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xd2, 0xbf, 0x07, 0xa6, 0x7e, 0x03, 0x00, 0x00, + 0x44, 0x38, 0xf4, 0x31, 0x23, 0x97, 0x30, 0x96, 0x60, 0x13, 0xb2, 0x22, 0xc6, 0x19, 0xd8, 0x23, + 0x4c, 0xca, 0x9a, 0x2c, 0xbd, 0x50, 0x4f, 0x04, 0x83, 0x3d, 0xe1, 0x2b, 0xe4, 0x4d, 0xbc, 0x27, + 0xf4, 0xab, 0x51, 0xd3, 0x47, 0xad, 0x3e, 0x6a, 0x2c, 0x16, 0x3b, 0xf9, 0x9e, 0x78, 0x24, 0xc7, + 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, + 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x71, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, + 0x7e, 0x2e, 0xcc, 0x42, 0x08, 0xa5, 0x5b, 0x9c, 0x92, 0xad, 0x9f, 0x9c, 0x93, 0x99, 0x9a, 0x57, + 0xa2, 0x9f, 0x5e, 0x54, 0x90, 0x8c, 0xe4, 0x84, 0x24, 0x36, 0x70, 0xc6, 0x30, 0x06, 0x04, 0x00, + 0x00, 0xff, 0xff, 0x32, 0x5b, 0x2b, 0x51, 0x89, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/client/grpc/reflection/reflection.pb.gw.go b/client/grpc/reflection/reflection.pb.gw.go index cba2f47082..b3e8c46414 100644 --- a/client/grpc/reflection/reflection.pb.gw.go +++ b/client/grpc/reflection/reflection.pb.gw.go @@ -235,7 +235,7 @@ func RegisterReflectionServiceHandlerClient(ctx context.Context, mux *runtime.Se var ( pattern_ReflectionService_ListAllInterfaces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "base", "reflection", "v1beta1", "interfaces"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_ReflectionService_ListImplementations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "base", "reflection", "v1beta1", "implementations", "interface_name"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ReflectionService_ListImplementations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"cosmos", "base", "reflection", "v1beta1", "interfaces", "interface_name", "implementations"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( diff --git a/proto/ibc/lightclients/solomachine/v1/solomachine.proto b/proto/ibc/lightclients/solomachine/v1/solomachine.proto index be46ebc0e6..2127c8fe40 100644 --- a/proto/ibc/lightclients/solomachine/v1/solomachine.proto +++ b/proto/ibc/lightclients/solomachine/v1/solomachine.proto @@ -38,9 +38,9 @@ message Header { [(gogoproto.moretags) = "yaml:\"new_public_key\""]; } -// Evidence defines evidence of misbehaviour for a solo machine which consists +// Misbehaviour defines misbehaviour for a solo machine which consists // of a sequence and two signatures over different messages at that sequence. -message Evidence { +message Misbehaviour { option (gogoproto.goproto_getters) = false; option (gogoproto.goproto_stringer) = false; string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; @@ -82,11 +82,11 @@ message MsgUpdateClient { } // MsgSubmitClientMisbehaviour defines an sdk.Msg type that supports submitting -// arbitrary Evidence. +// arbitrary Misbehaviour. message MsgSubmitClientMisbehaviour { option (gogoproto.goproto_getters) = false; bytes submitter = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; - Evidence evidence = 2; + Misbehaviour misbehaviour = 2; } diff --git a/proto/ibc/tendermint/tendermint.proto b/proto/ibc/tendermint/tendermint.proto index 18b1cbaf5e..e6cd0f6e79 100644 --- a/proto/ibc/tendermint/tendermint.proto +++ b/proto/ibc/tendermint/tendermint.proto @@ -68,9 +68,9 @@ message ConsensusState { ]; } -// Evidence is a wrapper over two conflicting Headers -// that implements Evidence interface expected by ICS-02 -message Evidence { +// Misbehaviour is a wrapper over two conflicting Headers +// that implements Misbehaviour interface expected by ICS-02 +message Misbehaviour { option (gogoproto.goproto_getters) = false; option (gogoproto.goproto_stringer) = false; @@ -164,7 +164,7 @@ message MsgUpdateClient { message MsgSubmitClientMisbehaviour { option (gogoproto.goproto_getters) = false; - Evidence evidence = 1; - bytes submitter = 2 + Misbehaviour misbehaviour = 1; + bytes submitter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; } diff --git a/x/ibc/02-client/exported/exported.go b/x/ibc/02-client/exported/exported.go index 7e0fc328be..82fe7e6367 100644 --- a/x/ibc/02-client/exported/exported.go +++ b/x/ibc/02-client/exported/exported.go @@ -133,7 +133,7 @@ type ConsensusState interface { ValidateBasic() error } -// Misbehaviour defines a specific consensus kind and an evidence +// Misbehaviour defines counterparty misbehaviour for a specific consensus type type Misbehaviour interface { evidenceexported.Evidence ClientType() ClientType @@ -146,11 +146,12 @@ type Header interface { GetHeight() uint64 } -// message types for the IBC client +// 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 diff --git a/x/ibc/02-client/handler.go b/x/ibc/02-client/handler.go index 3ce4e9e59a..0be44574d9 100644 --- a/x/ibc/02-client/handler.go +++ b/x/ibc/02-client/handler.go @@ -84,7 +84,7 @@ func HandlerClientMisbehaviour(k keeper.Keeper) evidencetypes.Handler { return func(ctx sdk.Context, evidence evidenceexported.Evidence) error { misbehaviour, ok := evidence.(exported.Misbehaviour) if !ok { - return sdkerrors.Wrapf(types.ErrInvalidEvidence, + return sdkerrors.Wrapf(types.ErrInvalidMisbehaviour, "expected evidence to implement client Misbehaviour interface, got %T", evidence, ) } diff --git a/x/ibc/02-client/keeper/client_test.go b/x/ibc/02-client/keeper/client_test.go index 364e64be64..ed4997eb8e 100644 --- a/x/ibc/02-client/keeper/client_test.go +++ b/x/ibc/02-client/keeper/client_test.go @@ -266,14 +266,14 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { altTime := suite.ctx.BlockTime().Add(time.Minute) testCases := []struct { - name string - evidence *ibctmtypes.Evidence - malleate func() error - expPass bool + name string + misbehaviour *ibctmtypes.Misbehaviour + malleate func() error + expPass bool }{ { "trusting period misbehavior should pass", - &ibctmtypes.Evidence{ + &ibctmtypes.Misbehaviour{ Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, altTime, bothValSet, bothValSet, bothSigners), Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), ChainId: testChainID, @@ -290,7 +290,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "misbehavior at later height should pass", - &ibctmtypes.Evidence{ + &ibctmtypes.Misbehaviour{ Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight, altTime, bothValSet, valSet, bothSigners), Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners), ChainId: testChainID, @@ -318,7 +318,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "misbehavior at later height with different trusted heights should pass", - &ibctmtypes.Evidence{ + &ibctmtypes.Misbehaviour{ Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight, altTime, bothValSet, valSet, bothSigners), Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight+3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), ChainId: testChainID, @@ -346,7 +346,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "misbehaviour fails validatebasic", - &ibctmtypes.Evidence{ + &ibctmtypes.Misbehaviour{ Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+1, testClientHeight, altTime, bothValSet, bothValSet, bothSigners), Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), ChainId: testChainID, @@ -363,7 +363,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "trusted ConsensusState1 not found", - &ibctmtypes.Evidence{ + &ibctmtypes.Misbehaviour{ Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight+3, altTime, bothValSet, bothValSet, bothSigners), Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners), ChainId: testChainID, @@ -380,7 +380,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, { "trusted ConsensusState2 not found", - &ibctmtypes.Evidence{ + &ibctmtypes.Misbehaviour{ Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight, altTime, bothValSet, valSet, bothSigners), Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight+3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), ChainId: testChainID, @@ -398,13 +398,13 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { { "client state not found", - &ibctmtypes.Evidence{}, + &ibctmtypes.Misbehaviour{}, func() error { return nil }, false, }, { "client already frozen at earlier height", - &ibctmtypes.Evidence{ + &ibctmtypes.Misbehaviour{ Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, altTime, bothValSet, bothValSet, bothSigners), Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), ChainId: testChainID, @@ -425,7 +425,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { { "misbehaviour check failed", - &ibctmtypes.Evidence{ + &ibctmtypes.Misbehaviour{ Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, altTime, bothValSet, bothValSet, bothSigners), Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners), ChainId: testChainID, @@ -453,7 +453,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { err := tc.malleate() suite.Require().NoError(err) - err = suite.keeper.CheckMisbehaviourAndUpdateState(suite.ctx, tc.evidence) + err = suite.keeper.CheckMisbehaviourAndUpdateState(suite.ctx, tc.misbehaviour) if tc.expPass { suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) @@ -461,8 +461,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { clientState, found := suite.keeper.GetClientState(suite.ctx, testClientID) suite.Require().True(found, "valid test case %d failed: %s", i, tc.name) suite.Require().True(clientState.IsFrozen(), "valid test case %d failed: %s", i, tc.name) - suite.Require().Equal(uint64(tc.evidence.GetHeight()), clientState.GetFrozenHeight(), - "valid test case %d failed: %s. Expected FrozenHeight %d got %d", tc.evidence.GetHeight(), clientState.GetFrozenHeight()) + suite.Require().Equal(uint64(tc.misbehaviour.GetHeight()), clientState.GetFrozenHeight(), + "valid test case %d failed: %s. Expected FrozenHeight %d got %d", tc.misbehaviour.GetHeight(), clientState.GetFrozenHeight()) } else { suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) } diff --git a/x/ibc/02-client/types/errors.go b/x/ibc/02-client/types/errors.go index b51fd25063..2526f16183 100644 --- a/x/ibc/02-client/types/errors.go +++ b/x/ibc/02-client/types/errors.go @@ -16,7 +16,7 @@ var ( ErrInvalidClientType = sdkerrors.Register(SubModuleName, 9, "invalid client type") ErrRootNotFound = sdkerrors.Register(SubModuleName, 10, "commitment root not found") ErrInvalidHeader = sdkerrors.Register(SubModuleName, 11, "invalid client header") - ErrInvalidEvidence = sdkerrors.Register(SubModuleName, 12, "invalid light client misbehaviour evidence") + ErrInvalidMisbehaviour = sdkerrors.Register(SubModuleName, 12, "invalid light client misbehaviour") ErrFailedClientStateVerification = sdkerrors.Register(SubModuleName, 13, "client state verification failed") ErrFailedClientConsensusStateVerification = sdkerrors.Register(SubModuleName, 14, "client consensus state verification failed") ErrFailedConnectionStateVerification = sdkerrors.Register(SubModuleName, 15, "connection state verification failed") diff --git a/x/ibc/02-client/types/query.pb.gw.go b/x/ibc/02-client/types/query.pb.gw.go index 8e39fc807f..9dbd863cd2 100644 --- a/x/ibc/02-client/types/query.pb.gw.go +++ b/x/ibc/02-client/types/query.pb.gw.go @@ -290,7 +290,6 @@ func local_request_Query_ConsensusStates_0(ctx context.Context, marshaler runtim // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { mux.Handle("GET", pattern_Query_ClientState_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { diff --git a/x/ibc/07-tendermint/client/cli/tx.go b/x/ibc/07-tendermint/client/cli/tx.go index 6e6c4b3999..d34794f10c 100644 --- a/x/ibc/07-tendermint/client/cli/tx.go +++ b/x/ibc/07-tendermint/client/cli/tx.go @@ -183,11 +183,11 @@ func NewUpdateClientCmd() *cobra.Command { // https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#misbehaviour func NewSubmitMisbehaviourCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "misbehaviour [path/to/evidence.json]", + Use: "misbehaviour [path/to/misbehaviour.json]", Short: "submit a client misbehaviour", Long: "submit a client misbehaviour to invalidate to invalidate previous state roots and prevent future updates", Example: fmt.Sprintf( - "$ %s tx ibc %s misbehaviour [path/to/evidence.json] --from node0 --home ../node0/cli --chain-id $CID", + "$ %s tx ibc %s misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName, ), Args: cobra.ExactArgs(1), @@ -200,19 +200,19 @@ func NewSubmitMisbehaviourCmd() *cobra.Command { cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) - var ev *types.Evidence - if err := cdc.UnmarshalJSON([]byte(args[0]), ev); err != nil { + var m *types.Misbehaviour + if err := cdc.UnmarshalJSON([]byte(args[0]), m); err != nil { // check for file path if JSON input is not provided contents, err := ioutil.ReadFile(args[0]) if err != nil { return errors.New("neither JSON input nor path to .json file were provided") } - if err := cdc.UnmarshalJSON(contents, ev); err != nil { - return errors.Wrap(err, "error unmarshalling evidence file") + if err := cdc.UnmarshalJSON(contents, m); err != nil { + return errors.Wrap(err, "error unmarshalling misbehaviour file") } } - msg := types.NewMsgSubmitClientMisbehaviour(ev, clientCtx.GetFromAddress()) + msg := types.NewMsgSubmitClientMisbehaviour(m, clientCtx.GetFromAddress()) 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 c10bc49dff..98f7701836 100644 --- a/x/ibc/07-tendermint/types/codec.go +++ b/x/ibc/07-tendermint/types/codec.go @@ -20,7 +20,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { ) registry.RegisterImplementations( (*evidenceexported.Evidence)(nil), - &Evidence{}, + &Misbehaviour{}, ) } diff --git a/x/ibc/07-tendermint/types/evidence.go b/x/ibc/07-tendermint/types/evidence.go deleted file mode 100644 index ddcadf35d6..0000000000 --- a/x/ibc/07-tendermint/types/evidence.go +++ /dev/null @@ -1,185 +0,0 @@ -package types - -import ( - "math" - "time" - - yaml "gopkg.in/yaml.v2" - - "github.com/tendermint/tendermint/crypto/tmhash" - tmbytes "github.com/tendermint/tendermint/libs/bytes" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmtypes "github.com/tendermint/tendermint/types" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" - 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 ( - _ evidenceexported.Evidence = Evidence{} - _ clientexported.Misbehaviour = Evidence{} -) - -// NewEvidence creates a new Evidence instance. -func NewEvidence(clientID, chainID string, header1, header2 *Header) *Evidence { - return &Evidence{ - ClientId: clientID, - ChainId: chainID, - Header1: header1, - Header2: header2, - } - -} - -// ClientType is Tendermint light client -func (ev Evidence) ClientType() clientexported.ClientType { - return clientexported.Tendermint -} - -// GetClientID returns the ID of the client that committed a misbehaviour. -func (ev Evidence) GetClientID() string { - return ev.ClientId -} - -// Route implements Evidence interface -func (ev Evidence) Route() string { - return clienttypes.SubModuleName -} - -// Type implements Evidence interface -func (ev Evidence) Type() string { - return "client_misbehaviour" -} - -// String implements Evidence interface -func (ev Evidence) String() string { - // FIXME: implement custom marshaller - bz, err := yaml.Marshal(ev) - if err != nil { - panic(err) - } - return string(bz) -} - -// Hash implements Evidence interface -func (ev Evidence) Hash() tmbytes.HexBytes { - bz := SubModuleCdc.MustMarshalBinaryBare(&ev) - return tmhash.Sum(bz) -} - -// GetHeight returns the height at which misbehaviour occurred -// -// NOTE: assumes that evidence headers have the same height -func (ev Evidence) GetHeight() int64 { - return int64(math.Min(float64(ev.Header1.GetHeight()), float64(ev.Header2.GetHeight()))) -} - -// GetTime returns the timestamp at which misbehaviour occurred. It uses the -// maximum value from both headers to prevent producing an invalid header outside -// of the evidence age range. -func (ev Evidence) GetTime() time.Time { - minTime := int64(math.Max(float64(ev.Header1.GetTime().UnixNano()), float64(ev.Header2.GetTime().UnixNano()))) - return time.Unix(0, minTime) -} - -// ValidateBasic implements Evidence interface -func (ev Evidence) ValidateBasic() error { - if ev.Header1 == nil { - return sdkerrors.Wrap(ErrInvalidHeader, "evidence Header1 cannot be nil") - } - if ev.Header2 == nil { - return sdkerrors.Wrap(ErrInvalidHeader, "evidence Header2 cannot be nil") - } - if ev.Header1.TrustedHeight == 0 { - return sdkerrors.Wrap(ErrInvalidHeaderHeight, "evidence Header1 must have non-zero trusted height") - } - if ev.Header2.TrustedHeight == 0 { - return sdkerrors.Wrap(ErrInvalidHeaderHeight, "evidence Header2 must have non-zero trusted height") - } - if ev.Header1.TrustedValidators == nil { - return sdkerrors.Wrap(ErrInvalidValidatorSet, "trusted validator set in Header1 cannot be empty") - } - if ev.Header2.TrustedValidators == nil { - return sdkerrors.Wrap(ErrInvalidValidatorSet, "trusted validator set in Header2 cannot be empty") - } - - if err := host.ClientIdentifierValidator(ev.ClientId); err != nil { - return sdkerrors.Wrap(err, "evidence client ID is invalid") - } - - // ValidateBasic on both validators - if err := ev.Header1.ValidateBasic(ev.ChainId); err != nil { - return sdkerrors.Wrap( - clienttypes.ErrInvalidEvidence, - sdkerrors.Wrap(err, "header 1 failed validation").Error(), - ) - } - if err := ev.Header2.ValidateBasic(ev.ChainId); err != nil { - return sdkerrors.Wrap( - clienttypes.ErrInvalidEvidence, - sdkerrors.Wrap(err, "header 2 failed validation").Error(), - ) - } - // Ensure that Heights are the same - if ev.Header1.GetHeight() != ev.Header2.GetHeight() { - return sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, "headers in evidence are on different heights (%d ≠ %d)", ev.Header1.GetHeight(), ev.Header2.GetHeight()) - } - - blockID1, err := tmtypes.BlockIDFromProto(&ev.Header1.SignedHeader.Commit.BlockID) - if err != nil { - return sdkerrors.Wrap(err, "invalid block ID from header 1 in evidence") - } - blockID2, err := tmtypes.BlockIDFromProto(&ev.Header2.SignedHeader.Commit.BlockID) - if err != nil { - return sdkerrors.Wrap(err, "invalid block ID from header 2 in evidence") - } - - // Ensure that Commit Hashes are different - if blockID1.Equals(*blockID2) { - return sdkerrors.Wrap(clienttypes.ErrInvalidEvidence, "headers blockIDs are not equal") - } - if err := ValidCommit(ev.ChainId, ev.Header1.Commit, ev.Header1.ValidatorSet); err != nil { - return err - } - if err := ValidCommit(ev.ChainId, ev.Header2.Commit, ev.Header2.ValidatorSet); err != nil { - return err - } - return nil -} - -// ValidCommit checks if the given commit is a valid commit from the passed-in validatorset -// -// CommitToVoteSet will panic if the commit cannot be converted to a valid voteset given the validatorset -// This implies that someone tried to submit evidence that wasn't actually committed by the validatorset -// thus we should return an error here and reject the evidence rather than panicing. -func ValidCommit(chainID string, commit *tmproto.Commit, valSet *tmproto.ValidatorSet) (err error) { - defer func() { - if r := recover(); r != nil { - err = sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, "invalid commit: %v", r) - } - }() - - tmCommit, err := tmtypes.CommitFromProto(commit) - if err != nil { - return sdkerrors.Wrap(err, "commit is not tendermint commit type") - } - tmValset, err := tmtypes.ValidatorSetFromProto(valSet) - if err != nil { - return sdkerrors.Wrap(err, "validator set is not tendermint validator set type") - } - - // Convert commits to vote-sets given the validator set so we can check if they both have 2/3 power - voteSet := tmtypes.CommitToVoteSet(chainID, tmCommit, tmValset) - - blockID, ok := voteSet.TwoThirdsMajority() - - // Check that ValidatorSet did indeed commit to blockID in Commit - if !ok || !blockID.Equals(tmCommit.BlockID) { - return sdkerrors.Wrap(clienttypes.ErrInvalidEvidence, "validator set did not commit to header") - } - - return nil -} diff --git a/x/ibc/07-tendermint/types/evidence_test.go b/x/ibc/07-tendermint/types/evidence_test.go deleted file mode 100644 index 3d0fa44832..0000000000 --- a/x/ibc/07-tendermint/types/evidence_test.go +++ /dev/null @@ -1,266 +0,0 @@ -package types_test - -import ( - "time" - - "github.com/tendermint/tendermint/crypto/tmhash" - tmbytes "github.com/tendermint/tendermint/libs/bytes" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmtypes "github.com/tendermint/tendermint/types" - - clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" -) - -func (suite *TendermintTestSuite) TestEvidence() { - signers := []tmtypes.PrivValidator{suite.privVal} - - ev := &types.Evidence{ - Header1: suite.header, - Header2: types.CreateTestHeader(chainID, height, height-1, suite.now, suite.valSet, suite.valSet, signers), - ChainId: chainID, - ClientId: clientID, - } - - suite.Require().Equal(ev.ClientType(), clientexported.Tendermint) - suite.Require().Equal(ev.GetClientID(), clientID) - suite.Require().Equal(ev.Route(), "client") - suite.Require().Equal(ev.Type(), "client_misbehaviour") - suite.Require().Equal(ev.Hash(), tmbytes.HexBytes(tmhash.Sum(suite.cdc.MustMarshalBinaryBare(ev)))) - suite.Require().Equal(ev.GetHeight(), int64(height)) -} - -func (suite *TendermintTestSuite) TestEvidenceValidateBasic() { - altPrivVal := tmtypes.NewMockPV() - altPubKey, err := altPrivVal.GetPubKey() - suite.Require().NoError(err) - - altVal := tmtypes.NewValidator(altPubKey, height) - - // Create bothValSet with both suite validator and altVal - bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) - // Create alternative validator set with only altVal - altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) - - signers := []tmtypes.PrivValidator{suite.privVal} - - // Create signer array and ensure it is in same order as bothValSet - _, suiteVal := suite.valSet.GetByIndex(0) - bothSigners := types.CreateSortedSignerArray(altPrivVal, suite.privVal, altVal, suiteVal) - - altSigners := []tmtypes.PrivValidator{altPrivVal} - - testCases := []struct { - name string - evidence *types.Evidence - malleateEvidence func(ev *types.Evidence) error - expPass bool - }{ - { - "valid evidence", - &types.Evidence{ - Header1: suite.header, - Header2: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers), - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { return nil }, - true, - }, - { - "evidence Header1 is nil", - types.NewEvidence(clientID, chainID, nil, suite.header), - func(ev *types.Evidence) error { return nil }, - false, - }, - { - "evidence Header2 is nil", - types.NewEvidence(clientID, chainID, suite.header, nil), - func(ev *types.Evidence) error { return nil }, - false, - }, - - { - "valid evidence with different trusted headers", - &types.Evidence{ - Header1: suite.header, - Header2: types.CreateTestHeader(chainID, height, height-3, suite.now.Add(time.Minute), suite.valSet, bothValSet, signers), - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { return nil }, - true, - }, - { - "trusted height is 0 in Header1", - &types.Evidence{ - Header1: types.CreateTestHeader(chainID, height, 0, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers), - Header2: suite.header, - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { return nil }, - false, - }, - { - "trusted height is 0 in Header2", - &types.Evidence{ - Header1: suite.header, - Header2: types.CreateTestHeader(chainID, height, 0, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers), - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { return nil }, - false, - }, - { - "trusted valset is nil in Header1", - &types.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), suite.valSet, nil, signers), - Header2: suite.header, - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { return nil }, - false, - }, - { - "trusted valset is nil in Header2", - &types.Evidence{ - Header1: suite.header, - Header2: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), suite.valSet, nil, signers), - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { return nil }, - false, - }, - { - "invalid client ID ", - &types.Evidence{ - Header1: suite.header, - Header2: types.CreateTestHeader(chainID, height, height-1, suite.now, suite.valSet, suite.valSet, signers), - ChainId: chainID, - ClientId: "GAIA", - }, - func(ev *types.Evidence) error { return nil }, - false, - }, - { - "wrong chainID on header1", - &types.Evidence{ - Header1: suite.header, - Header2: types.CreateTestHeader("ethermint", height, height-1, suite.now, suite.valSet, suite.valSet, signers), - ChainId: "ethermint", - ClientId: clientID, - }, - func(ev *types.Evidence) error { return nil }, - false, - }, - { - "wrong chainID on header2", - &types.Evidence{ - Header1: suite.header, - Header2: types.CreateTestHeader("ethermint", height, height-1, suite.now, suite.valSet, suite.valSet, signers), - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { return nil }, - false, - }, - { - "mismatched heights", - &types.Evidence{ - Header1: suite.header, - Header2: types.CreateTestHeader(chainID, 6, 4, suite.now, suite.valSet, suite.valSet, signers), - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { return nil }, - false, - }, - { - "same block id", - &types.Evidence{ - Header1: suite.header, - Header2: suite.header, - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { return nil }, - false, - }, - { - "header 1 doesn't have 2/3 majority", - &types.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, suite.valSet, bothSigners), - Header2: suite.header, - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { - // voteSet contains only altVal which is less than 2/3 of total power (height/1height) - wrongVoteSet := tmtypes.NewVoteSet(chainID, int64(ev.Header1.GetHeight()), 1, tmproto.PrecommitType, altValSet) - blockID, err := tmtypes.BlockIDFromProto(&ev.Header1.Commit.BlockID) - if err != nil { - return err - } - - tmCommit, err := tmtypes.MakeCommit(*blockID, int64(ev.Header2.GetHeight()), ev.Header1.Commit.Round, wrongVoteSet, altSigners, suite.now) - ev.Header1.Commit = tmCommit.ToProto() - return err - }, - false, - }, - { - "header 2 doesn't have 2/3 majority", - &types.Evidence{ - Header1: suite.header, - Header2: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, suite.valSet, bothSigners), - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { - // voteSet contains only altVal which is less than 2/3 of total power (height/1height) - wrongVoteSet := tmtypes.NewVoteSet(chainID, int64(ev.Header2.GetHeight()), 1, tmproto.PrecommitType, altValSet) - blockID, err := tmtypes.BlockIDFromProto(&ev.Header2.Commit.BlockID) - if err != nil { - return err - } - - tmCommit, err := tmtypes.MakeCommit(*blockID, int64(ev.Header2.GetHeight()), ev.Header2.Commit.Round, wrongVoteSet, altSigners, suite.now) - ev.Header2.Commit = tmCommit.ToProto() - return err - }, - false, - }, - { - "validators sign off on wrong commit", - &types.Evidence{ - Header1: suite.header, - Header2: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, suite.valSet, bothSigners), - ChainId: chainID, - ClientId: clientID, - }, - func(ev *types.Evidence) error { - tmBlockID := types.MakeBlockID(tmhash.Sum([]byte("other_hash")), 3, tmhash.Sum([]byte("other_partset"))) - ev.Header2.Commit.BlockID = tmBlockID.ToProto() - return nil - }, - false, - }, - } - - for i, tc := range testCases { - tc := tc - - err := tc.malleateEvidence(tc.evidence) - suite.Require().NoError(err) - - if tc.expPass { - suite.Require().NoError(tc.evidence.ValidateBasic(), "valid test case %d failed: %s", i, tc.name) - } else { - suite.Require().Error(tc.evidence.ValidateBasic(), "invalid test case %d passed: %s", i, tc.name) - } - } -} diff --git a/x/ibc/07-tendermint/types/misbehaviour.go b/x/ibc/07-tendermint/types/misbehaviour.go index 3f5957cb01..4d13ebc59f 100644 --- a/x/ibc/07-tendermint/types/misbehaviour.go +++ b/x/ibc/07-tendermint/types/misbehaviour.go @@ -1,141 +1,185 @@ package types import ( + "math" "time" + yaml "gopkg.in/yaml.v2" + + "github.com/tendermint/tendermint/crypto/tmhash" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" 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" ) -// CheckMisbehaviourAndUpdateState determines whether or not two conflicting -// headers at the same height would have convinced the light client. -// -// NOTE: consensusState1 is the trusted consensus state that corresponds to the TrustedHeight -// of misbehaviour.Header1 -// Similarly, consensusState2 is the trusted consensus state that corresponds -// to misbehaviour.Header2 -func (cs ClientState) CheckMisbehaviourAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryMarshaler, - clientStore sdk.KVStore, - misbehaviour clientexported.Misbehaviour, -) (clientexported.ClientState, error) { +var ( + _ evidenceexported.Evidence = Misbehaviour{} + _ clientexported.Misbehaviour = Misbehaviour{} +) - // If client is already frozen at earlier height than evidence, return with error - if cs.IsFrozen() && cs.FrozenHeight <= uint64(misbehaviour.GetHeight()) { - return nil, sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, - "client is already frozen at earlier height %d than misbehaviour height %d", cs.FrozenHeight, misbehaviour.GetHeight()) +// NewMisbehaviour creates a new Misbehaviour instance. +func NewMisbehaviour(clientID, chainID string, header1, header2 *Header) *Misbehaviour { + return &Misbehaviour{ + ClientId: clientID, + ChainId: chainID, + Header1: header1, + Header2: header2, } - tmEvidence, ok := misbehaviour.(*Evidence) - if !ok { - return nil, sdkerrors.Wrapf(clienttypes.ErrInvalidClientType, "expected type %T, got %T", misbehaviour, &Evidence{}) - } - - // Retrieve trusted consensus states for each Header in misbehaviour - // and unmarshal from clientStore - - // Get consensus bytes from clientStore - tmConsensusState1, err := GetConsensusState(clientStore, cdc, tmEvidence.Header1.TrustedHeight) - if err != nil { - return nil, sdkerrors.Wrapf(err, "could not get trusted consensus state from clientStore for Header1 at TrustedHeight: %d", tmEvidence.Header1.TrustedHeight) - } - - // Get consensus bytes from clientStore - tmConsensusState2, err := GetConsensusState(clientStore, cdc, tmEvidence.Header2.TrustedHeight) - if err != nil { - return nil, sdkerrors.Wrapf(err, "could not get trusted consensus state from clientStore for Header2 at TrustedHeight: %d", tmEvidence.Header2.TrustedHeight) - } - - // calculate the age of the misbehaviour evidence - infractionHeight := tmEvidence.GetHeight() - infractionTime := tmEvidence.GetTime() - ageDuration := ctx.BlockTime().Sub(infractionTime) - ageBlocks := int64(cs.LatestHeight) - infractionHeight - - // TODO: Retrieve consensusparams from client state and not context - // Issue #6516: https://github.com/cosmos/cosmos-sdk/issues/6516 - consensusParams := ctx.ConsensusParams() - - // Reject misbehaviour if the age is too old. Evidence is considered stale - // if the difference in time and number of blocks is greater than the allowed - // parameters defined. - // - // NOTE: The first condition is a safety check as the consensus params cannot - // be nil since the previous param values will be used in case they can't be - // retrieved. If they are not set during initialization, Tendermint will always - // use the default values. - if consensusParams != nil && - consensusParams.Evidence != nil && - (ageDuration > consensusParams.Evidence.MaxAgeDuration || - ageBlocks > consensusParams.Evidence.MaxAgeNumBlocks) { - return nil, sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, - "age duration (%s) and age blocks (%d) are greater than max consensus params for duration (%s) and block (%d)", - ageDuration, ageBlocks, consensusParams.Evidence.MaxAgeDuration, consensusParams.Evidence.MaxAgeNumBlocks, - ) - } - - // Check the validity of the two conflicting headers against their respective - // trusted consensus states - // NOTE: header height and commitment root assertions are checked in - // evidence.ValidateBasic by the client keeper and msg.ValidateBasic - // by the base application. - if err := checkMisbehaviourHeader( - &cs, tmConsensusState1, tmEvidence.Header1, ctx.BlockTime(), - ); err != nil { - return nil, sdkerrors.Wrap(err, "verifying Header1 in Evidence failed") - } - if err := checkMisbehaviourHeader( - &cs, tmConsensusState2, tmEvidence.Header2, ctx.BlockTime(), - ); err != nil { - return nil, sdkerrors.Wrap(err, "verifying Header2 in Evidence failed") - } - - cs.FrozenHeight = uint64(tmEvidence.GetHeight()) - return &cs, nil } -// checkMisbehaviourHeader checks that a Header in Misbehaviour is valid evidence given -// a trusted ConsensusState -func checkMisbehaviourHeader( - clientState *ClientState, consState *ConsensusState, header *Header, currentTimestamp time.Time, -) error { +// ClientType is Tendermint light client +func (misbehaviour Misbehaviour) ClientType() clientexported.ClientType { + return clientexported.Tendermint +} - tmTrustedValset, err := tmtypes.ValidatorSetFromProto(header.TrustedValidators) +// GetClientID returns the ID of the client that committed a misbehaviour. +func (misbehaviour Misbehaviour) GetClientID() string { + return misbehaviour.ClientId +} + +// Route implements Misbehaviour interface +func (misbehaviour Misbehaviour) Route() string { + return clienttypes.SubModuleName +} + +// Type implements Misbehaviour interface +func (misbehaviour Misbehaviour) Type() string { + return clientexported.TypeEvidenceClientMisbehaviour +} + +// String implements Misbehaviour interface +func (misbehaviour Misbehaviour) String() string { + // FIXME: implement custom marshaller + bz, err := yaml.Marshal(misbehaviour) if err != nil { - return sdkerrors.Wrap(err, "trusted validator set is not tendermint validator set type") + panic(err) + } + return string(bz) +} + +// Hash implements Misbehaviour interface +func (misbehaviour Misbehaviour) Hash() tmbytes.HexBytes { + bz := SubModuleCdc.MustMarshalBinaryBare(&misbehaviour) + return tmhash.Sum(bz) +} + +// GetHeight returns the height at which misbehaviour occurred +// +// NOTE: assumes that misbehaviour headers have the same height +func (misbehaviour Misbehaviour) GetHeight() int64 { + return int64(math.Min(float64(misbehaviour.Header1.GetHeight()), float64(misbehaviour.Header2.GetHeight()))) +} + +// GetTime returns the timestamp at which misbehaviour occurred. It uses the +// maximum value from both headers to prevent producing an invalid header outside +// of the misbehaviour age range. +func (misbehaviour Misbehaviour) GetTime() time.Time { + minTime := int64(math.Max(float64(misbehaviour.Header1.GetTime().UnixNano()), float64(misbehaviour.Header2.GetTime().UnixNano()))) + return time.Unix(0, minTime) +} + +// ValidateBasic implements Misbehaviour interface +func (misbehaviour Misbehaviour) ValidateBasic() error { + if misbehaviour.Header1 == nil { + return sdkerrors.Wrap(ErrInvalidHeader, "misbehaviour Header1 cannot be nil") + } + if misbehaviour.Header2 == nil { + return sdkerrors.Wrap(ErrInvalidHeader, "misbehaviour Header2 cannot be nil") + } + if misbehaviour.Header1.TrustedHeight == 0 { + return sdkerrors.Wrap(ErrInvalidHeaderHeight, "misbehaviour Header1 must have non-zero trusted height") + } + if misbehaviour.Header2.TrustedHeight == 0 { + return sdkerrors.Wrap(ErrInvalidHeaderHeight, "misbehaviour Header2 must have non-zero trusted height") + } + if misbehaviour.Header1.TrustedValidators == nil { + return sdkerrors.Wrap(ErrInvalidValidatorSet, "trusted validator set in Header1 cannot be empty") + } + if misbehaviour.Header2.TrustedValidators == nil { + return sdkerrors.Wrap(ErrInvalidValidatorSet, "trusted validator set in Header2 cannot be empty") } - tmCommit, err := tmtypes.CommitFromProto(header.Commit) - if err != nil { - return sdkerrors.Wrap(err, "commit is not tendermint commit type") + if err := host.ClientIdentifierValidator(misbehaviour.ClientId); err != nil { + return sdkerrors.Wrap(err, "misbehaviour client ID is invalid") } - // check the trusted fields for the header against ConsensusState - if err := checkTrustedHeader(header, consState); err != nil { - return err - } - - // assert that the timestamp is not from more than an unbonding period ago - if currentTimestamp.Sub(consState.Timestamp) >= clientState.UnbondingPeriod { - return sdkerrors.Wrapf( - ErrUnbondingPeriodExpired, - "current timestamp minus the latest consensus state timestamp is greater than or equal to the unbonding period (%s >= %s)", - currentTimestamp.Sub(consState.Timestamp), clientState.UnbondingPeriod, + // ValidateBasic on both validators + if err := misbehaviour.Header1.ValidateBasic(misbehaviour.ChainId); err != nil { + return sdkerrors.Wrap( + clienttypes.ErrInvalidMisbehaviour, + sdkerrors.Wrap(err, "header 1 failed validation").Error(), ) } + if err := misbehaviour.Header2.ValidateBasic(misbehaviour.ChainId); err != nil { + return sdkerrors.Wrap( + clienttypes.ErrInvalidMisbehaviour, + sdkerrors.Wrap(err, "header 2 failed validation").Error(), + ) + } + // Ensure that Heights are the same + if misbehaviour.Header1.GetHeight() != misbehaviour.Header2.GetHeight() { + return sdkerrors.Wrapf(clienttypes.ErrInvalidMisbehaviour, "headers in misbehaviour are on different heights (%d ≠ %d)", misbehaviour.Header1.GetHeight(), misbehaviour.Header2.GetHeight()) + } - // - ValidatorSet must have 2/3 similarity with trusted FromValidatorSet - // - ValidatorSets on both headers are valid given the last trusted ValidatorSet - if err := tmTrustedValset.VerifyCommitLightTrusting( - clientState.GetChainID(), tmCommit, clientState.TrustLevel.ToTendermint(), - ); err != nil { - return sdkerrors.Wrapf(clienttypes.ErrInvalidEvidence, "validator set in header has too much change from trusted validator set: %v", err) + blockID1, err := tmtypes.BlockIDFromProto(&misbehaviour.Header1.SignedHeader.Commit.BlockID) + if err != nil { + return sdkerrors.Wrap(err, "invalid block ID from header 1 in misbehaviour") + } + blockID2, err := tmtypes.BlockIDFromProto(&misbehaviour.Header2.SignedHeader.Commit.BlockID) + if err != nil { + return sdkerrors.Wrap(err, "invalid block ID from header 2 in misbehaviour") + } + + // Ensure that Commit Hashes are different + if blockID1.Equals(*blockID2) { + return sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "headers blockIDs are not equal") + } + if err := ValidCommit(misbehaviour.ChainId, misbehaviour.Header1.Commit, misbehaviour.Header1.ValidatorSet); err != nil { + return err + } + if err := ValidCommit(misbehaviour.ChainId, misbehaviour.Header2.Commit, misbehaviour.Header2.ValidatorSet); err != nil { + return err } return nil } + +// ValidCommit checks if the given commit is a valid commit from the passed-in validatorset +// +// CommitToVoteSet will panic if the commit cannot be converted to a valid voteset given the validatorset +// This implies that someone tried to submit misbehaviour that wasn't actually committed by the validatorset +// thus we should return an error here and reject the misbehaviour rather than panicing. +func ValidCommit(chainID string, commit *tmproto.Commit, valSet *tmproto.ValidatorSet) (err error) { + defer func() { + if r := recover(); r != nil { + err = sdkerrors.Wrapf(clienttypes.ErrInvalidMisbehaviour, "invalid commit: %v", r) + } + }() + + tmCommit, err := tmtypes.CommitFromProto(commit) + if err != nil { + return sdkerrors.Wrap(err, "commit is not tendermint commit type") + } + tmValset, err := tmtypes.ValidatorSetFromProto(valSet) + if err != nil { + return sdkerrors.Wrap(err, "validator set is not tendermint validator set type") + } + + // Convert commits to vote-sets given the validator set so we can check if they both have 2/3 power + voteSet := tmtypes.CommitToVoteSet(chainID, tmCommit, tmValset) + + blockID, ok := voteSet.TwoThirdsMajority() + + // Check that ValidatorSet did indeed commit to blockID in Commit + if !ok || !blockID.Equals(tmCommit.BlockID) { + return sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "validator set did not commit to header") + } + + return nil +} diff --git a/x/ibc/07-tendermint/types/misbehaviour_handle.go b/x/ibc/07-tendermint/types/misbehaviour_handle.go new file mode 100644 index 0000000000..26266341ef --- /dev/null +++ b/x/ibc/07-tendermint/types/misbehaviour_handle.go @@ -0,0 +1,141 @@ +package types + +import ( + "time" + + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/codec" + 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" +) + +// CheckMisbehaviourAndUpdateState determines whether or not two conflicting +// headers at the same height would have convinced the light client. +// +// NOTE: consensusState1 is the trusted consensus state that corresponds to the TrustedHeight +// of misbehaviour.Header1 +// Similarly, consensusState2 is the trusted consensus state that corresponds +// to misbehaviour.Header2 +func (cs ClientState) CheckMisbehaviourAndUpdateState( + ctx sdk.Context, + cdc codec.BinaryMarshaler, + clientStore sdk.KVStore, + misbehaviour clientexported.Misbehaviour, +) (clientexported.ClientState, error) { + + // If client is already frozen at earlier height than misbehaviour, return with error + if cs.IsFrozen() && cs.FrozenHeight <= uint64(misbehaviour.GetHeight()) { + return nil, sdkerrors.Wrapf(clienttypes.ErrInvalidMisbehaviour, + "client is already frozen at earlier height %d than misbehaviour height %d", cs.FrozenHeight, misbehaviour.GetHeight()) + } + + tmEvidence, ok := misbehaviour.(*Misbehaviour) + if !ok { + return nil, sdkerrors.Wrapf(clienttypes.ErrInvalidClientType, "expected type %T, got %T", misbehaviour, &Misbehaviour{}) + } + + // Retrieve trusted consensus states for each Header in misbehaviour + // and unmarshal from clientStore + + // Get consensus bytes from clientStore + tmConsensusState1, err := GetConsensusState(clientStore, cdc, tmEvidence.Header1.TrustedHeight) + if err != nil { + return nil, sdkerrors.Wrapf(err, "could not get trusted consensus state from clientStore for Header1 at TrustedHeight: %d", tmEvidence.Header1.TrustedHeight) + } + + // Get consensus bytes from clientStore + tmConsensusState2, err := GetConsensusState(clientStore, cdc, tmEvidence.Header2.TrustedHeight) + if err != nil { + return nil, sdkerrors.Wrapf(err, "could not get trusted consensus state from clientStore for Header2 at TrustedHeight: %d", tmEvidence.Header2.TrustedHeight) + } + + // calculate the age of the misbehaviour + infractionHeight := tmEvidence.GetHeight() + infractionTime := tmEvidence.GetTime() + ageDuration := ctx.BlockTime().Sub(infractionTime) + ageBlocks := int64(cs.LatestHeight) - infractionHeight + + // TODO: Retrieve consensusparams from client state and not context + // Issue #6516: https://github.com/cosmos/cosmos-sdk/issues/6516 + consensusParams := ctx.ConsensusParams() + + // Reject misbehaviour if the age is too old. Misbehaviour is considered stale + // if the difference in time and number of blocks is greater than the allowed + // parameters defined. + // + // NOTE: The first condition is a safety check as the consensus params cannot + // be nil since the previous param values will be used in case they can't be + // retrieved. If they are not set during initialization, Tendermint will always + // use the default values. + if consensusParams != nil && + consensusParams.Evidence != nil && + (ageDuration > consensusParams.Evidence.MaxAgeDuration || + ageBlocks > consensusParams.Evidence.MaxAgeNumBlocks) { + return nil, sdkerrors.Wrapf(clienttypes.ErrInvalidMisbehaviour, + "age duration (%s) and age blocks (%d) are greater than max consensus params for duration (%s) and block (%d)", + ageDuration, ageBlocks, consensusParams.Evidence.MaxAgeDuration, consensusParams.Evidence.MaxAgeNumBlocks, + ) + } + + // Check the validity of the two conflicting headers against their respective + // trusted consensus states + // NOTE: header height and commitment root assertions are checked in + // misbehaviour.ValidateBasic by the client keeper and msg.ValidateBasic + // by the base application. + if err := checkMisbehaviourHeader( + &cs, tmConsensusState1, tmEvidence.Header1, ctx.BlockTime(), + ); err != nil { + return nil, sdkerrors.Wrap(err, "verifying Header1 in Misbehaviour failed") + } + if err := checkMisbehaviourHeader( + &cs, tmConsensusState2, tmEvidence.Header2, ctx.BlockTime(), + ); err != nil { + return nil, sdkerrors.Wrap(err, "verifying Header2 in Misbehaviour failed") + } + + cs.FrozenHeight = uint64(tmEvidence.GetHeight()) + return &cs, nil +} + +// checkMisbehaviourHeader checks that a Header in Misbehaviour is valid misbehaviour given +// a trusted ConsensusState +func checkMisbehaviourHeader( + clientState *ClientState, consState *ConsensusState, header *Header, currentTimestamp time.Time, +) error { + + tmTrustedValset, err := tmtypes.ValidatorSetFromProto(header.TrustedValidators) + if err != nil { + return sdkerrors.Wrap(err, "trusted validator set is not tendermint validator set type") + } + + tmCommit, err := tmtypes.CommitFromProto(header.Commit) + if err != nil { + return sdkerrors.Wrap(err, "commit is not tendermint commit type") + } + + // check the trusted fields for the header against ConsensusState + if err := checkTrustedHeader(header, consState); err != nil { + return err + } + + // assert that the timestamp is not from more than an unbonding period ago + if currentTimestamp.Sub(consState.Timestamp) >= clientState.UnbondingPeriod { + return sdkerrors.Wrapf( + ErrUnbondingPeriodExpired, + "current timestamp minus the latest consensus state timestamp is greater than or equal to the unbonding period (%s >= %s)", + currentTimestamp.Sub(consState.Timestamp), clientState.UnbondingPeriod, + ) + } + + // - ValidatorSet must have 2/3 similarity with trusted FromValidatorSet + // - ValidatorSets on both headers are valid given the last trusted ValidatorSet + if err := tmTrustedValset.VerifyCommitLightTrusting( + clientState.GetChainID(), tmCommit, clientState.TrustLevel.ToTendermint(), + ); err != nil { + return sdkerrors.Wrapf(clienttypes.ErrInvalidMisbehaviour, "validator set in header has too much change from trusted validator set: %v", err) + } + return nil +} diff --git a/x/ibc/07-tendermint/types/misbehaviour_handle_test.go b/x/ibc/07-tendermint/types/misbehaviour_handle_test.go new file mode 100644 index 0000000000..47bb06c4b1 --- /dev/null +++ b/x/ibc/07-tendermint/types/misbehaviour_handle_test.go @@ -0,0 +1,318 @@ +package types_test + +import ( + "fmt" + "time" + + "github.com/tendermint/tendermint/crypto/tmhash" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/simapp" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" +) + +func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { + altPrivVal := tmtypes.NewMockPV() + altPubKey, err := altPrivVal.GetPubKey() + suite.Require().NoError(err) + + altVal := tmtypes.NewValidator(altPubKey, 4) + + // Create bothValSet with both suite validator and altVal + bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) + bothValsHash := bothValSet.Hash() + // Create alternative validator set with only altVal + altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) + + _, suiteVal := suite.valSet.GetByIndex(0) + + // Create signer array and ensure it is in same order as bothValSet + bothSigners := types.CreateSortedSignerArray(altPrivVal, suite.privVal, altVal, suiteVal) + + altSigners := []tmtypes.PrivValidator{altPrivVal} + + testCases := []struct { + name string + clientState clientexported.ClientState + consensusState1 clientexported.ConsensusState + consensusState2 clientexported.ConsensusState + misbehaviour clientexported.Misbehaviour + timestamp time.Time + expPass bool + }{ + { + "valid misbehavior misbehaviour", + 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(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + true, + }, + { + "valid misbehavior at height greater than last consensusState", + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-1, bothValsHash), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-1, bothValsHash), + &types.Misbehaviour{ + Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + true, + }, + { + "valid misbehavior misbehaviour with different trusted heights", + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-1, bothValsHash), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-3, suite.valsHash), + &types.Misbehaviour{ + Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height-3, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + true, + }, + { + "consensus state's valset hash different from misbehaviour should still pass", + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, suite.valsHash), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, suite.valsHash), + &types.Misbehaviour{ + Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, suite.valSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + true, + }, + { + "invalid misbehavior misbehaviour with trusted height different from trusted consensus state", + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-1, bothValsHash), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-3, suite.valsHash), + &types.Misbehaviour{ + Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + false, + }, + { + "invalid misbehavior misbehaviour with trusted validators different from trusted consensus state", + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-1, bothValsHash), + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-3, suite.valsHash), + &types.Misbehaviour{ + Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height-3, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + false, + }, + { + "already frozen client state", + types.ClientState{FrozenHeight: 1}, + 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(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + false, + }, + { + "trusted consensus state does not exist", + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), + nil, // consensus state for trusted height - 1 does not exist in store + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, bothValsHash), + &types.Misbehaviour{ + Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + false, + }, + { + "invalid tendermint misbehaviour misbehaviour", + 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), + nil, + suite.now, + false, + }, + { + "rejected misbehaviour due to expired age duration", + 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(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now.Add(2 * time.Minute).Add(simapp.DefaultConsensusParams.Evidence.MaxAgeDuration), + false, + }, + { + "rejected misbehaviour due to expired block duration", + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, uint64(height+simapp.DefaultConsensusParams.Evidence.MaxAgeNumBlocks+1), 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(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now.Add(time.Hour), + false, + }, + { + "provided height > header height", + 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(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + false, + }, + { + "unbonding period expired", + types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), + &types.ConsensusState{Timestamp: time.Time{}, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash}, + types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, bothValsHash), + &types.Misbehaviour{ + Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now.Add(ubdPeriod), + false, + }, + { + "trusted validators is incorrect for given consensus state", + 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(chainID, height, height, suite.now, bothValSet, suite.valSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + false, + }, + { + "first valset has too much change", + 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(chainID, height, height, suite.now, altValSet, bothValSet, altSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + false, + }, + { + "second valset has too much change", + 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(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + false, + }, + { + "both valsets have too much change", + 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(chainID, height, height, suite.now, altValSet, bothValSet, altSigners), + Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners), + ChainId: chainID, + ClientId: chainID, + }, + suite.now, + false, + }, + } + + for i, tc := range testCases { + tc := tc + suite.Run(fmt.Sprintf("Case: %s", tc.name), func() { + // reset suite to create fresh application state + suite.SetupTest() + + // Set current timestamp in context + ctx := suite.chainA.GetContext().WithBlockTime(tc.timestamp) + ctx = ctx.WithConsensusParams(simapp.DefaultConsensusParams) + + // Set trusted consensus states in client store + + if tc.consensusState1 != nil { + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientConsensusState(ctx, clientID, tc.consensusState1.GetHeight(), tc.consensusState1) + } + if tc.consensusState2 != nil { + suite.chainA.App.IBCKeeper.ClientKeeper.SetClientConsensusState(ctx, clientID, tc.consensusState2.GetHeight(), tc.consensusState2) + } + + clientState, err := tc.clientState.CheckMisbehaviourAndUpdateState( + ctx, + suite.cdc, + suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(ctx, clientID), // pass in clientID prefixed clientStore + tc.misbehaviour, + ) + + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) + suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.name) + suite.Require().True(clientState.IsFrozen(), "valid test case %d failed: %s", i, tc.name) + suite.Require().Equal(uint64(tc.misbehaviour.GetHeight()), clientState.GetFrozenHeight(), + "valid test case %d failed: %s. Expected FrozenHeight %d got %d", tc.misbehaviour.GetHeight(), clientState.GetFrozenHeight()) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) + suite.Require().Nil(clientState, "invalid test case %d passed: %s", i, tc.name) + } + }) + } +} diff --git a/x/ibc/07-tendermint/types/misbehaviour_test.go b/x/ibc/07-tendermint/types/misbehaviour_test.go index c41f70a499..b9c9927b60 100644 --- a/x/ibc/07-tendermint/types/misbehaviour_test.go +++ b/x/ibc/07-tendermint/types/misbehaviour_test.go @@ -1,318 +1,265 @@ package types_test import ( - "fmt" "time" "github.com/tendermint/tendermint/crypto/tmhash" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/cosmos-sdk/simapp" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" - commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types" ) -func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { +func (suite *TendermintTestSuite) TestEvidence() { + signers := []tmtypes.PrivValidator{suite.privVal} + + misbehaviour := &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader(chainID, height, height-1, suite.now, suite.valSet, suite.valSet, signers), + ChainId: chainID, + ClientId: clientID, + } + + suite.Require().Equal(misbehaviour.ClientType(), clientexported.Tendermint) + suite.Require().Equal(misbehaviour.GetClientID(), clientID) + suite.Require().Equal(misbehaviour.Route(), "client") + suite.Require().Equal(misbehaviour.Type(), "client_misbehaviour") + suite.Require().Equal(misbehaviour.Hash(), tmbytes.HexBytes(tmhash.Sum(suite.cdc.MustMarshalBinaryBare(misbehaviour)))) + suite.Require().Equal(misbehaviour.GetHeight(), int64(height)) +} + +func (suite *TendermintTestSuite) TestEvidenceValidateBasic() { altPrivVal := tmtypes.NewMockPV() altPubKey, err := altPrivVal.GetPubKey() suite.Require().NoError(err) - altVal := tmtypes.NewValidator(altPubKey, 4) + altVal := tmtypes.NewValidator(altPubKey, height) // Create bothValSet with both suite validator and altVal bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) - bothValsHash := bothValSet.Hash() // Create alternative validator set with only altVal altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) - _, suiteVal := suite.valSet.GetByIndex(0) + signers := []tmtypes.PrivValidator{suite.privVal} // Create signer array and ensure it is in same order as bothValSet + _, suiteVal := suite.valSet.GetByIndex(0) bothSigners := types.CreateSortedSignerArray(altPrivVal, suite.privVal, altVal, suiteVal) altSigners := []tmtypes.PrivValidator{altPrivVal} testCases := []struct { - name string - clientState clientexported.ClientState - consensusState1 clientexported.ConsensusState - consensusState2 clientexported.ConsensusState - evidence clientexported.Misbehaviour - timestamp time.Time - expPass bool + name string + misbehaviour *types.Misbehaviour + malleateMisbehaviour func(misbehaviour *types.Misbehaviour) error + expPass bool }{ { - "valid misbehavior evidence", - 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.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + "valid misbehaviour", + &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers), ChainId: chainID, - ClientId: chainID, + ClientId: clientID, }, - suite.now, + func(misbehaviour *types.Misbehaviour) error { return nil }, true, }, { - "valid misbehavior at height greater than last consensusState", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-1, bothValsHash), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-1, bothValsHash), - &types.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + "misbehaviour Header1 is nil", + types.NewMisbehaviour(clientID, chainID, nil, suite.header), + func(m *types.Misbehaviour) error { return nil }, + false, + }, + { + "misbehaviour Header2 is nil", + types.NewMisbehaviour(clientID, chainID, suite.header, nil), + func(m *types.Misbehaviour) error { return nil }, + false, + }, + { + "valid misbehaviour with different trusted headers", + &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader(chainID, height, height-3, suite.now.Add(time.Minute), suite.valSet, bothValSet, signers), ChainId: chainID, - ClientId: chainID, + ClientId: clientID, }, - suite.now, + func(misbehaviour *types.Misbehaviour) error { return nil }, true, }, { - "valid misbehavior evidence with different trusted heights", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-1, bothValsHash), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-3, suite.valsHash), - &types.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height-3, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + "trusted height is 0 in Header1", + &types.Misbehaviour{ + Header1: types.CreateTestHeader(chainID, height, 0, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers), + Header2: suite.header, ChainId: chainID, - ClientId: chainID, + ClientId: clientID, }, - suite.now, - true, - }, - { - "consensus state's valset hash different from evidence should still pass", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, suite.valsHash), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, suite.valsHash), - &types.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, suite.valSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), - ChainId: chainID, - ClientId: chainID, - }, - suite.now, - true, - }, - { - "invalid misbehavior evidence with trusted height different from trusted consensus state", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-1, bothValsHash), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-3, suite.valsHash), - &types.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), - ChainId: chainID, - ClientId: chainID, - }, - suite.now, + func(misbehaviour *types.Misbehaviour) error { return nil }, false, }, { - "invalid misbehavior evidence with trusted validators different from trusted consensus state", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-1, bothValsHash), - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height-3, suite.valsHash), - &types.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height-3, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + "trusted height is 0 in Header2", + &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader(chainID, height, 0, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers), ChainId: chainID, - ClientId: chainID, + ClientId: clientID, }, - suite.now, + func(misbehaviour *types.Misbehaviour) error { return nil }, false, }, { - "already frozen client state", - types.ClientState{FrozenHeight: 1}, - 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.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + "trusted valset is nil in Header1", + &types.Misbehaviour{ + Header1: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), suite.valSet, nil, signers), + Header2: suite.header, ChainId: chainID, - ClientId: chainID, + ClientId: clientID, }, - suite.now, + func(misbehaviour *types.Misbehaviour) error { return nil }, false, }, { - "trusted consensus state does not exist", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), - nil, // consensus state for trusted height - 1 does not exist in store - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, bothValsHash), - &types.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + "trusted valset is nil in Header2", + &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), suite.valSet, nil, signers), ChainId: chainID, - ClientId: chainID, + ClientId: clientID, }, - suite.now, + func(misbehaviour *types.Misbehaviour) error { return nil }, false, }, { - "invalid tendermint misbehaviour evidence", - 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), - nil, - suite.now, + "invalid client ID ", + &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader(chainID, height, height-1, suite.now, suite.valSet, suite.valSet, signers), + ChainId: chainID, + ClientId: "GAIA", + }, + func(misbehaviour *types.Misbehaviour) error { return nil }, false, }, { - "rejected misbehaviour due to expired age duration", - 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.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), - ChainId: chainID, - ClientId: chainID, + "wrong chainID on header1", + &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader("ethermint", height, height-1, suite.now, suite.valSet, suite.valSet, signers), + ChainId: "ethermint", + ClientId: clientID, }, - suite.now.Add(2 * time.Minute).Add(simapp.DefaultConsensusParams.Evidence.MaxAgeDuration), + func(misbehaviour *types.Misbehaviour) error { return nil }, false, }, { - "rejected misbehaviour due to expired block duration", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, uint64(height+simapp.DefaultConsensusParams.Evidence.MaxAgeNumBlocks+1), 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.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + "wrong chainID on header2", + &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader("ethermint", height, height-1, suite.now, suite.valSet, suite.valSet, signers), ChainId: chainID, - ClientId: chainID, + ClientId: clientID, }, - suite.now.Add(time.Hour), + func(misbehaviour *types.Misbehaviour) error { return nil }, false, }, { - "provided height > header height", - 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.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height-1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + "mismatched heights", + &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader(chainID, 6, 4, suite.now, suite.valSet, suite.valSet, signers), ChainId: chainID, - ClientId: chainID, + ClientId: clientID, }, - suite.now, + func(misbehaviour *types.Misbehaviour) error { return nil }, false, }, { - "unbonding period expired", - types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs()), - &types.ConsensusState{Timestamp: time.Time{}, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), NextValidatorsHash: bothValsHash}, - types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), height, bothValsHash), - &types.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + "same block id", + &types.Misbehaviour{ + Header1: suite.header, + Header2: suite.header, ChainId: chainID, - ClientId: chainID, + ClientId: clientID, }, - suite.now.Add(ubdPeriod), + func(misbehaviour *types.Misbehaviour) error { return nil }, false, }, { - "trusted validators is incorrect for given consensus state", - 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.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, suite.valSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + "header 1 doesn't have 2/3 majority", + &types.Misbehaviour{ + Header1: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, suite.valSet, bothSigners), + Header2: suite.header, ChainId: chainID, - ClientId: chainID, + ClientId: clientID, + }, + func(misbehaviour *types.Misbehaviour) error { + // voteSet contains only altVal which is less than 2/3 of total power (height/1height) + wrongVoteSet := tmtypes.NewVoteSet(chainID, int64(misbehaviour.Header1.GetHeight()), 1, tmproto.PrecommitType, altValSet) + blockID, err := tmtypes.BlockIDFromProto(&misbehaviour.Header1.Commit.BlockID) + if err != nil { + return err + } + + tmCommit, err := tmtypes.MakeCommit(*blockID, int64(misbehaviour.Header2.GetHeight()), misbehaviour.Header1.Commit.Round, wrongVoteSet, altSigners, suite.now) + misbehaviour.Header1.Commit = tmCommit.ToProto() + return err }, - suite.now, false, }, { - "first valset has too much change", - 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.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height, suite.now, altValSet, bothValSet, altSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + "header 2 doesn't have 2/3 majority", + &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, suite.valSet, bothSigners), ChainId: chainID, - ClientId: chainID, + ClientId: clientID, + }, + func(misbehaviour *types.Misbehaviour) error { + // voteSet contains only altVal which is less than 2/3 of total power (height/1height) + wrongVoteSet := tmtypes.NewVoteSet(chainID, int64(misbehaviour.Header2.GetHeight()), 1, tmproto.PrecommitType, altValSet) + blockID, err := tmtypes.BlockIDFromProto(&misbehaviour.Header2.Commit.BlockID) + if err != nil { + return err + } + + tmCommit, err := tmtypes.MakeCommit(*blockID, int64(misbehaviour.Header2.GetHeight()), misbehaviour.Header2.Commit.Round, wrongVoteSet, altSigners, suite.now) + misbehaviour.Header2.Commit = tmCommit.ToProto() + return err }, - suite.now, false, }, { - "second valset has too much change", - 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.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners), + "validators sign off on wrong commit", + &types.Misbehaviour{ + Header1: suite.header, + Header2: types.CreateTestHeader(chainID, height, height-1, suite.now, bothValSet, suite.valSet, bothSigners), ChainId: chainID, - ClientId: chainID, + ClientId: clientID, }, - suite.now, - false, - }, - { - "both valsets have too much change", - 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.Evidence{ - Header1: types.CreateTestHeader(chainID, height, height, suite.now, altValSet, bothValSet, altSigners), - Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners), - ChainId: chainID, - ClientId: chainID, + func(misbehaviour *types.Misbehaviour) error { + tmBlockID := types.MakeBlockID(tmhash.Sum([]byte("other_hash")), 3, tmhash.Sum([]byte("other_partset"))) + misbehaviour.Header2.Commit.BlockID = tmBlockID.ToProto() + return nil }, - suite.now, false, }, } for i, tc := range testCases { tc := tc - suite.Run(fmt.Sprintf("Case: %s", tc.name), func() { - // reset suite to create fresh application state - suite.SetupTest() - // Set current timestamp in context - ctx := suite.chainA.GetContext().WithBlockTime(tc.timestamp) - ctx = ctx.WithConsensusParams(simapp.DefaultConsensusParams) + err := tc.malleateMisbehaviour(tc.misbehaviour) + suite.Require().NoError(err) - // Set trusted consensus states in client store - - if tc.consensusState1 != nil { - suite.chainA.App.IBCKeeper.ClientKeeper.SetClientConsensusState(ctx, clientID, tc.consensusState1.GetHeight(), tc.consensusState1) - } - if tc.consensusState2 != nil { - suite.chainA.App.IBCKeeper.ClientKeeper.SetClientConsensusState(ctx, clientID, tc.consensusState2.GetHeight(), tc.consensusState2) - } - - clientState, err := tc.clientState.CheckMisbehaviourAndUpdateState( - ctx, - suite.cdc, - suite.chainA.App.IBCKeeper.ClientKeeper.ClientStore(ctx, clientID), // pass in clientID prefixed clientStore - tc.evidence, - ) - - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.name) - suite.Require().True(clientState.IsFrozen(), "valid test case %d failed: %s", i, tc.name) - suite.Require().Equal(uint64(tc.evidence.GetHeight()), clientState.GetFrozenHeight(), - "valid test case %d failed: %s. Expected FrozenHeight %d got %d", tc.evidence.GetHeight(), clientState.GetFrozenHeight()) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) - suite.Require().Nil(clientState, "invalid test case %d passed: %s", i, tc.name) - } - }) + if tc.expPass { + suite.Require().NoError(tc.misbehaviour.ValidateBasic(), "valid test case %d failed: %s", i, tc.name) + } else { + suite.Require().Error(tc.misbehaviour.ValidateBasic(), "invalid test case %d passed: %s", i, tc.name) + } } } diff --git a/x/ibc/07-tendermint/types/msgs.go b/x/ibc/07-tendermint/types/msgs.go index 44cd756f2e..e93239e2f1 100644 --- a/x/ibc/07-tendermint/types/msgs.go +++ b/x/ibc/07-tendermint/types/msgs.go @@ -186,8 +186,8 @@ func (msg MsgUpdateClient) GetHeader() clientexported.Header { // NewMsgSubmitClientMisbehaviour creates a new MsgSubmitClientMisbehaviour // instance. -func NewMsgSubmitClientMisbehaviour(e *Evidence, s sdk.AccAddress) *MsgSubmitClientMisbehaviour { - return &MsgSubmitClientMisbehaviour{Evidence: e, Submitter: s} +func NewMsgSubmitClientMisbehaviour(m *Misbehaviour, s sdk.AccAddress) *MsgSubmitClientMisbehaviour { + return &MsgSubmitClientMisbehaviour{Misbehaviour: m, Submitter: s} } // Route returns the MsgSubmitClientMisbehaviour's route. @@ -200,10 +200,10 @@ func (msg MsgSubmitClientMisbehaviour) Type() string { // ValidateBasic performs basic (non-state-dependant) validation on a MsgSubmitClientMisbehaviour. func (msg MsgSubmitClientMisbehaviour) ValidateBasic() error { - if msg.Evidence == nil { + if msg.Misbehaviour == nil { return sdkerrors.Wrap(evidencetypes.ErrInvalidEvidence, "missing evidence") } - if err := msg.Evidence.ValidateBasic(); err != nil { + if err := msg.Misbehaviour.ValidateBasic(); err != nil { return err } if msg.Submitter.Empty() { @@ -225,7 +225,7 @@ func (msg MsgSubmitClientMisbehaviour) GetSigners() []sdk.AccAddress { } func (msg MsgSubmitClientMisbehaviour) GetEvidence() evidenceexported.Evidence { - return msg.Evidence + return msg.Misbehaviour } func (msg MsgSubmitClientMisbehaviour) GetSubmitter() sdk.AccAddress { diff --git a/x/ibc/07-tendermint/types/tendermint.pb.go b/x/ibc/07-tendermint/types/tendermint.pb.go index cb10f0a822..28ed8dd574 100644 --- a/x/ibc/07-tendermint/types/tendermint.pb.go +++ b/x/ibc/07-tendermint/types/tendermint.pb.go @@ -131,26 +131,26 @@ func (m *ConsensusState) XXX_DiscardUnknown() { var xxx_messageInfo_ConsensusState proto.InternalMessageInfo -// Evidence is a wrapper over two conflicting Headers -// that implements Evidence interface expected by ICS-02 -type Evidence struct { +// Misbehaviour is a wrapper over two conflicting Headers +// that implements Misbehaviour interface expected by ICS-02 +type Misbehaviour struct { ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` ChainId string `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty" yaml:"chain_id"` Header1 *Header `protobuf:"bytes,3,opt,name=header_1,json=header1,proto3" json:"header_1,omitempty" yaml:"header_1"` Header2 *Header `protobuf:"bytes,4,opt,name=header_2,json=header2,proto3" json:"header_2,omitempty" yaml:"header_2"` } -func (m *Evidence) Reset() { *m = Evidence{} } -func (*Evidence) ProtoMessage() {} -func (*Evidence) Descriptor() ([]byte, []int) { +func (m *Misbehaviour) Reset() { *m = Misbehaviour{} } +func (*Misbehaviour) ProtoMessage() {} +func (*Misbehaviour) Descriptor() ([]byte, []int) { return fileDescriptor_76a953d5a747dd66, []int{2} } -func (m *Evidence) XXX_Unmarshal(b []byte) error { +func (m *Misbehaviour) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *Evidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *Misbehaviour) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_Evidence.Marshal(b, m, deterministic) + return xxx_messageInfo_Misbehaviour.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -160,17 +160,17 @@ func (m *Evidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *Evidence) XXX_Merge(src proto.Message) { - xxx_messageInfo_Evidence.Merge(m, src) +func (m *Misbehaviour) XXX_Merge(src proto.Message) { + xxx_messageInfo_Misbehaviour.Merge(m, src) } -func (m *Evidence) XXX_Size() int { +func (m *Misbehaviour) XXX_Size() int { return m.Size() } -func (m *Evidence) XXX_DiscardUnknown() { - xxx_messageInfo_Evidence.DiscardUnknown(m) +func (m *Misbehaviour) XXX_DiscardUnknown() { + xxx_messageInfo_Misbehaviour.DiscardUnknown(m) } -var xxx_messageInfo_Evidence proto.InternalMessageInfo +var xxx_messageInfo_Misbehaviour proto.InternalMessageInfo // Header defines the Tendermint client consensus Header. // It encapsulates all the information necessary to update from a trusted @@ -387,8 +387,8 @@ var xxx_messageInfo_MsgUpdateClient proto.InternalMessageInfo // MsgSubmitClientMisbehaviour defines an sdk.Msg type that submits Evidence for // light client misbehaviour. type MsgSubmitClientMisbehaviour struct { - Evidence *Evidence `protobuf:"bytes,1,opt,name=evidence,proto3" json:"evidence,omitempty"` - Submitter github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=submitter,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"submitter,omitempty"` + Misbehaviour *Misbehaviour `protobuf:"bytes,1,opt,name=misbehaviour,proto3" json:"misbehaviour,omitempty"` + Submitter github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=submitter,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"submitter,omitempty"` } func (m *MsgSubmitClientMisbehaviour) Reset() { *m = MsgSubmitClientMisbehaviour{} } @@ -427,7 +427,7 @@ var xxx_messageInfo_MsgSubmitClientMisbehaviour proto.InternalMessageInfo func init() { proto.RegisterType((*ClientState)(nil), "ibc.tendermint.ClientState") proto.RegisterType((*ConsensusState)(nil), "ibc.tendermint.ConsensusState") - proto.RegisterType((*Evidence)(nil), "ibc.tendermint.Evidence") + proto.RegisterType((*Misbehaviour)(nil), "ibc.tendermint.Misbehaviour") proto.RegisterType((*Header)(nil), "ibc.tendermint.Header") proto.RegisterType((*Fraction)(nil), "ibc.tendermint.Fraction") proto.RegisterType((*MsgCreateClient)(nil), "ibc.tendermint.MsgCreateClient") @@ -438,76 +438,76 @@ func init() { func init() { proto.RegisterFile("ibc/tendermint/tendermint.proto", fileDescriptor_76a953d5a747dd66) } var fileDescriptor_76a953d5a747dd66 = []byte{ - // 1103 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xcf, 0x4f, 0xe3, 0xc6, - 0x17, 0xc7, 0x21, 0x84, 0x30, 0x09, 0x3f, 0xbe, 0xb3, 0x7c, 0x69, 0x60, 0x69, 0x1c, 0xb9, 0x17, - 0x2e, 0x38, 0x25, 0x8b, 0x5a, 0x09, 0xa9, 0x52, 0xd7, 0x6c, 0x2b, 0xa8, 0x8a, 0x4a, 0x87, 0x6e, - 0x2b, 0x55, 0xaa, 0x2c, 0xc7, 0x9e, 0x24, 0x23, 0x6c, 0x4f, 0xe4, 0x99, 0x20, 0xe8, 0x5f, 0xb0, - 0xbd, 0xed, 0x71, 0x2f, 0x95, 0xda, 0x6b, 0xcf, 0xfd, 0x17, 0x2a, 0xed, 0x91, 0x63, 0x4f, 0x6e, - 0x05, 0xff, 0x41, 0x8e, 0x9c, 0x2a, 0xcf, 0x8c, 0x7f, 0x24, 0xa0, 0xdd, 0x76, 0xb5, 0xcb, 0x05, - 0x66, 0xde, 0x8f, 0xcf, 0x9b, 0xf7, 0xf2, 0x79, 0xef, 0x19, 0xe8, 0xa4, 0xeb, 0xb6, 0x39, 0x0e, - 0x3d, 0x1c, 0x05, 0x24, 0xe4, 0x85, 0xa3, 0x39, 0x8c, 0x28, 0xa7, 0x70, 0x89, 0x74, 0x5d, 0x33, - 0x97, 0x6e, 0xb4, 0x8a, 0xc6, 0x17, 0x43, 0xcc, 0xda, 0x67, 0x8e, 0x4f, 0x3c, 0x87, 0xd3, 0x48, - 0x7a, 0x6c, 0x6c, 0xde, 0xb2, 0x10, 0x7f, 0x95, 0xf6, 0x81, 0x4b, 0xc3, 0x1e, 0xa1, 0xed, 0x61, - 0x44, 0x69, 0x2f, 0x15, 0x36, 0xfb, 0x94, 0xf6, 0x7d, 0xdc, 0x16, 0xb7, 0xee, 0xa8, 0xd7, 0xf6, - 0x46, 0x91, 0xc3, 0x09, 0x0d, 0x95, 0x5e, 0x9f, 0xd6, 0x73, 0x12, 0x60, 0xc6, 0x9d, 0x60, 0x98, - 0x1a, 0x24, 0x69, 0xb8, 0x34, 0x08, 0x08, 0x0f, 0x70, 0xc8, 0x0b, 0x47, 0x65, 0xb0, 0xda, 0xa7, - 0x7d, 0x2a, 0x8e, 0xed, 0xe4, 0x24, 0xa5, 0xc6, 0xb3, 0x39, 0x50, 0xdb, 0xf7, 0x09, 0x0e, 0xf9, - 0x09, 0x77, 0x38, 0x86, 0xeb, 0xa0, 0xea, 0x0e, 0x1c, 0x12, 0xda, 0xc4, 0x6b, 0x68, 0x2d, 0x6d, - 0x6b, 0x01, 0xcd, 0x8b, 0xfb, 0xa1, 0x07, 0x9f, 0x82, 0x1a, 0x8f, 0x46, 0x8c, 0xdb, 0x3e, 0x3e, - 0xc3, 0x7e, 0xa3, 0xd4, 0xd2, 0xb6, 0x6a, 0x9d, 0x86, 0x39, 0x59, 0x1d, 0xf3, 0xf3, 0xc8, 0x71, - 0x93, 0x77, 0x5b, 0x1b, 0x2f, 0x63, 0x7d, 0x66, 0x1c, 0xeb, 0xf0, 0xc2, 0x09, 0xfc, 0x3d, 0xa3, - 0xe0, 0x6a, 0x20, 0x20, 0x6e, 0x5f, 0x26, 0x17, 0xd8, 0x03, 0xcb, 0xe2, 0x46, 0xc2, 0xbe, 0x3d, - 0xc4, 0x11, 0xa1, 0x5e, 0x63, 0x56, 0x40, 0xaf, 0x9b, 0x32, 0x67, 0x33, 0xcd, 0xd9, 0x7c, 0xa2, - 0x6a, 0x62, 0x19, 0x0a, 0x7b, 0xad, 0x80, 0x9d, 0xfb, 0x1b, 0x2f, 0xfe, 0xd2, 0x35, 0xb4, 0x94, - 0x4a, 0x8f, 0x85, 0x10, 0x12, 0xb0, 0x32, 0x0a, 0xbb, 0x34, 0xf4, 0x0a, 0x81, 0xca, 0xaf, 0x0b, - 0xf4, 0x81, 0x0a, 0xf4, 0x9e, 0x0c, 0x34, 0x0d, 0x20, 0x23, 0x2d, 0x67, 0x62, 0x15, 0x0a, 0x83, - 0xe5, 0xc0, 0x39, 0xb7, 0x5d, 0x9f, 0xba, 0xa7, 0xb6, 0x17, 0x91, 0x1e, 0x6f, 0xcc, 0xfd, 0xc7, - 0x94, 0xa6, 0xfc, 0x65, 0xa0, 0xc5, 0xc0, 0x39, 0xdf, 0x4f, 0x84, 0x4f, 0x12, 0x19, 0xfc, 0x04, - 0x2c, 0xf6, 0x22, 0xfa, 0x23, 0x0e, 0xed, 0x01, 0x26, 0xfd, 0x01, 0x6f, 0x54, 0x5a, 0xda, 0x56, - 0xd9, 0x6a, 0x8c, 0x63, 0x7d, 0x55, 0xa2, 0x4c, 0xa8, 0x0d, 0x54, 0x97, 0xf7, 0x03, 0x71, 0x4d, - 0xdc, 0x7d, 0x87, 0x63, 0xc6, 0x53, 0xf7, 0xf9, 0x69, 0xf7, 0x09, 0xb5, 0x81, 0xea, 0xf2, 0xae, - 0xdc, 0x0f, 0x41, 0x4d, 0x30, 0xd8, 0x66, 0x43, 0xec, 0xb2, 0x46, 0xb5, 0x35, 0xbb, 0x55, 0xeb, - 0xac, 0x98, 0xc4, 0x65, 0x9d, 0x47, 0xe6, 0x71, 0xa2, 0x39, 0x19, 0x62, 0xd7, 0x5a, 0xcb, 0x29, - 0x50, 0x30, 0x37, 0x10, 0x18, 0xa6, 0x26, 0x6c, 0xaf, 0xfc, 0xec, 0x17, 0x7d, 0xc6, 0xf8, 0xbd, - 0x04, 0x96, 0xf6, 0x69, 0xc8, 0x70, 0xc8, 0x46, 0x4c, 0xb2, 0xd1, 0x02, 0x0b, 0x19, 0xcf, 0x05, - 0x1d, 0x6b, 0x9d, 0x8d, 0x5b, 0x25, 0xfc, 0x26, 0xb5, 0xb0, 0xaa, 0x49, 0x0d, 0x9f, 0x27, 0x95, - 0xca, 0xdd, 0xe0, 0x2e, 0x28, 0x47, 0x94, 0x72, 0xc5, 0xd7, 0x0d, 0xc1, 0xd7, 0x42, 0x73, 0x1c, - 0xe1, 0xe8, 0xd4, 0xc7, 0x88, 0x52, 0x6e, 0x95, 0x13, 0x77, 0x24, 0xac, 0xe1, 0x1a, 0xa8, 0xa8, - 0xaa, 0x24, 0x64, 0x2c, 0x23, 0x75, 0x83, 0x3f, 0x69, 0x60, 0x35, 0xc4, 0xe7, 0xdc, 0xce, 0x7a, - 0x9e, 0xd9, 0x03, 0x87, 0x0d, 0x04, 0x95, 0xea, 0xd6, 0x77, 0xe3, 0x58, 0x7f, 0x28, 0xb3, 0xbd, - 0xcb, 0xca, 0xb8, 0x89, 0xf5, 0xdd, 0x3e, 0xe1, 0x83, 0x51, 0x37, 0x79, 0xc3, 0xdd, 0x63, 0xa7, - 0xed, 0x93, 0x2e, 0x6b, 0x77, 0x2f, 0x38, 0x66, 0xe6, 0x01, 0x3e, 0xb7, 0x92, 0x03, 0x82, 0x09, - 0xdc, 0xb7, 0x19, 0xda, 0x81, 0xc3, 0x06, 0xaa, 0x6c, 0x3f, 0x97, 0x40, 0xf5, 0xb3, 0x33, 0xe2, - 0xe1, 0xd0, 0xc5, 0x70, 0x07, 0x2c, 0xb8, 0xa2, 0x9b, 0xb3, 0xfe, 0xb5, 0x56, 0xc7, 0xb1, 0xbe, - 0x22, 0x9f, 0x94, 0xa9, 0x0c, 0x54, 0x95, 0xe7, 0x43, 0x0f, 0x9a, 0x85, 0x8e, 0x2f, 0x09, 0x8f, - 0x07, 0xe3, 0x58, 0x5f, 0x56, 0x1e, 0x4a, 0x63, 0xe4, 0x63, 0xe0, 0x6b, 0x50, 0x1d, 0x60, 0xc7, - 0xc3, 0x91, 0xbd, 0xa3, 0x1a, 0x75, 0x6d, 0x7a, 0x06, 0x1c, 0x08, 0xbd, 0xd5, 0xbc, 0x8a, 0xf5, - 0x79, 0x79, 0xde, 0xc9, 0x21, 0x53, 0x67, 0x03, 0xcd, 0xcb, 0xe3, 0x4e, 0x01, 0xb2, 0xa3, 0x5a, - 0xf2, 0x5f, 0x40, 0x76, 0x6e, 0x41, 0x76, 0x32, 0xc8, 0xce, 0x5e, 0x35, 0xa9, 0xcd, 0x8b, 0xa4, - 0x3e, 0x37, 0x25, 0x50, 0x91, 0x1e, 0xd0, 0x01, 0x8b, 0x8c, 0xf4, 0x43, 0xec, 0xd9, 0xd2, 0x4c, - 0x51, 0xaa, 0x59, 0x0c, 0x24, 0x27, 0xf5, 0x89, 0x30, 0x53, 0x41, 0x37, 0x2f, 0x63, 0x5d, 0xcb, - 0xbb, 0x62, 0x02, 0xc2, 0x40, 0x75, 0x56, 0xb0, 0x85, 0x3f, 0x80, 0xc5, 0xec, 0x37, 0xb7, 0x19, - 0x4e, 0x69, 0x77, 0x47, 0x88, 0xec, 0xc7, 0x3c, 0xc1, 0xbc, 0xd8, 0x74, 0x13, 0xee, 0x06, 0xaa, - 0x9f, 0x15, 0xec, 0xe0, 0xa7, 0x40, 0x8e, 0x35, 0x11, 0x3f, 0xa7, 0xa7, 0xb5, 0x3e, 0x8e, 0xf5, - 0xff, 0x17, 0x86, 0x61, 0xa6, 0x37, 0xd0, 0xa2, 0x12, 0xa8, 0xb6, 0xf5, 0x01, 0x4c, 0x2d, 0x72, - 0x72, 0xaa, 0xaa, 0xbf, 0xee, 0x95, 0xef, 0x8f, 0x63, 0x7d, 0x7d, 0x32, 0x4a, 0x8e, 0x61, 0xa0, - 0xff, 0x29, 0x61, 0x4e, 0x53, 0xe3, 0x0b, 0x50, 0x4d, 0x17, 0x02, 0xdc, 0x04, 0x0b, 0xe1, 0x28, - 0xc0, 0x51, 0xa2, 0x11, 0x95, 0x9f, 0x45, 0xb9, 0x00, 0xb6, 0x40, 0xcd, 0xc3, 0x21, 0x0d, 0x48, - 0x28, 0xf4, 0x25, 0xa1, 0x2f, 0x8a, 0x8c, 0x5f, 0xe7, 0xc0, 0xf2, 0x11, 0xeb, 0xef, 0x47, 0xd8, - 0xe1, 0x58, 0xee, 0xac, 0x37, 0xe3, 0x7b, 0x45, 0xfd, 0xfa, 0xa5, 0x57, 0x51, 0x0d, 0x29, 0xab, - 0xe9, 0xb5, 0x37, 0xfb, 0xee, 0xd6, 0x5e, 0xf9, 0xbe, 0xd6, 0xde, 0xdc, 0xbd, 0xad, 0xbd, 0xca, - 0x3b, 0x58, 0x7b, 0x6f, 0x6f, 0xf1, 0xc0, 0x43, 0x50, 0x11, 0xdd, 0x1b, 0x89, 0xdd, 0x57, 0xb7, - 0x76, 0x6e, 0x62, 0x7d, 0xbb, 0x30, 0x9f, 0x5d, 0xca, 0x02, 0xca, 0xd4, 0xbf, 0x6d, 0xe6, 0x9d, - 0xaa, 0x0f, 0xb9, 0xc7, 0xae, 0xfb, 0xd8, 0xf3, 0x22, 0xcc, 0x18, 0x52, 0x00, 0x6a, 0x18, 0xff, - 0xa1, 0x09, 0x8e, 0x3e, 0x1d, 0x7a, 0xf7, 0xca, 0xd1, 0x3c, 0x8f, 0xd9, 0xb7, 0x93, 0xc7, 0x6f, - 0x1a, 0x78, 0x78, 0xc4, 0xfa, 0x27, 0xa3, 0x6e, 0x40, 0xb8, 0xcc, 0xe3, 0x88, 0xb0, 0x2e, 0x1e, - 0x38, 0x67, 0x84, 0x8e, 0x22, 0xb8, 0x0b, 0xaa, 0x58, 0xed, 0x1c, 0x35, 0x44, 0x6f, 0x75, 0x44, - 0xba, 0x93, 0x50, 0x66, 0x09, 0xbf, 0x02, 0x0b, 0x4c, 0x20, 0x72, 0x95, 0xd9, 0x1b, 0xbd, 0x34, - 0xc7, 0x90, 0x8f, 0xb5, 0x8e, 0x5f, 0x5e, 0x35, 0xb5, 0xcb, 0xab, 0xa6, 0xf6, 0xf7, 0x55, 0x53, - 0x7b, 0x7e, 0xdd, 0x9c, 0xb9, 0xbc, 0x6e, 0xce, 0xfc, 0x79, 0xdd, 0x9c, 0xf9, 0xfe, 0xa3, 0x57, - 0x22, 0x9f, 0xb7, 0x93, 0x6f, 0xe6, 0x0f, 0x3f, 0xde, 0x9e, 0xfe, 0x5c, 0xef, 0x56, 0x04, 0x51, - 0x1f, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0x59, 0x41, 0xd4, 0xdb, 0x1c, 0x0c, 0x00, 0x00, + // 1096 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4f, 0x4f, 0x1b, 0x47, + 0x14, 0x67, 0x8d, 0x31, 0x66, 0x6c, 0xfe, 0x74, 0x42, 0xa9, 0x21, 0xd4, 0x6b, 0x6d, 0x2f, 0x5c, + 0x58, 0x17, 0x27, 0x6a, 0x25, 0xa4, 0x4a, 0xc9, 0x12, 0x55, 0x50, 0x15, 0x95, 0x0e, 0x4d, 0x2b, + 0x55, 0xaa, 0x56, 0xeb, 0xdd, 0xb1, 0x3d, 0x62, 0x77, 0xc7, 0xda, 0x19, 0x23, 0xe8, 0x27, 0x48, + 0x6f, 0x39, 0xe6, 0xd8, 0x7c, 0x87, 0xaa, 0xdf, 0xa0, 0x52, 0x8e, 0x1c, 0x7b, 0xda, 0x56, 0xf0, + 0x0d, 0x7c, 0xe4, 0x54, 0xed, 0xcc, 0xec, 0x1f, 0x1b, 0x94, 0x34, 0x51, 0xc2, 0x05, 0xe6, 0xfd, + 0xfb, 0xbd, 0x99, 0xe7, 0xdf, 0x7b, 0x6f, 0x81, 0x4e, 0xba, 0x6e, 0x9b, 0xe3, 0xd0, 0xc3, 0x51, + 0x40, 0x42, 0x5e, 0x38, 0x9a, 0xc3, 0x88, 0x72, 0x0a, 0x97, 0x48, 0xd7, 0x35, 0x73, 0xed, 0x46, + 0xab, 0xe8, 0x7c, 0x3e, 0xc4, 0xac, 0x7d, 0xea, 0xf8, 0xc4, 0x73, 0x38, 0x8d, 0x64, 0xc4, 0xc6, + 0xe6, 0x0d, 0x0f, 0xf1, 0x57, 0x59, 0xef, 0xb9, 0x34, 0xec, 0x11, 0xda, 0x1e, 0x46, 0x94, 0xf6, + 0x52, 0x65, 0xb3, 0x4f, 0x69, 0xdf, 0xc7, 0x6d, 0x21, 0x75, 0x47, 0xbd, 0xb6, 0x37, 0x8a, 0x1c, + 0x4e, 0x68, 0xa8, 0xec, 0xfa, 0xb4, 0x9d, 0x93, 0x00, 0x33, 0xee, 0x04, 0xc3, 0xd4, 0x21, 0x79, + 0x86, 0x4b, 0x83, 0x80, 0xf0, 0x00, 0x87, 0xbc, 0x70, 0x54, 0x0e, 0xab, 0x7d, 0xda, 0xa7, 0xe2, + 0xd8, 0x4e, 0x4e, 0x52, 0x6b, 0x3c, 0x9b, 0x03, 0xb5, 0x3d, 0x9f, 0xe0, 0x90, 0x1f, 0x73, 0x87, + 0x63, 0xb8, 0x0e, 0xaa, 0xee, 0xc0, 0x21, 0xa1, 0x4d, 0xbc, 0x86, 0xd6, 0xd2, 0xb6, 0x16, 0xd0, + 0xbc, 0x90, 0x0f, 0x3c, 0xf8, 0x14, 0xd4, 0x78, 0x34, 0x62, 0xdc, 0xf6, 0xf1, 0x29, 0xf6, 0x1b, + 0xa5, 0x96, 0xb6, 0x55, 0xeb, 0x34, 0xcc, 0xc9, 0xea, 0x98, 0x5f, 0x47, 0x8e, 0x9b, 0xdc, 0xdb, + 0xda, 0x78, 0x15, 0xeb, 0x33, 0xe3, 0x58, 0x87, 0xe7, 0x4e, 0xe0, 0xef, 0x1a, 0x85, 0x50, 0x03, + 0x01, 0x21, 0x7d, 0x9b, 0x08, 0xb0, 0x07, 0x96, 0x85, 0x44, 0xc2, 0xbe, 0x3d, 0xc4, 0x11, 0xa1, + 0x5e, 0x63, 0x56, 0x40, 0xaf, 0x9b, 0xf2, 0xcd, 0x66, 0xfa, 0x66, 0xf3, 0x89, 0xaa, 0x89, 0x65, + 0x28, 0xec, 0xb5, 0x02, 0x76, 0x1e, 0x6f, 0xbc, 0xf8, 0x47, 0xd7, 0xd0, 0x52, 0xaa, 0x3d, 0x12, + 0x4a, 0x48, 0xc0, 0xca, 0x28, 0xec, 0xd2, 0xd0, 0x2b, 0x24, 0x2a, 0xbf, 0x29, 0xd1, 0x67, 0x2a, + 0xd1, 0x27, 0x32, 0xd1, 0x34, 0x80, 0xcc, 0xb4, 0x9c, 0xa9, 0x55, 0x2a, 0x0c, 0x96, 0x03, 0xe7, + 0xcc, 0x76, 0x7d, 0xea, 0x9e, 0xd8, 0x5e, 0x44, 0x7a, 0xbc, 0x31, 0xf7, 0x96, 0x4f, 0x9a, 0x8a, + 0x97, 0x89, 0x16, 0x03, 0xe7, 0x6c, 0x2f, 0x51, 0x3e, 0x49, 0x74, 0xf0, 0x2b, 0xb0, 0xd8, 0x8b, + 0xe8, 0xaf, 0x38, 0xb4, 0x07, 0x98, 0xf4, 0x07, 0xbc, 0x51, 0x69, 0x69, 0x5b, 0x65, 0xab, 0x31, + 0x8e, 0xf5, 0x55, 0x89, 0x32, 0x61, 0x36, 0x50, 0x5d, 0xca, 0xfb, 0x42, 0x4c, 0xc2, 0x7d, 0x87, + 0x63, 0xc6, 0xd3, 0xf0, 0xf9, 0xe9, 0xf0, 0x09, 0xb3, 0x81, 0xea, 0x52, 0x56, 0xe1, 0x07, 0xa0, + 0x26, 0x18, 0x6c, 0xb3, 0x21, 0x76, 0x59, 0xa3, 0xda, 0x9a, 0xdd, 0xaa, 0x75, 0x56, 0x4c, 0xe2, + 0xb2, 0xce, 0x03, 0xf3, 0x28, 0xb1, 0x1c, 0x0f, 0xb1, 0x6b, 0xad, 0xe5, 0x14, 0x28, 0xb8, 0x1b, + 0x08, 0x0c, 0x53, 0x17, 0xb6, 0x5b, 0x7e, 0xf6, 0xbb, 0x3e, 0x63, 0xfc, 0x51, 0x02, 0x4b, 0x7b, + 0x34, 0x64, 0x38, 0x64, 0x23, 0x26, 0xd9, 0x68, 0x81, 0x85, 0x8c, 0xe7, 0x82, 0x8e, 0xb5, 0xce, + 0xc6, 0x8d, 0x12, 0xfe, 0x90, 0x7a, 0x58, 0xd5, 0xa4, 0x86, 0xcf, 0x93, 0x4a, 0xe5, 0x61, 0xf0, + 0x21, 0x28, 0x47, 0x94, 0x72, 0xc5, 0xd7, 0x0d, 0xc1, 0xd7, 0x42, 0x73, 0x1c, 0xe2, 0xe8, 0xc4, + 0xc7, 0x88, 0x52, 0x6e, 0x95, 0x93, 0x70, 0x24, 0xbc, 0xe1, 0x1a, 0xa8, 0xa8, 0xaa, 0x24, 0x64, + 0x2c, 0x23, 0x25, 0xc1, 0xdf, 0x34, 0xb0, 0x1a, 0xe2, 0x33, 0x6e, 0x67, 0x3d, 0xcf, 0xec, 0x81, + 0xc3, 0x06, 0x82, 0x4a, 0x75, 0xeb, 0xa7, 0x71, 0xac, 0xdf, 0x97, 0xaf, 0xbd, 0xcd, 0xcb, 0xb8, + 0x8e, 0xf5, 0x87, 0x7d, 0xc2, 0x07, 0xa3, 0x6e, 0x72, 0x87, 0xdb, 0xc7, 0x4e, 0xdb, 0x27, 0x5d, + 0xd6, 0xee, 0x9e, 0x73, 0xcc, 0xcc, 0x7d, 0x7c, 0x66, 0x25, 0x07, 0x04, 0x13, 0xb8, 0x1f, 0x33, + 0xb4, 0x7d, 0x87, 0x0d, 0x54, 0xd9, 0x5e, 0x96, 0x40, 0xfd, 0x90, 0xb0, 0x2e, 0x1e, 0x38, 0xa7, + 0x84, 0x8e, 0x22, 0xb8, 0x03, 0x16, 0x5c, 0xd1, 0xd1, 0x59, 0x0f, 0x5b, 0xab, 0xe3, 0x58, 0x5f, + 0x91, 0xd7, 0xca, 0x4c, 0x06, 0xaa, 0xca, 0xf3, 0x81, 0x07, 0xcd, 0x42, 0xd7, 0x97, 0x44, 0xc4, + 0xbd, 0x71, 0xac, 0x2f, 0xab, 0x08, 0x65, 0x31, 0xf2, 0x51, 0xf0, 0x3d, 0xa8, 0x0e, 0xb0, 0xe3, + 0xe1, 0xc8, 0xde, 0x51, 0xcd, 0xba, 0x36, 0x3d, 0x07, 0xf6, 0x85, 0xdd, 0x6a, 0x5e, 0xc6, 0xfa, + 0xbc, 0x3c, 0xef, 0xe4, 0x90, 0x69, 0xb0, 0x81, 0xe6, 0xe5, 0x71, 0xa7, 0x00, 0xd9, 0x51, 0x6d, + 0xf9, 0x3f, 0x20, 0x3b, 0x37, 0x20, 0x3b, 0x19, 0x64, 0x67, 0xb7, 0x9a, 0xd4, 0xe7, 0x45, 0x52, + 0xa3, 0xeb, 0x12, 0xa8, 0xc8, 0x08, 0xe8, 0x80, 0x45, 0x46, 0xfa, 0x21, 0xf6, 0x6c, 0xe9, 0xa6, + 0x68, 0xd5, 0x2c, 0x26, 0x92, 0xd3, 0xfa, 0x58, 0xb8, 0xa9, 0xa4, 0x9b, 0x17, 0xb1, 0xae, 0xe5, + 0x9d, 0x31, 0x01, 0x61, 0xa0, 0x3a, 0x2b, 0xf8, 0xc2, 0x5f, 0xc0, 0x62, 0xf6, 0xbb, 0xdb, 0x0c, + 0xa7, 0xd4, 0xbb, 0x25, 0x45, 0xf6, 0x83, 0x1e, 0x63, 0x5e, 0x6c, 0xbc, 0x89, 0x70, 0x03, 0xd5, + 0x4f, 0x0b, 0x7e, 0xf0, 0x11, 0x90, 0xa3, 0x4d, 0xe4, 0xcf, 0x29, 0x6a, 0xad, 0x8f, 0x63, 0xfd, + 0xe3, 0xc2, 0x40, 0xcc, 0xec, 0x06, 0x5a, 0x54, 0x0a, 0xd5, 0xba, 0x3e, 0x80, 0xa9, 0x47, 0x4e, + 0x50, 0x55, 0xf5, 0x37, 0xdd, 0xf2, 0xd3, 0x71, 0xac, 0xaf, 0x4f, 0x66, 0xc9, 0x31, 0x0c, 0xf4, + 0x91, 0x52, 0xe6, 0x54, 0x35, 0xbe, 0x01, 0xd5, 0x74, 0x29, 0xc0, 0x4d, 0xb0, 0x10, 0x8e, 0x02, + 0x1c, 0x25, 0x16, 0x51, 0xf9, 0x59, 0x94, 0x2b, 0x60, 0x0b, 0xd4, 0x3c, 0x1c, 0xd2, 0x80, 0x84, + 0xc2, 0x5e, 0x12, 0xf6, 0xa2, 0xca, 0x78, 0x39, 0x07, 0x96, 0x0f, 0x59, 0x7f, 0x2f, 0xc2, 0x0e, + 0xc7, 0x72, 0x6f, 0xbd, 0x1b, 0xdf, 0x2b, 0xea, 0xd7, 0x2f, 0xbd, 0x8e, 0x6a, 0x48, 0x79, 0x4d, + 0xaf, 0xbe, 0xd9, 0x0f, 0xb7, 0xfa, 0xca, 0x77, 0xb5, 0xfa, 0xe6, 0xee, 0x6c, 0xf5, 0x55, 0x3e, + 0xc0, 0xea, 0x7b, 0x7f, 0xcb, 0x07, 0x1e, 0x80, 0x8a, 0xe8, 0xde, 0x48, 0xec, 0xbf, 0xba, 0xb5, + 0x73, 0x1d, 0xeb, 0xdb, 0x85, 0x19, 0xed, 0x52, 0x16, 0x50, 0xa6, 0xfe, 0x6d, 0x33, 0xef, 0x44, + 0x7d, 0xcc, 0x3d, 0x76, 0xdd, 0xc7, 0x9e, 0x17, 0x61, 0xc6, 0x90, 0x02, 0x50, 0x03, 0xf9, 0x2f, + 0x4d, 0x70, 0xf4, 0xe9, 0xd0, 0xbb, 0x53, 0x8e, 0xe6, 0xef, 0x98, 0x7d, 0x3f, 0xef, 0xf8, 0x53, + 0x03, 0xf7, 0x0f, 0x59, 0xff, 0x78, 0xd4, 0x0d, 0x08, 0x97, 0xef, 0x98, 0xd8, 0x33, 0x8f, 0x40, + 0x3d, 0x28, 0xc8, 0x6a, 0x90, 0x6e, 0x4e, 0x5f, 0xb3, 0x18, 0x83, 0x26, 0x22, 0xe0, 0x77, 0x60, + 0x81, 0x09, 0x74, 0xae, 0x5e, 0xf9, 0x4e, 0xb7, 0xce, 0x31, 0xe4, 0xc5, 0xad, 0xa3, 0x57, 0x97, + 0x4d, 0xed, 0xe2, 0xb2, 0xa9, 0xfd, 0x7b, 0xd9, 0xd4, 0x9e, 0x5f, 0x35, 0x67, 0x2e, 0xae, 0x9a, + 0x33, 0x7f, 0x5f, 0x35, 0x67, 0x7e, 0xfe, 0xe2, 0xb5, 0xc8, 0x67, 0xed, 0xe4, 0x1b, 0xfa, 0xf3, + 0x2f, 0xb7, 0xa7, 0x3f, 0xdf, 0xbb, 0x15, 0x41, 0xda, 0x07, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, + 0xbf, 0xdb, 0xea, 0x9e, 0x2c, 0x0c, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { @@ -651,7 +651,7 @@ func (m *ConsensusState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *Evidence) Marshal() (dAtA []byte, err error) { +func (m *Misbehaviour) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -661,12 +661,12 @@ func (m *Evidence) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *Evidence) MarshalTo(dAtA []byte) (int, error) { +func (m *Misbehaviour) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Misbehaviour) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -982,9 +982,9 @@ func (m *MsgSubmitClientMisbehaviour) MarshalToSizedBuffer(dAtA []byte) (int, er i-- dAtA[i] = 0x12 } - if m.Evidence != nil { + if m.Misbehaviour != nil { { - size, err := m.Evidence.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Misbehaviour.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -1061,7 +1061,7 @@ func (m *ConsensusState) Size() (n int) { return n } -func (m *Evidence) Size() (n int) { +func (m *Misbehaviour) Size() (n int) { if m == nil { return 0 } @@ -1187,8 +1187,8 @@ func (m *MsgSubmitClientMisbehaviour) Size() (n int) { } var l int _ = l - if m.Evidence != nil { - l = m.Evidence.Size() + if m.Misbehaviour != nil { + l = m.Misbehaviour.Size() n += 1 + l + sovTendermint(uint64(l)) } l = len(m.Submitter) @@ -1665,7 +1665,7 @@ func (m *ConsensusState) Unmarshal(dAtA []byte) error { } return nil } -func (m *Evidence) Unmarshal(dAtA []byte) error { +func (m *Misbehaviour) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1688,10 +1688,10 @@ func (m *Evidence) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Evidence: wiretype end group for non-group") + return fmt.Errorf("proto: Misbehaviour: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Evidence: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Misbehaviour: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -2632,7 +2632,7 @@ func (m *MsgSubmitClientMisbehaviour) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Misbehaviour", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2659,10 +2659,10 @@ func (m *MsgSubmitClientMisbehaviour) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Evidence == nil { - m.Evidence = &Evidence{} + if m.Misbehaviour == nil { + m.Misbehaviour = &Misbehaviour{} } - if err := m.Evidence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Misbehaviour.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/ibc/09-localhost/types/client_state.go b/x/ibc/09-localhost/types/client_state.go index 94057a00fa..74e4b1a6f1 100644 --- a/x/ibc/09-localhost/types/client_state.go +++ b/x/ibc/09-localhost/types/client_state.go @@ -88,7 +88,7 @@ func (cs ClientState) CheckHeaderAndUpdateState( func (cs ClientState) CheckMisbehaviourAndUpdateState( _ sdk.Context, _ codec.BinaryMarshaler, _ sdk.KVStore, _ clientexported.Misbehaviour, ) (clientexported.ClientState, error) { - return nil, sdkerrors.Wrap(clienttypes.ErrInvalidEvidence, "cannot submit misbehaviour to localhost client") + return nil, sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "cannot submit misbehaviour to localhost client") } // VerifyClientState verifies that the localhost client state is stored locally diff --git a/x/ibc/light-clients/solomachine/client/cli/tx.go b/x/ibc/light-clients/solomachine/client/cli/tx.go index 678e33499a..99b41200f2 100644 --- a/x/ibc/light-clients/solomachine/client/cli/tx.go +++ b/x/ibc/light-clients/solomachine/client/cli/tx.go @@ -102,10 +102,10 @@ func NewUpdateClientCmd() *cobra.Command { // future updates. func NewSubmitMisbehaviourCmd() *cobra.Command { return &cobra.Command{ - Use: "misbehaviour [path/to/evidence.json]", + Use: "misbehaviour [path/to/misbehaviour.json]", Short: "submit a client misbehaviour", Long: "submit a client misbehaviour to prevent future updates", - Example: fmt.Sprintf("%s tx ibc %s misbehaviour [path/to/evidence.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), + Example: fmt.Sprintf("%s tx ibc %s misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) @@ -116,19 +116,19 @@ func NewSubmitMisbehaviourCmd() *cobra.Command { cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) - var ev *types.Evidence - if err := cdc.UnmarshalJSON([]byte(args[0]), ev); err != nil { + var m *types.Misbehaviour + if err := cdc.UnmarshalJSON([]byte(args[0]), m); err != nil { // check for file path if JSON input is not provided contents, err := ioutil.ReadFile(args[0]) if err != nil { return errors.New("neither JSON input nor path to .json file were provided") } - if err := cdc.UnmarshalJSON(contents, ev); err != nil { - return errors.Wrap(err, "error unmarshalling evidence file") + if err := cdc.UnmarshalJSON(contents, m); err != nil { + return errors.Wrap(err, "error unmarshalling misbehaviour file") } } - msg := types.NewMsgSubmitClientMisbehaviour(ev, clientCtx.GetFromAddress()) + msg := types.NewMsgSubmitClientMisbehaviour(m, clientCtx.GetFromAddress()) if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/ibc/light-clients/solomachine/types/evidence.go b/x/ibc/light-clients/solomachine/types/evidence.go deleted file mode 100644 index 91279cce22..0000000000 --- a/x/ibc/light-clients/solomachine/types/evidence.go +++ /dev/null @@ -1,101 +0,0 @@ -package types - -import ( - "bytes" - - yaml "gopkg.in/yaml.v2" - - "github.com/tendermint/tendermint/crypto/tmhash" - tmbytes "github.com/tendermint/tendermint/libs/bytes" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" - 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 ( - _ evidenceexported.Evidence = (*Evidence)(nil) - _ clientexported.Misbehaviour = (*Evidence)(nil) -) - -// ClientType is a Solo Machine light client. -func (ev Evidence) ClientType() clientexported.ClientType { - return clientexported.SoloMachine -} - -// GetClientID returns the ID of the client that committed a misbehaviour. -func (ev Evidence) GetClientID() string { - return ev.ClientId -} - -// Route implements Evidence interface. -func (ev Evidence) Route() string { - return clienttypes.SubModuleName -} - -// Type implements Evidence interface. -func (ev Evidence) Type() string { - return "client_misbehaviour" -} - -// String implements Evidence interface. -func (ev Evidence) String() string { - out, _ := yaml.Marshal(ev) - return string(out) -} - -// Hash implements Evidence interface -func (ev Evidence) Hash() tmbytes.HexBytes { - bz := SubModuleCdc.MustMarshalBinaryBare(&ev) - return tmhash.Sum(bz) -} - -// GetHeight returns the sequence at which misbehaviour occurred. -func (ev Evidence) GetHeight() int64 { - return int64(ev.Sequence) -} - -// ValidateBasic implements Evidence interface. -func (ev Evidence) ValidateBasic() error { - if err := host.ClientIdentifierValidator(ev.ClientId); err != nil { - return sdkerrors.Wrap(err, "invalid client identifier for solo machine") - } - - if ev.Sequence == 0 { - return sdkerrors.Wrap(clienttypes.ErrInvalidEvidence, "sequence cannot be 0") - } - - if err := ev.SignatureOne.ValidateBasic(); err != nil { - return sdkerrors.Wrap(err, "signature one failed basic validation") - } - - if err := ev.SignatureTwo.ValidateBasic(); err != nil { - return sdkerrors.Wrap(err, "signature two failed basic validation") - } - - // evidence signatures cannot be identical - if bytes.Equal(ev.SignatureOne.Signature, ev.SignatureTwo.Signature) { - return sdkerrors.Wrap(clienttypes.ErrInvalidEvidence, "evidence signatures cannot be equal") - } - - // message data signed cannot be identical - if bytes.Equal(ev.SignatureOne.Data, ev.SignatureTwo.Data) { - return sdkerrors.Wrap(clienttypes.ErrInvalidEvidence, "evidence signature data must be signed over different messages") - } - - return nil -} - -// ValidateBasic ensures that the signature and data fields are non-empty. -func (sd SignatureAndData) ValidateBasic() error { - if len(sd.Signature) == 0 { - return sdkerrors.Wrap(ErrInvalidSignatureAndData, "signature cannot be empty") - } - if len(sd.Data) == 0 { - return sdkerrors.Wrap(ErrInvalidSignatureAndData, "data for signature cannot be empty") - } - - return nil -} diff --git a/x/ibc/light-clients/solomachine/types/evidence_test.go b/x/ibc/light-clients/solomachine/types/evidence_test.go deleted file mode 100644 index 87bb39a887..0000000000 --- a/x/ibc/light-clients/solomachine/types/evidence_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package types_test - -import ( - "github.com/tendermint/tendermint/crypto/tmhash" - tmbytes "github.com/tendermint/tendermint/libs/bytes" - - clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine/types" -) - -func (suite *SoloMachineTestSuite) TestEvidence() { - ev := suite.solomachine.CreateEvidence() - - suite.Require().Equal(clientexported.SoloMachine, ev.ClientType()) - suite.Require().Equal(suite.solomachine.ClientID, ev.GetClientID()) - suite.Require().Equal("client", ev.Route()) - suite.Require().Equal("client_misbehaviour", ev.Type()) - suite.Require().Equal(tmbytes.HexBytes(tmhash.Sum(types.SubModuleCdc.MustMarshalBinaryBare(ev))), ev.Hash()) - suite.Require().Equal(int64(suite.solomachine.Sequence), ev.GetHeight()) -} - -func (suite *SoloMachineTestSuite) TestEvidenceValidateBasic() { - testCases := []struct { - name string - malleateEvidence func(ev *types.Evidence) - expPass bool - }{ - { - "valid evidence", - func(*types.Evidence) {}, - true, - }, - { - "invalid client ID", - func(ev *types.Evidence) { - ev.ClientId = "(badclientid)" - }, - false, - }, - { - "sequence is zero", - func(ev *types.Evidence) { - ev.Sequence = 0 - }, - false, - }, - { - "signature one sig is empty", - func(ev *types.Evidence) { - ev.SignatureOne.Signature = []byte{} - }, - false, - }, - { - "signature two sig is empty", - func(ev *types.Evidence) { - ev.SignatureTwo.Signature = []byte{} - }, - false, - }, - { - "signature one data is empty", - func(ev *types.Evidence) { - ev.SignatureOne.Data = nil - }, - false, - }, - { - "signature two data is empty", - func(ev *types.Evidence) { - ev.SignatureTwo.Data = []byte{} - }, - false, - }, - { - "signatures are identical", - func(ev *types.Evidence) { - ev.SignatureTwo.Signature = ev.SignatureOne.Signature - }, - false, - }, - { - "data signed is identical", - func(ev *types.Evidence) { - ev.SignatureTwo.Data = ev.SignatureOne.Data - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - - ev := suite.solomachine.CreateEvidence() - tc.malleateEvidence(ev) - - err := ev.ValidateBasic() - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} diff --git a/x/ibc/light-clients/solomachine/types/misbehaviour.go b/x/ibc/light-clients/solomachine/types/misbehaviour.go index 6e92047904..ed51402841 100644 --- a/x/ibc/light-clients/solomachine/types/misbehaviour.go +++ b/x/ibc/light-clients/solomachine/types/misbehaviour.go @@ -1,62 +1,100 @@ package types import ( - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" + "bytes" + + yaml "gopkg.in/yaml.v2" + + "github.com/tendermint/tendermint/crypto/tmhash" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" 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" ) -// CheckMisbehaviourAndUpdateState determines whether or not the currently registered -// public key signed over two different messages with the same sequence. If this is true -// the client state is updated to a frozen status. -func (cs ClientState) CheckMisbehaviourAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryMarshaler, - clientStore sdk.KVStore, - misbehaviour clientexported.Misbehaviour, -) (clientexported.ClientState, error) { +var ( + _ evidenceexported.Evidence = (*Misbehaviour)(nil) + _ clientexported.Misbehaviour = (*Misbehaviour)(nil) +) - evidence, ok := misbehaviour.(*Evidence) - if !ok { - return nil, sdkerrors.Wrapf( - clienttypes.ErrInvalidClientType, - "evidence type %T, expected %T", misbehaviour, &Evidence{}, - ) - } - - if cs.IsFrozen() { - return nil, sdkerrors.Wrapf(clienttypes.ErrClientFrozen, "client is already frozen") - } - - if err := checkMisbehaviour(cs, evidence); err != nil { - return nil, err - } - - cs.FrozenSequence = uint64(evidence.GetHeight()) - return cs, nil +// ClientType is a Solo Machine light client. +func (misbehaviour Misbehaviour) ClientType() clientexported.ClientType { + return clientexported.SoloMachine } -// checkMisbehaviour checks if the currently registered public key has signed -// over two different messages at the same sequence. -// NOTE: a check that the evidence message data are not equal is done by -// evidence.ValidateBasic which is called by the 02-client keeper. -func checkMisbehaviour(clientState ClientState, evidence *Evidence) error { - pubKey := clientState.ConsensusState.GetPubKey() +// GetClientID returns the ID of the client that committed a misbehaviour. +func (misbehaviour Misbehaviour) GetClientID() string { + return misbehaviour.ClientId +} - data := EvidenceSignBytes(evidence.Sequence, evidence.SignatureOne.Data) +// Route implements Evidence interface. +func (misbehaviour Misbehaviour) Route() string { + return clienttypes.SubModuleName +} - // check first signature - if err := VerifySignature(pubKey, data, evidence.SignatureOne.Signature); err != nil { - return sdkerrors.Wrap(err, "evidence signature one failed to be verified") +// Type implements Evidence interface. +func (misbehaviour Misbehaviour) Type() string { + return clientexported.TypeEvidenceClientMisbehaviour +} + +// String implements Evidence interface. +func (misbehaviour Misbehaviour) String() string { + out, _ := yaml.Marshal(misbehaviour) + return string(out) +} + +// Hash implements Evidence interface +func (misbehaviour Misbehaviour) Hash() tmbytes.HexBytes { + bz := SubModuleCdc.MustMarshalBinaryBare(&misbehaviour) + return tmhash.Sum(bz) +} + +// GetHeight returns the sequence at which misbehaviour occurred. +func (misbehaviour Misbehaviour) GetHeight() int64 { + return int64(misbehaviour.Sequence) +} + +// ValidateBasic implements Evidence interface. +func (misbehaviour Misbehaviour) ValidateBasic() error { + if err := host.ClientIdentifierValidator(misbehaviour.ClientId); err != nil { + return sdkerrors.Wrap(err, "invalid client identifier for solo machine") } - data = EvidenceSignBytes(evidence.Sequence, evidence.SignatureTwo.Data) + if misbehaviour.Sequence == 0 { + return sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "sequence cannot be 0") + } - // check second signature - if err := VerifySignature(pubKey, data, evidence.SignatureTwo.Signature); err != nil { - return sdkerrors.Wrap(err, "evidence signature two failed to be verified") + if err := misbehaviour.SignatureOne.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "signature one failed basic validation") + } + + if err := misbehaviour.SignatureTwo.ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "signature two failed basic validation") + } + + // misbehaviour signatures cannot be identical + if bytes.Equal(misbehaviour.SignatureOne.Signature, misbehaviour.SignatureTwo.Signature) { + return sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "misbehaviour signatures cannot be equal") + } + + // message data signed cannot be identical + if bytes.Equal(misbehaviour.SignatureOne.Data, misbehaviour.SignatureTwo.Data) { + return sdkerrors.Wrap(clienttypes.ErrInvalidMisbehaviour, "misbehaviour signature data must be signed over different messages") + } + + return nil +} + +// ValidateBasic ensures that the signature and data fields are non-empty. +func (sd SignatureAndData) ValidateBasic() error { + if len(sd.Signature) == 0 { + return sdkerrors.Wrap(ErrInvalidSignatureAndData, "signature cannot be empty") + } + if len(sd.Data) == 0 { + return sdkerrors.Wrap(ErrInvalidSignatureAndData, "data for signature cannot be empty") } return nil diff --git a/x/ibc/light-clients/solomachine/types/misbehaviour_handle.go b/x/ibc/light-clients/solomachine/types/misbehaviour_handle.go new file mode 100644 index 0000000000..335c77ab95 --- /dev/null +++ b/x/ibc/light-clients/solomachine/types/misbehaviour_handle.go @@ -0,0 +1,63 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + 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" +) + +// CheckMisbehaviourAndUpdateState determines whether or not the currently registered +// public key signed over two different messages with the same sequence. If this is true +// the client state is updated to a frozen status. +func (cs ClientState) CheckMisbehaviourAndUpdateState( + ctx sdk.Context, + cdc codec.BinaryMarshaler, + clientStore sdk.KVStore, + misbehaviour clientexported.Misbehaviour, +) (clientexported.ClientState, error) { + + soloMisbehaviour, ok := misbehaviour.(*Misbehaviour) + if !ok { + return nil, sdkerrors.Wrapf( + clienttypes.ErrInvalidClientType, + "misbehaviour type %T, expected %T", misbehaviour, &Misbehaviour{}, + ) + } + + if cs.IsFrozen() { + return nil, sdkerrors.Wrapf(clienttypes.ErrClientFrozen, "client is already frozen") + } + + if err := checkMisbehaviour(cs, soloMisbehaviour); err != nil { + return nil, err + } + + cs.FrozenSequence = uint64(soloMisbehaviour.GetHeight()) + return cs, nil +} + +// checkMisbehaviour checks if the currently registered public key has signed +// over two different messages at the same sequence. +// NOTE: a check that the misbehaviour message data are not equal is done by +// misbehaviour.ValidateBasic which is called by the 02-client keeper. +func checkMisbehaviour(clientState ClientState, soloMisbehaviour *Misbehaviour) error { + pubKey := clientState.ConsensusState.GetPubKey() + + data := EvidenceSignBytes(soloMisbehaviour.Sequence, soloMisbehaviour.SignatureOne.Data) + + // check first signature + if err := VerifySignature(pubKey, data, soloMisbehaviour.SignatureOne.Signature); err != nil { + return sdkerrors.Wrap(err, "misbehaviour signature one failed to be verified") + } + + data = EvidenceSignBytes(soloMisbehaviour.Sequence, soloMisbehaviour.SignatureTwo.Data) + + // check second signature + if err := VerifySignature(pubKey, data, soloMisbehaviour.SignatureTwo.Signature); err != nil { + return sdkerrors.Wrap(err, "misbehaviour signature two failed to be verified") + } + + return nil +} diff --git a/x/ibc/light-clients/solomachine/types/misbehaviour_handle_test.go b/x/ibc/light-clients/solomachine/types/misbehaviour_handle_test.go new file mode 100644 index 0000000000..b697172739 --- /dev/null +++ b/x/ibc/light-clients/solomachine/types/misbehaviour_handle_test.go @@ -0,0 +1,145 @@ +package types_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" +) + +func (suite *SoloMachineTestSuite) TestCheckMisbehaviourAndUpdateState() { + var ( + clientState clientexported.ClientState + misbehaviour clientexported.Misbehaviour + ) + + testCases := []struct { + name string + setup func() + expPass bool + }{ + { + "valid misbehaviour", + func() { + clientState = suite.solomachine.ClientState() + misbehaviour = suite.solomachine.CreateMisbehaviour() + }, + true, + }, + { + "client is frozen", + func() { + cs := suite.solomachine.ClientState() + cs.FrozenSequence = 1 + clientState = cs + misbehaviour = suite.solomachine.CreateMisbehaviour() + }, + false, + }, + { + "wrong client state type", + func() { + clientState = ibctmtypes.ClientState{} + misbehaviour = suite.solomachine.CreateMisbehaviour() + }, + false, + }, + { + "invalid misbehaviour type", + func() { + clientState = suite.solomachine.ClientState() + misbehaviour = ibctmtypes.Misbehaviour{} + }, + false, + }, + { + "invalid first signature", + func() { + clientState = suite.solomachine.ClientState() + + // store in temp before assigning to interface type + m := suite.solomachine.CreateMisbehaviour() + + msg := []byte("DATA ONE") + data := append(sdk.Uint64ToBigEndian(suite.solomachine.Sequence+1), msg...) + sig, err := suite.solomachine.PrivateKey.Sign(data) + suite.Require().NoError(err) + + m.SignatureOne.Signature = sig + m.SignatureOne.Data = msg + misbehaviour = m + }, + false, + }, + { + "invalid second signature", + func() { + clientState = suite.solomachine.ClientState() + + // store in temp before assigning to interface type + m := suite.solomachine.CreateMisbehaviour() + + msg := []byte("DATA TWO") + data := append(sdk.Uint64ToBigEndian(suite.solomachine.Sequence+1), msg...) + sig, err := suite.solomachine.PrivateKey.Sign(data) + suite.Require().NoError(err) + + m.SignatureTwo.Signature = sig + m.SignatureTwo.Data = msg + misbehaviour = m + }, + false, + }, + { + "signatures sign over different sequence", + func() { + clientState = suite.solomachine.ClientState() + + // store in temp before assigning to interface type + m := suite.solomachine.CreateMisbehaviour() + + // Signature One + msg := []byte("DATA ONE") + // sequence used is plus 1 + data := append(sdk.Uint64ToBigEndian(suite.solomachine.Sequence+1), msg...) + sig, err := suite.solomachine.PrivateKey.Sign(data) + suite.Require().NoError(err) + + m.SignatureOne.Signature = sig + m.SignatureOne.Data = msg + + // Signature Two + msg = []byte("DATA TWO") + // sequence used is minus 1 + data = append(sdk.Uint64ToBigEndian(suite.solomachine.Sequence-1), msg...) + sig, err = suite.solomachine.PrivateKey.Sign(data) + suite.Require().NoError(err) + + m.SignatureTwo.Signature = sig + m.SignatureTwo.Data = msg + + misbehaviour = m + + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + // setup test + tc.setup() + + clientState, err := clientState.CheckMisbehaviourAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), suite.store, misbehaviour) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().True(clientState.IsFrozen(), "client not frozen") + } else { + suite.Require().Error(err) + suite.Require().Nil(clientState) + } + }) + } +} diff --git a/x/ibc/light-clients/solomachine/types/misbehaviour_test.go b/x/ibc/light-clients/solomachine/types/misbehaviour_test.go index aef81d7a07..67db944bc8 100644 --- a/x/ibc/light-clients/solomachine/types/misbehaviour_test.go +++ b/x/ibc/light-clients/solomachine/types/misbehaviour_test.go @@ -1,124 +1,88 @@ package types_test import ( - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/tendermint/crypto/tmhash" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/solomachine/types" ) -func (suite *SoloMachineTestSuite) TestCheckMisbehaviourAndUpdateState() { - var ( - clientState clientexported.ClientState - evidence clientexported.Misbehaviour - ) +func (suite *SoloMachineTestSuite) TestMisbehaviour() { + misbehaviour := suite.solomachine.CreateMisbehaviour() + suite.Require().Equal(clientexported.SoloMachine, misbehaviour.ClientType()) + suite.Require().Equal(suite.solomachine.ClientID, misbehaviour.GetClientID()) + suite.Require().Equal("client", misbehaviour.Route()) + suite.Require().Equal("client_misbehaviour", misbehaviour.Type()) + suite.Require().Equal(tmbytes.HexBytes(tmhash.Sum(types.SubModuleCdc.MustMarshalBinaryBare(misbehaviour))), misbehaviour.Hash()) + suite.Require().Equal(int64(suite.solomachine.Sequence), misbehaviour.GetHeight()) +} + +func (suite *SoloMachineTestSuite) TestMisbehaviourValidateBasic() { testCases := []struct { - name string - setup func() - expPass bool + name string + malleateMisbehaviour func(misbehaviour *types.Misbehaviour) + expPass bool }{ { - "valid misbehaviour evidence", - func() { - clientState = suite.solomachine.ClientState() - evidence = suite.solomachine.CreateEvidence() - }, + "valid misbehaviour", + func(*types.Misbehaviour) {}, true, }, { - "client is frozen", - func() { - cs := suite.solomachine.ClientState() - cs.FrozenSequence = 1 - clientState = cs - evidence = suite.solomachine.CreateEvidence() + "invalid client ID", + func(misbehaviour *types.Misbehaviour) { + misbehaviour.ClientId = "(badclientid)" }, false, }, { - "wrong client state type", - func() { - clientState = ibctmtypes.ClientState{} - evidence = suite.solomachine.CreateEvidence() + "sequence is zero", + func(misbehaviour *types.Misbehaviour) { + misbehaviour.Sequence = 0 }, false, }, { - "invalid evidence type", - func() { - clientState = suite.solomachine.ClientState() - evidence = ibctmtypes.Evidence{} + "signature one sig is empty", + func(misbehaviour *types.Misbehaviour) { + misbehaviour.SignatureOne.Signature = []byte{} }, false, }, { - "invalid first signature", - func() { - clientState = suite.solomachine.ClientState() - - // store in temp before assigning to interface type - ev := suite.solomachine.CreateEvidence() - - msg := []byte("DATA ONE") - data := append(sdk.Uint64ToBigEndian(suite.solomachine.Sequence+1), msg...) - sig, err := suite.solomachine.PrivateKey.Sign(data) - suite.Require().NoError(err) - - ev.SignatureOne.Signature = sig - ev.SignatureOne.Data = msg - evidence = ev + "signature two sig is empty", + func(misbehaviour *types.Misbehaviour) { + misbehaviour.SignatureTwo.Signature = []byte{} }, false, }, { - "invalid second signature", - func() { - clientState = suite.solomachine.ClientState() - - // store in temp before assigning to interface type - ev := suite.solomachine.CreateEvidence() - - msg := []byte("DATA TWO") - data := append(sdk.Uint64ToBigEndian(suite.solomachine.Sequence+1), msg...) - sig, err := suite.solomachine.PrivateKey.Sign(data) - suite.Require().NoError(err) - - ev.SignatureTwo.Signature = sig - ev.SignatureTwo.Data = msg - evidence = ev + "signature one data is empty", + func(misbehaviour *types.Misbehaviour) { + misbehaviour.SignatureOne.Data = nil }, false, }, { - "signatures sign over different sequence", - func() { - clientState = suite.solomachine.ClientState() - - // store in temp before assigning to interface type - ev := suite.solomachine.CreateEvidence() - - // Signature One - msg := []byte("DATA ONE") - // sequence used is plus 1 - data := append(sdk.Uint64ToBigEndian(suite.solomachine.Sequence+1), msg...) - sig, err := suite.solomachine.PrivateKey.Sign(data) - suite.Require().NoError(err) - - ev.SignatureOne.Signature = sig - ev.SignatureOne.Data = msg - - // Signature Two - msg = []byte("DATA TWO") - // sequence used is minus 1 - data = append(sdk.Uint64ToBigEndian(suite.solomachine.Sequence-1), msg...) - sig, err = suite.solomachine.PrivateKey.Sign(data) - suite.Require().NoError(err) - - ev.SignatureTwo.Signature = sig - ev.SignatureTwo.Data = msg - - evidence = ev - + "signature two data is empty", + func(misbehaviour *types.Misbehaviour) { + misbehaviour.SignatureTwo.Data = []byte{} + }, + false, + }, + { + "signatures are identical", + func(misbehaviour *types.Misbehaviour) { + misbehaviour.SignatureTwo.Signature = misbehaviour.SignatureOne.Signature + }, + false, + }, + { + "data signed is identical", + func(misbehaviour *types.Misbehaviour) { + misbehaviour.SignatureTwo.Data = misbehaviour.SignatureOne.Data }, false, }, @@ -128,17 +92,16 @@ func (suite *SoloMachineTestSuite) TestCheckMisbehaviourAndUpdateState() { tc := tc suite.Run(tc.name, func() { - // setup test - tc.setup() - clientState, err := clientState.CheckMisbehaviourAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), suite.store, evidence) + misbehaviour := suite.solomachine.CreateMisbehaviour() + tc.malleateMisbehaviour(misbehaviour) + + err := misbehaviour.ValidateBasic() if tc.expPass { suite.Require().NoError(err) - suite.Require().True(clientState.IsFrozen(), "client not frozen") } else { suite.Require().Error(err) - suite.Require().Nil(clientState) } }) } diff --git a/x/ibc/light-clients/solomachine/types/msgs.go b/x/ibc/light-clients/solomachine/types/msgs.go index 76713e88c3..92eb9ce6f0 100644 --- a/x/ibc/light-clients/solomachine/types/msgs.go +++ b/x/ibc/light-clients/solomachine/types/msgs.go @@ -126,8 +126,8 @@ func (msg MsgUpdateClient) GetHeader() clientexported.Header { // NewMsgSubmitClientMisbehaviour creates a new MsgSubmitClientMisbehaviour // instance. -func NewMsgSubmitClientMisbehaviour(e *Evidence, s sdk.AccAddress) *MsgSubmitClientMisbehaviour { - return &MsgSubmitClientMisbehaviour{Evidence: e, Submitter: s} +func NewMsgSubmitClientMisbehaviour(m *Misbehaviour, s sdk.AccAddress) *MsgSubmitClientMisbehaviour { + return &MsgSubmitClientMisbehaviour{Misbehaviour: m, Submitter: s} } // Route returns the MsgSubmitClientMisbehaviour's route. @@ -140,7 +140,7 @@ func (msg MsgSubmitClientMisbehaviour) Type() string { // ValidateBasic performs basic (non-state-dependent) validation on a MsgSubmitClientMisbehaviour. func (msg MsgSubmitClientMisbehaviour) ValidateBasic() error { - if err := msg.Evidence.ValidateBasic(); err != nil { + if err := msg.Misbehaviour.ValidateBasic(); err != nil { return err } if msg.Submitter.Empty() { @@ -162,7 +162,7 @@ func (msg MsgSubmitClientMisbehaviour) GetSigners() []sdk.AccAddress { } func (msg MsgSubmitClientMisbehaviour) GetEvidence() evidenceexported.Evidence { - return msg.Evidence + return msg.Misbehaviour } func (msg MsgSubmitClientMisbehaviour) GetSubmitter() sdk.AccAddress { diff --git a/x/ibc/light-clients/solomachine/types/solomachine.pb.go b/x/ibc/light-clients/solomachine/types/solomachine.pb.go index 4f753ba53e..72210ff2bc 100644 --- a/x/ibc/light-clients/solomachine/types/solomachine.pb.go +++ b/x/ibc/light-clients/solomachine/types/solomachine.pb.go @@ -149,26 +149,26 @@ func (m *Header) XXX_DiscardUnknown() { var xxx_messageInfo_Header proto.InternalMessageInfo -// Evidence defines evidence of misbehaviour for a solo machine which consists +// Misbehaviour defines misbehaviour for a solo machine which consists // of a sequence and two signatures over different messages at that sequence. -type Evidence struct { +type Misbehaviour struct { ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` Sequence uint64 `protobuf:"varint,2,opt,name=sequence,proto3" json:"sequence,omitempty"` SignatureOne *SignatureAndData `protobuf:"bytes,3,opt,name=signature_one,json=signatureOne,proto3" json:"signature_one,omitempty" yaml:"signature_one"` SignatureTwo *SignatureAndData `protobuf:"bytes,4,opt,name=signature_two,json=signatureTwo,proto3" json:"signature_two,omitempty" yaml:"signature_two"` } -func (m *Evidence) Reset() { *m = Evidence{} } -func (*Evidence) ProtoMessage() {} -func (*Evidence) Descriptor() ([]byte, []int) { +func (m *Misbehaviour) Reset() { *m = Misbehaviour{} } +func (*Misbehaviour) ProtoMessage() {} +func (*Misbehaviour) Descriptor() ([]byte, []int) { return fileDescriptor_6cc2ee18f7f86d4e, []int{3} } -func (m *Evidence) XXX_Unmarshal(b []byte) error { +func (m *Misbehaviour) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *Evidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *Misbehaviour) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_Evidence.Marshal(b, m, deterministic) + return xxx_messageInfo_Misbehaviour.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -178,17 +178,17 @@ func (m *Evidence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *Evidence) XXX_Merge(src proto.Message) { - xxx_messageInfo_Evidence.Merge(m, src) +func (m *Misbehaviour) XXX_Merge(src proto.Message) { + xxx_messageInfo_Misbehaviour.Merge(m, src) } -func (m *Evidence) XXX_Size() int { +func (m *Misbehaviour) XXX_Size() int { return m.Size() } -func (m *Evidence) XXX_DiscardUnknown() { - xxx_messageInfo_Evidence.DiscardUnknown(m) +func (m *Misbehaviour) XXX_DiscardUnknown() { + xxx_messageInfo_Misbehaviour.DiscardUnknown(m) } -var xxx_messageInfo_Evidence proto.InternalMessageInfo +var xxx_messageInfo_Misbehaviour proto.InternalMessageInfo // SignatureAndData contains a signature and the data signed over to create that // signature. @@ -349,10 +349,10 @@ func (m *MsgUpdateClient) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateClient proto.InternalMessageInfo // MsgSubmitClientMisbehaviour defines an sdk.Msg type that supports submitting -// arbitrary Evidence. +// arbitrary Misbehaviour. type MsgSubmitClientMisbehaviour struct { - Submitter github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=submitter,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"submitter,omitempty"` - Evidence *Evidence `protobuf:"bytes,2,opt,name=evidence,proto3" json:"evidence,omitempty"` + Submitter github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=submitter,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"submitter,omitempty"` + Misbehaviour *Misbehaviour `protobuf:"bytes,2,opt,name=misbehaviour,proto3" json:"misbehaviour,omitempty"` } func (m *MsgSubmitClientMisbehaviour) Reset() { *m = MsgSubmitClientMisbehaviour{} } @@ -392,7 +392,7 @@ func init() { proto.RegisterType((*ClientState)(nil), "ibc.lightclients.solomachine.v1.ClientState") proto.RegisterType((*ConsensusState)(nil), "ibc.lightclients.solomachine.v1.ConsensusState") proto.RegisterType((*Header)(nil), "ibc.lightclients.solomachine.v1.Header") - proto.RegisterType((*Evidence)(nil), "ibc.lightclients.solomachine.v1.Evidence") + proto.RegisterType((*Misbehaviour)(nil), "ibc.lightclients.solomachine.v1.Misbehaviour") proto.RegisterType((*SignatureAndData)(nil), "ibc.lightclients.solomachine.v1.SignatureAndData") proto.RegisterType((*TimestampedSignature)(nil), "ibc.lightclients.solomachine.v1.TimestampedSignature") proto.RegisterType((*MsgCreateClient)(nil), "ibc.lightclients.solomachine.v1.MsgCreateClient") @@ -405,52 +405,52 @@ func init() { } var fileDescriptor_6cc2ee18f7f86d4e = []byte{ - // 716 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0x4d, 0x6f, 0xd3, 0x4c, - 0x10, 0x8e, 0xd3, 0xa8, 0x4a, 0xb6, 0x7d, 0xd3, 0xbe, 0x56, 0x8a, 0x42, 0xa8, 0xe2, 0xca, 0x12, - 0x6a, 0x39, 0xd4, 0x96, 0xe1, 0xd6, 0x0b, 0xaa, 0x43, 0x25, 0x3e, 0x54, 0x15, 0x39, 0x45, 0x42, - 0x80, 0x14, 0xad, 0xed, 0xad, 0xb3, 0x6a, 0xec, 0x35, 0xde, 0x75, 0x42, 0xf8, 0x05, 0x48, 0x5c, - 0x38, 0x72, 0xe4, 0x0f, 0x20, 0x71, 0xe7, 0xc2, 0x0d, 0x4e, 0xa8, 0x47, 0x4e, 0x11, 0x6a, 0xfe, - 0x41, 0x8e, 0x9c, 0x50, 0xbc, 0x1b, 0x27, 0x8e, 0xaa, 0x46, 0x7c, 0x48, 0x9c, 0xbc, 0x3b, 0x9e, - 0x79, 0xe6, 0x79, 0x66, 0x66, 0x77, 0x81, 0x81, 0x6d, 0x47, 0xef, 0x60, 0xaf, 0xcd, 0x9c, 0x0e, - 0x46, 0x01, 0xa3, 0x3a, 0x25, 0x1d, 0xe2, 0x43, 0xa7, 0x8d, 0x03, 0xa4, 0x77, 0x8d, 0xd9, 0xad, - 0x16, 0x46, 0x84, 0x11, 0x59, 0xc1, 0xb6, 0xa3, 0xcd, 0x86, 0x68, 0xb3, 0x3e, 0x5d, 0xa3, 0xb6, - 0xed, 0x10, 0xea, 0x13, 0xaa, 0xdb, 0x90, 0x22, 0xdd, 0x89, 0xfa, 0x21, 0x23, 0x7a, 0xd7, 0xb0, - 0x11, 0x83, 0x86, 0xd8, 0x72, 0xa4, 0x5a, 0xc5, 0x23, 0x1e, 0x49, 0x96, 0xfa, 0x78, 0xc5, 0xad, - 0xea, 0x57, 0x09, 0xac, 0x34, 0x12, 0xe4, 0x26, 0x83, 0x0c, 0xc9, 0x0d, 0xb0, 0x76, 0x12, 0x91, - 0x97, 0x28, 0x68, 0x51, 0xf4, 0x3c, 0x46, 0x81, 0x83, 0xaa, 0xd2, 0x96, 0xb4, 0x53, 0x30, 0x6b, - 0xa3, 0x81, 0x72, 0xa5, 0x0f, 0xfd, 0xce, 0x9e, 0x3a, 0xe7, 0xa0, 0x5a, 0x65, 0x6e, 0x69, 0x0a, - 0x83, 0xcc, 0xc0, 0x9a, 0x43, 0x02, 0x8a, 0x02, 0x1a, 0xd3, 0x16, 0x1d, 0xe3, 0x56, 0xf3, 0x5b, - 0xd2, 0xce, 0xca, 0x4d, 0x5d, 0x5b, 0x20, 0x47, 0x6b, 0x4c, 0xe2, 0x12, 0x3a, 0xb3, 0x59, 0xe7, - 0x10, 0x55, 0xab, 0xec, 0x64, 0x7c, 0xf7, 0x0a, 0xaf, 0xde, 0x29, 0x39, 0xf5, 0xbd, 0x04, 0xca, - 0x59, 0x10, 0xb9, 0x06, 0x8a, 0x59, 0x31, 0x56, 0xba, 0x97, 0x9f, 0x02, 0x10, 0xc6, 0x76, 0x07, - 0x3b, 0xad, 0x53, 0xd4, 0x17, 0x2c, 0xaf, 0x6b, 0xbc, 0xa6, 0xda, 0xb8, 0xa6, 0x9a, 0x28, 0xa2, - 0xa8, 0xa9, 0xf6, 0x30, 0xf1, 0x7e, 0x80, 0xfa, 0xe6, 0xc6, 0x68, 0xa0, 0xfc, 0xcf, 0xb9, 0x4d, - 0x21, 0x54, 0xab, 0x14, 0x4e, 0x3c, 0xe4, 0x4d, 0x50, 0x62, 0xd8, 0x47, 0x94, 0x41, 0x3f, 0xac, - 0x2e, 0x25, 0x99, 0xa7, 0x06, 0xc1, 0xf7, 0x83, 0x04, 0x96, 0xef, 0x22, 0xe8, 0xa2, 0xe8, 0x52, - 0x9e, 0x9b, 0xa0, 0x44, 0xb1, 0x17, 0x40, 0x16, 0x47, 0xbc, 0x98, 0xab, 0xd6, 0xd4, 0x20, 0x9f, - 0x80, 0x72, 0x80, 0x7a, 0xad, 0x19, 0x25, 0x4b, 0xbf, 0xa2, 0xe4, 0xea, 0x68, 0xa0, 0x6c, 0x70, - 0x25, 0x59, 0x18, 0xd5, 0x5a, 0x0d, 0x50, 0x2f, 0x75, 0x14, 0x94, 0x3f, 0xe7, 0x41, 0xf1, 0xa0, - 0x8b, 0xdd, 0x84, 0x98, 0x01, 0x4a, 0xbc, 0x95, 0x2d, 0xec, 0x26, 0xac, 0x4b, 0x66, 0x65, 0x34, - 0x50, 0xd6, 0x45, 0xd3, 0x26, 0xbf, 0x54, 0xab, 0xc8, 0xd7, 0xf7, 0xdc, 0x8c, 0xce, 0xfc, 0x9c, - 0xce, 0x10, 0xfc, 0x97, 0xca, 0x6a, 0x91, 0x00, 0x09, 0x21, 0xc6, 0xc2, 0xc1, 0x69, 0x4e, 0xa2, - 0xf6, 0x03, 0xf7, 0x0e, 0x64, 0xd0, 0xac, 0x8e, 0x06, 0x4a, 0x85, 0xb3, 0xc8, 0x20, 0xaa, 0xd6, - 0x6a, 0xba, 0x3f, 0x0a, 0xe6, 0x32, 0xb2, 0x1e, 0xa9, 0x16, 0xfe, 0x6a, 0x46, 0xd6, 0x23, 0xb3, - 0x19, 0x8f, 0x7b, 0x64, 0xaf, 0x38, 0xae, 0xe2, 0xdb, 0x71, 0x25, 0xef, 0x83, 0xf5, 0x79, 0x94, - 0x6c, 0xa7, 0xa5, 0xf9, 0x4e, 0xcb, 0xa0, 0xe0, 0x42, 0x06, 0xc5, 0x08, 0x24, 0x6b, 0xd1, 0x95, - 0xc7, 0xa0, 0x72, 0x3c, 0x99, 0x2d, 0xe4, 0xa6, 0xb0, 0x0b, 0xf0, 0x32, 0x23, 0x9a, 0xbf, 0x78, - 0x44, 0x3f, 0x49, 0x60, 0xed, 0x90, 0x7a, 0x8d, 0x08, 0x41, 0x86, 0xf8, 0x65, 0xf1, 0x3b, 0x6d, - 0xff, 0x97, 0xb7, 0xc2, 0x6b, 0x2e, 0xe1, 0x51, 0xe8, 0xfe, 0x91, 0x84, 0xdb, 0x60, 0xb9, 0x9d, - 0x9c, 0x55, 0xc1, 0x7c, 0x7b, 0x21, 0x73, 0x7e, 0xb4, 0x2d, 0x11, 0x26, 0xd8, 0x7c, 0x94, 0xc0, - 0xb5, 0x43, 0xea, 0x35, 0x63, 0xdb, 0xc7, 0x8c, 0xb3, 0x39, 0xc4, 0xd4, 0x46, 0x6d, 0xd8, 0xc5, - 0x24, 0x8e, 0xe4, 0x23, 0x50, 0xa2, 0xc9, 0x3f, 0x86, 0x22, 0xde, 0x32, 0xd3, 0xf8, 0x31, 0x50, - 0x76, 0x3d, 0xcc, 0xda, 0xb1, 0xad, 0x39, 0xc4, 0xd7, 0xc5, 0xad, 0xcf, 0x3f, 0xbb, 0xd4, 0x3d, - 0xd5, 0x59, 0x3f, 0x44, 0x54, 0xdb, 0x77, 0x9c, 0x7d, 0xd7, 0x8d, 0x10, 0xa5, 0xd6, 0x14, 0x43, - 0x3e, 0x00, 0x45, 0x24, 0x0e, 0xac, 0x60, 0x7e, 0x63, 0x21, 0xf3, 0xc9, 0x09, 0xb7, 0xd2, 0x50, - 0xce, 0xde, 0x7c, 0xf6, 0xe5, 0xbc, 0x2e, 0x9d, 0x9d, 0xd7, 0xa5, 0xef, 0xe7, 0x75, 0xe9, 0xcd, - 0xb0, 0x9e, 0x3b, 0x1b, 0xd6, 0x73, 0xdf, 0x86, 0xf5, 0xdc, 0x13, 0xf3, 0x52, 0x82, 0x2f, 0xf4, - 0xf4, 0xf9, 0xdb, 0xbd, 0xe8, 0xfd, 0x4b, 0x04, 0xd8, 0xcb, 0xc9, 0xbb, 0x74, 0xeb, 0x67, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xee, 0x37, 0x2c, 0xb2, 0x2c, 0x07, 0x00, 0x00, + // 712 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0xcf, 0x6e, 0xd3, 0x4e, + 0x10, 0x8e, 0xd3, 0xa8, 0x6a, 0xb6, 0xf9, 0xa5, 0xfd, 0x59, 0x29, 0x0a, 0xa1, 0x8a, 0x2b, 0x4b, + 0xa8, 0xbd, 0xc4, 0x96, 0xe1, 0xd6, 0x0b, 0xaa, 0xc3, 0x81, 0x3f, 0xaa, 0x0a, 0x4e, 0x91, 0x10, + 0x20, 0x45, 0x6b, 0x7b, 0xeb, 0xac, 0x1a, 0x7b, 0x8d, 0x77, 0x9d, 0x10, 0x9e, 0x00, 0x89, 0x0b, + 0x47, 0x8e, 0xbc, 0x00, 0x12, 0x8f, 0xc0, 0x0d, 0x24, 0x24, 0xd4, 0x23, 0xa7, 0x08, 0x35, 0x6f, + 0x90, 0x23, 0x27, 0x14, 0xef, 0x26, 0xb1, 0xa3, 0xaa, 0x11, 0x7f, 0x24, 0x4e, 0xde, 0x1d, 0xcf, + 0x7c, 0xf3, 0x7d, 0x33, 0xb3, 0xbb, 0xc0, 0xc0, 0xb6, 0xa3, 0x77, 0xb1, 0xd7, 0x61, 0x4e, 0x17, + 0xa3, 0x80, 0x51, 0x9d, 0x92, 0x2e, 0xf1, 0xa1, 0xd3, 0xc1, 0x01, 0xd2, 0x7b, 0x46, 0x7a, 0xab, + 0x85, 0x11, 0x61, 0x44, 0x56, 0xb0, 0xed, 0x68, 0xe9, 0x10, 0x2d, 0xed, 0xd3, 0x33, 0x6a, 0xbb, + 0x0e, 0xa1, 0x3e, 0xa1, 0xba, 0x0d, 0x29, 0xd2, 0x9d, 0x68, 0x10, 0x32, 0xa2, 0xf7, 0x0c, 0x1b, + 0x31, 0x68, 0x88, 0x2d, 0x47, 0xaa, 0x55, 0x3c, 0xe2, 0x91, 0x64, 0xa9, 0x4f, 0x56, 0xdc, 0xaa, + 0x7e, 0x95, 0xc0, 0x7a, 0x33, 0x41, 0x6e, 0x31, 0xc8, 0x90, 0xdc, 0x04, 0x1b, 0x27, 0x11, 0x79, + 0x89, 0x82, 0x36, 0x45, 0xcf, 0x63, 0x14, 0x38, 0xa8, 0x2a, 0xed, 0x48, 0x7b, 0x05, 0xb3, 0x36, + 0x1e, 0x2a, 0x57, 0x06, 0xd0, 0xef, 0xee, 0xab, 0x0b, 0x0e, 0xaa, 0x55, 0xe6, 0x96, 0x96, 0x30, + 0xc8, 0x0c, 0x6c, 0x38, 0x24, 0xa0, 0x28, 0xa0, 0x31, 0x6d, 0xd3, 0x09, 0x6e, 0x35, 0xbf, 0x23, + 0xed, 0xad, 0xdf, 0xd0, 0xb5, 0x25, 0x72, 0xb4, 0xe6, 0x34, 0x2e, 0xa1, 0x93, 0xce, 0xba, 0x80, + 0xa8, 0x5a, 0x65, 0x27, 0xe3, 0xbb, 0x5f, 0x78, 0xf5, 0x4e, 0xc9, 0xa9, 0xef, 0x25, 0x50, 0xce, + 0x82, 0xc8, 0x35, 0xb0, 0x96, 0x15, 0x63, 0xcd, 0xf6, 0xf2, 0x53, 0x00, 0xc2, 0xd8, 0xee, 0x62, + 0xa7, 0x7d, 0x8a, 0x06, 0x82, 0xe5, 0x75, 0x8d, 0xd7, 0x54, 0x9b, 0xd4, 0x54, 0x13, 0x45, 0x14, + 0x35, 0xd5, 0x1e, 0x24, 0xde, 0xf7, 0xd1, 0xc0, 0xdc, 0x1a, 0x0f, 0x95, 0xff, 0x39, 0xb7, 0x39, + 0x84, 0x6a, 0x15, 0xc3, 0xa9, 0x87, 0xbc, 0x0d, 0x8a, 0x0c, 0xfb, 0x88, 0x32, 0xe8, 0x87, 0xd5, + 0x95, 0x24, 0xf3, 0xdc, 0x20, 0xf8, 0x7e, 0x90, 0xc0, 0xea, 0x1d, 0x04, 0x5d, 0x14, 0x5d, 0xca, + 0x73, 0x1b, 0x14, 0x29, 0xf6, 0x02, 0xc8, 0xe2, 0x88, 0x17, 0xb3, 0x64, 0xcd, 0x0d, 0xf2, 0x09, + 0x28, 0x07, 0xa8, 0xdf, 0x4e, 0x29, 0x59, 0xf9, 0x15, 0x25, 0x57, 0xc7, 0x43, 0x65, 0x8b, 0x2b, + 0xc9, 0xc2, 0xa8, 0x56, 0x29, 0x40, 0xfd, 0x99, 0xa3, 0xa0, 0xfc, 0x25, 0x0f, 0x4a, 0x87, 0x98, + 0xda, 0xa8, 0x03, 0x7b, 0x98, 0xc4, 0x91, 0x6c, 0x80, 0x22, 0x6f, 0x67, 0x1b, 0xbb, 0x09, 0xf3, + 0xa2, 0x59, 0x19, 0x0f, 0x95, 0x4d, 0xd1, 0xb8, 0xe9, 0x2f, 0xd5, 0x5a, 0xe3, 0xeb, 0xbb, 0x6e, + 0x46, 0x6b, 0x7e, 0x41, 0x6b, 0x08, 0xfe, 0x9b, 0x49, 0x6b, 0x93, 0x00, 0x09, 0x31, 0xc6, 0xd2, + 0xe1, 0x69, 0x4d, 0xa3, 0x0e, 0x02, 0xf7, 0x36, 0x64, 0xd0, 0xac, 0x8e, 0x87, 0x4a, 0x85, 0xb3, + 0xc8, 0x20, 0xaa, 0x56, 0x69, 0xb6, 0x3f, 0x0a, 0x16, 0x32, 0xb2, 0x3e, 0xa9, 0x16, 0xfe, 0x6a, + 0x46, 0xd6, 0x27, 0xe9, 0x8c, 0xc7, 0x7d, 0xb2, 0xbf, 0x36, 0xa9, 0xe4, 0xdb, 0x49, 0x35, 0xef, + 0x81, 0xcd, 0x45, 0x94, 0x6c, 0xb7, 0xa5, 0xc5, 0x6e, 0xcb, 0xa0, 0xe0, 0x42, 0x06, 0xc5, 0x18, + 0x24, 0x6b, 0xd1, 0x99, 0xc7, 0xa0, 0x72, 0x3c, 0x9d, 0x2f, 0xe4, 0xce, 0x60, 0x97, 0xe0, 0x65, + 0xc6, 0x34, 0x7f, 0xf1, 0x98, 0x7e, 0x94, 0xc0, 0xc6, 0x21, 0xf5, 0x9a, 0x11, 0x82, 0x0c, 0xf1, + 0x0b, 0xe3, 0x77, 0xda, 0xfe, 0x2f, 0x6f, 0x86, 0xd7, 0x5c, 0xc2, 0xa3, 0xd0, 0xfd, 0x23, 0x09, + 0xb7, 0xc0, 0x6a, 0x27, 0x39, 0xaf, 0x82, 0xf9, 0xee, 0x52, 0xe6, 0xfc, 0x78, 0x5b, 0x22, 0x4c, + 0xb0, 0xf9, 0x24, 0x81, 0x6b, 0x87, 0xd4, 0x6b, 0xc5, 0xb6, 0x8f, 0x19, 0x67, 0x93, 0x39, 0x53, + 0x47, 0xa0, 0x48, 0x93, 0x7f, 0x0c, 0x45, 0xbc, 0x65, 0xa6, 0xf1, 0x63, 0xa8, 0x34, 0x3c, 0xcc, + 0x3a, 0xb1, 0xad, 0x39, 0xc4, 0xd7, 0xc5, 0xcd, 0xcf, 0x3f, 0x0d, 0xea, 0x9e, 0xea, 0x6c, 0x10, + 0x22, 0xaa, 0x1d, 0x38, 0xce, 0x81, 0xeb, 0x46, 0x88, 0x52, 0x6b, 0x8e, 0x21, 0x3f, 0x04, 0x25, + 0x3f, 0x95, 0x40, 0xb0, 0x6f, 0x2c, 0x65, 0x9f, 0x66, 0x65, 0x65, 0x20, 0xb8, 0x12, 0xf3, 0xd9, + 0xe7, 0xf3, 0xba, 0x74, 0x76, 0x5e, 0x97, 0xbe, 0x9f, 0xd7, 0xa5, 0x37, 0xa3, 0x7a, 0xee, 0x6c, + 0x54, 0xcf, 0x7d, 0x1b, 0xd5, 0x73, 0x4f, 0xcc, 0x4b, 0xc9, 0xbe, 0xd0, 0x67, 0xcf, 0x61, 0xe3, + 0xa2, 0xf7, 0x30, 0x11, 0x63, 0xaf, 0x26, 0xef, 0xd4, 0xcd, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, + 0xec, 0x46, 0x40, 0x5d, 0x3c, 0x07, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { @@ -585,7 +585,7 @@ func (m *Header) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *Evidence) Marshal() (dAtA []byte, err error) { +func (m *Misbehaviour) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -595,12 +595,12 @@ func (m *Evidence) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *Evidence) MarshalTo(dAtA []byte) (int, error) { +func (m *Misbehaviour) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Misbehaviour) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -820,9 +820,9 @@ func (m *MsgSubmitClientMisbehaviour) MarshalToSizedBuffer(dAtA []byte) (int, er _ = i var l int _ = l - if m.Evidence != nil { + if m.Misbehaviour != nil { { - size, err := m.Evidence.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Misbehaviour.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -908,7 +908,7 @@ func (m *Header) Size() (n int) { return n } -func (m *Evidence) Size() (n int) { +func (m *Misbehaviour) Size() (n int) { if m == nil { return 0 } @@ -1009,8 +1009,8 @@ func (m *MsgSubmitClientMisbehaviour) Size() (n int) { if l > 0 { n += 1 + l + sovSolomachine(uint64(l)) } - if m.Evidence != nil { - l = m.Evidence.Size() + if m.Misbehaviour != nil { + l = m.Misbehaviour.Size() n += 1 + l + sovSolomachine(uint64(l)) } return n @@ -1399,7 +1399,7 @@ func (m *Header) Unmarshal(dAtA []byte) error { } return nil } -func (m *Evidence) Unmarshal(dAtA []byte) error { +func (m *Misbehaviour) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1422,10 +1422,10 @@ func (m *Evidence) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Evidence: wiretype end group for non-group") + return fmt.Errorf("proto: Misbehaviour: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Evidence: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Misbehaviour: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -2109,7 +2109,7 @@ func (m *MsgSubmitClientMisbehaviour) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Evidence", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Misbehaviour", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -2136,10 +2136,10 @@ func (m *MsgSubmitClientMisbehaviour) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Evidence == nil { - m.Evidence = &Evidence{} + if m.Misbehaviour == nil { + m.Misbehaviour = &Misbehaviour{} } - if err := m.Evidence.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Misbehaviour.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/ibc/spec/01_concepts.md b/x/ibc/spec/01_concepts.md index 253a5dcb7d..b710eaa92a 100644 --- a/x/ibc/spec/01_concepts.md +++ b/x/ibc/spec/01_concepts.md @@ -7,6 +7,28 @@ order: 1 > NOTE: if you are not familiar with the IBC terminology and concepts, please read this [document](https://github.com/cosmos/ics/blob/master/ibc/1_IBC_TERMINOLOGY.md) as prerequisite reading. +## Client Misbehaviour + +IBC clients must freeze when the counterparty chain becomes malicious and +takes actions that could fool the light client into accepting invalid state +transitions. Thus, relayers are able to submit Misbehaviour proofs that prove +that a counterparty chain has signed two Headers for the same height. This +constitutes misbehaviour as the IBC client could have accepted either header +as valid. Upon verifying the misbehaviour the IBC client must freeze at that +height so that any proof verifications for the frozen height or later fail. + +Note, there is a difference between the chain-level Misbehaviour that IBC is +concerned with and the validator-level Evidence that Tendermint is concerned +with. Tendermint must be able to detect, submit, and punish any evidence of +individual validators breaking the Tendermint consensus protocol and attempting +to mount an attack. IBC clients must only act when an attack is successful +and the chain has successfully forked. In this case, valid Headers submitted +to the IBC client can no longer be trusted and the client must freeze. + +Governance may then choose to override a frozen client and provide the correct, +canonical Header so that the client can continue operating after the Misbehaviour +submission. + ## Connection Version Negotation During the handshake procedure for connections a version string is agreed diff --git a/x/ibc/testing/solomachine.go b/x/ibc/testing/solomachine.go index 6a6a8cd291..94a258a7ef 100644 --- a/x/ibc/testing/solomachine.go +++ b/x/ibc/testing/solomachine.go @@ -80,9 +80,9 @@ func (solo *Solomachine) CreateHeader() *solomachinetypes.Header { return header } -// CreateEvidence constructs testing evidence for the solo machine client +// CreateMisbehaviour constructs testing misbehaviour for the solo machine client // by signing over two different data bytes at the same sequence. -func (solo *Solomachine) CreateEvidence() *solomachinetypes.Evidence { +func (solo *Solomachine) CreateMisbehaviour() *solomachinetypes.Misbehaviour { dataOne := []byte("DATA ONE") dataTwo := []byte("DATA TWO") @@ -102,7 +102,7 @@ func (solo *Solomachine) CreateEvidence() *solomachinetypes.Evidence { Data: dataTwo, } - return &solomachinetypes.Evidence{ + return &solomachinetypes.Misbehaviour{ ClientId: solo.ClientID, Sequence: solo.Sequence, SignatureOne: &signatureOne,