diff --git a/baseapp/abci.go b/baseapp/abci.go index d988ead0fcf4..b46afd6c73ef 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -379,9 +379,17 @@ func (app *BaseApp) snapshot(height int64) { // Query implements the ABCI interface. It delegates to CommitMultiStore if it // implements Queryable. -func (app *BaseApp) Query(req abci.RequestQuery) abci.ResponseQuery { +func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { defer telemetry.MeasureSince(time.Now(), "abci", "query") + // Add panic recovery for all queries. + // ref: https://github.com/cosmos/cosmos-sdk/pull/8039 + defer func() { + if r := recover(); r != nil { + res = sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r)) + } + }() + // when a client did not provide a query height, manually inject the latest if req.Height == 0 { req.Height = app.LastBlockHeight() diff --git a/baseapp/grpcserver.go b/baseapp/grpcserver.go index 74e8b8a21cac..a4342e0b8955 100644 --- a/baseapp/grpcserver.go +++ b/baseapp/grpcserver.go @@ -5,6 +5,8 @@ import ( "strconv" gogogrpc "github.com/gogo/protobuf/grpc" + grpcmiddleware "github.com/grpc-ecosystem/go-grpc-middleware" + grpcrecovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" @@ -74,7 +76,10 @@ func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) { newMethods[i] = grpc.MethodDesc{ MethodName: method.MethodName, Handler: func(srv interface{}, ctx context.Context, dec func(interface{}) error, _ grpc.UnaryServerInterceptor) (interface{}, error) { - return methodHandler(srv, ctx, dec, interceptor) + return methodHandler(srv, ctx, dec, grpcmiddleware.ChainUnaryServer( + grpcrecovery.UnaryServerInterceptor(), + interceptor, + )) }, } } diff --git a/types/query/query.pb.go b/client/grpc/tmservice/query.pb.go similarity index 93% rename from types/query/query.pb.go rename to client/grpc/tmservice/query.pb.go index c04a6bde32b6..c08d33dc2d4a 100644 --- a/types/query/query.pb.go +++ b/client/grpc/tmservice/query.pb.go @@ -1,11 +1,12 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: cosmos/base/tendermint/v1beta1/query.proto -package query +package tmservice import ( context "context" fmt "fmt" + query "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -35,7 +36,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type GetValidatorSetByHeightRequest struct { Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` // pagination defines an pagination for the request. - Pagination *PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (m *GetValidatorSetByHeightRequest) Reset() { *m = GetValidatorSetByHeightRequest{} } @@ -78,7 +79,7 @@ func (m *GetValidatorSetByHeightRequest) GetHeight() int64 { return 0 } -func (m *GetValidatorSetByHeightRequest) GetPagination() *PageRequest { +func (m *GetValidatorSetByHeightRequest) GetPagination() *query.PageRequest { if m != nil { return m.Pagination } @@ -90,7 +91,7 @@ type GetValidatorSetByHeightResponse struct { BlockHeight int64 `protobuf:"varint,1,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"` Validators []*Validator `protobuf:"bytes,2,rep,name=validators,proto3" json:"validators,omitempty"` // pagination defines an pagination for the response. - Pagination *PageResponse `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` + Pagination *query.PageResponse `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (m *GetValidatorSetByHeightResponse) Reset() { *m = GetValidatorSetByHeightResponse{} } @@ -140,7 +141,7 @@ func (m *GetValidatorSetByHeightResponse) GetValidators() []*Validator { return nil } -func (m *GetValidatorSetByHeightResponse) GetPagination() *PageResponse { +func (m *GetValidatorSetByHeightResponse) GetPagination() *query.PageResponse { if m != nil { return m.Pagination } @@ -150,7 +151,7 @@ func (m *GetValidatorSetByHeightResponse) GetPagination() *PageResponse { // GetLatestValidatorSetRequest is the request type for the Query/GetValidatorSetByHeight RPC method. type GetLatestValidatorSetRequest struct { // pagination defines an pagination for the request. - Pagination *PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (m *GetLatestValidatorSetRequest) Reset() { *m = GetLatestValidatorSetRequest{} } @@ -186,7 +187,7 @@ func (m *GetLatestValidatorSetRequest) XXX_DiscardUnknown() { var xxx_messageInfo_GetLatestValidatorSetRequest proto.InternalMessageInfo -func (m *GetLatestValidatorSetRequest) GetPagination() *PageRequest { +func (m *GetLatestValidatorSetRequest) GetPagination() *query.PageRequest { if m != nil { return m.Pagination } @@ -198,7 +199,7 @@ type GetLatestValidatorSetResponse struct { BlockHeight int64 `protobuf:"varint,1,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"` Validators []*Validator `protobuf:"bytes,2,rep,name=validators,proto3" json:"validators,omitempty"` // pagination defines an pagination for the response. - Pagination *PageResponse `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` + Pagination *query.PageResponse `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (m *GetLatestValidatorSetResponse) Reset() { *m = GetLatestValidatorSetResponse{} } @@ -248,7 +249,7 @@ func (m *GetLatestValidatorSetResponse) GetValidators() []*Validator { return nil } -func (m *GetLatestValidatorSetResponse) GetPagination() *PageResponse { +func (m *GetLatestValidatorSetResponse) GetPagination() *query.PageResponse { if m != nil { return m.Pagination } @@ -783,7 +784,7 @@ type Module struct { Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` // module version Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` - //checksum + // checksum Sum string `protobuf:"bytes,3,opt,name=sum,proto3" json:"sum,omitempty"` } @@ -864,72 +865,72 @@ func init() { } var fileDescriptor_40c93fb3ef485c5d = []byte{ - // 1031 bytes of a gzipped FileDescriptorProto + // 1040 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x56, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0xc6, 0x6d, 0x1c, 0x3f, 0x57, 0x90, 0x4c, 0x4a, 0xb3, 0xb5, 0x52, 0x37, 0xec, 0xa1, - 0x4d, 0x88, 0xb2, 0x2b, 0x3b, 0x84, 0x82, 0xf8, 0x27, 0x85, 0x40, 0x1a, 0x15, 0xaa, 0x68, 0x83, - 0x38, 0x20, 0xa4, 0xd5, 0xd8, 0x3b, 0xd9, 0x8c, 0x62, 0xef, 0x4c, 0x77, 0xc6, 0x41, 0x16, 0xaa, - 0x40, 0xfd, 0x00, 0x08, 0x89, 0xaf, 0xc0, 0x85, 0x2f, 0xc0, 0x11, 0x71, 0xe4, 0x46, 0x25, 0x24, - 0xe8, 0x11, 0x25, 0x7c, 0x0a, 0x4e, 0x68, 0x67, 0x66, 0xed, 0xdd, 0x26, 0xa9, 0xed, 0x1c, 0x90, - 0x38, 0x79, 0xf6, 0xbd, 0xf7, 0x7b, 0xf3, 0xfb, 0xbd, 0x79, 0x33, 0x7e, 0xf0, 0x5a, 0x9b, 0x89, - 0x2e, 0x13, 0x5e, 0x0b, 0x0b, 0xe2, 0x49, 0x12, 0x87, 0x24, 0xe9, 0xd2, 0x58, 0x7a, 0xc7, 0x8d, - 0x16, 0x91, 0xb8, 0xe1, 0x3d, 0xea, 0x91, 0xa4, 0xef, 0xf2, 0x84, 0x49, 0x86, 0xea, 0x3a, 0xd6, - 0x4d, 0x63, 0xdd, 0x61, 0xac, 0x6b, 0x62, 0x6b, 0xd7, 0x23, 0x16, 0x31, 0x15, 0xea, 0xa5, 0x2b, - 0x8d, 0xaa, 0x2d, 0x45, 0x8c, 0x45, 0x1d, 0xe2, 0x61, 0x4e, 0x3d, 0x1c, 0xc7, 0x4c, 0x62, 0x49, - 0x59, 0x2c, 0x8c, 0xb7, 0x96, 0xdb, 0x93, 0x37, 0xb9, 0x27, 0xfb, 0x9c, 0x64, 0xbe, 0xa5, 0x9c, - 0x4f, 0xd9, 0xbd, 0x56, 0x87, 0xb5, 0x8f, 0x2e, 0xf4, 0xe6, 0xb1, 0x05, 0x5d, 0x4a, 0xc4, 0x40, - 0x12, 0xc7, 0x11, 0x8d, 0x15, 0x09, 0x1d, 0xeb, 0x7c, 0x63, 0x41, 0x7d, 0x87, 0xc8, 0xcf, 0x70, - 0x87, 0x86, 0x58, 0xb2, 0x64, 0x9f, 0xc8, 0xad, 0xfe, 0x7d, 0x42, 0xa3, 0x43, 0xe9, 0x93, 0x47, - 0x3d, 0x22, 0x24, 0xba, 0x01, 0x33, 0x87, 0xca, 0x60, 0x5b, 0xcb, 0xd6, 0x4a, 0xc9, 0x37, 0x5f, - 0xe8, 0x23, 0x80, 0x61, 0x3a, 0x7b, 0x7a, 0xd9, 0x5a, 0xa9, 0x36, 0xef, 0xb8, 0xf9, 0x3a, 0xe9, - 0x02, 0x9a, 0xbd, 0xdd, 0x3d, 0x1c, 0x11, 0x93, 0xd3, 0xcf, 0x21, 0x9d, 0x67, 0x16, 0xdc, 0xbe, - 0x90, 0x82, 0xe0, 0x2c, 0x16, 0x04, 0xbd, 0x0a, 0xd7, 0x94, 0xfe, 0xa0, 0xc0, 0xa4, 0xaa, 0x6c, - 0x3a, 0x14, 0xed, 0x02, 0x1c, 0x67, 0x29, 0x84, 0x3d, 0xbd, 0x5c, 0x5a, 0xa9, 0x36, 0x57, 0xdd, - 0x17, 0x1f, 0x9b, 0x3b, 0xd8, 0xd4, 0xcf, 0x81, 0xd1, 0x4e, 0x41, 0x59, 0x49, 0x29, 0xbb, 0x3b, - 0x52, 0x99, 0xa6, 0x5a, 0x90, 0x76, 0x00, 0x4b, 0x3b, 0x44, 0x7e, 0x8c, 0x25, 0x11, 0x05, 0x7d, - 0x59, 0x69, 0x8b, 0x25, 0xb4, 0x2e, 0x5d, 0xc2, 0x3f, 0x2c, 0xb8, 0x75, 0xc1, 0x46, 0xff, 0xef, - 0x02, 0x7e, 0x6b, 0x41, 0x65, 0xb0, 0x05, 0xb2, 0xa1, 0x8c, 0xc3, 0x30, 0x21, 0x42, 0x28, 0xfe, - 0xd7, 0xfc, 0xec, 0x13, 0x2d, 0x42, 0x99, 0xf7, 0x5a, 0xc1, 0x11, 0xe9, 0xab, 0x46, 0xac, 0xf8, - 0x33, 0xbc, 0xd7, 0x7a, 0x40, 0xfa, 0xa9, 0xee, 0x63, 0x26, 0x69, 0x1c, 0x05, 0x9c, 0x7d, 0x49, - 0x12, 0xc5, 0xa5, 0xe4, 0x57, 0xb5, 0x6d, 0x2f, 0x35, 0xa1, 0x35, 0x98, 0xe7, 0x09, 0xe3, 0x4c, - 0x90, 0x24, 0xe0, 0x09, 0x65, 0x09, 0x95, 0x7d, 0xfb, 0x8a, 0x8a, 0x9b, 0xcb, 0x1c, 0x7b, 0xc6, - 0xee, 0x34, 0x60, 0x71, 0x87, 0xc8, 0xad, 0xb4, 0x6c, 0x63, 0xde, 0x13, 0xe7, 0x6b, 0xb0, 0xcf, - 0x42, 0xcc, 0xb1, 0xbc, 0x0e, 0xb3, 0xfa, 0x58, 0x68, 0x68, 0x8e, 0xff, 0x66, 0xbe, 0xca, 0xfa, - 0x56, 0x2b, 0xe8, 0xee, 0xb6, 0x5f, 0x56, 0xa1, 0xbb, 0x21, 0x5a, 0x87, 0xab, 0x6a, 0x69, 0x2e, - 0xdd, 0xe2, 0x05, 0x10, 0x5f, 0x47, 0x39, 0x8b, 0xf0, 0xca, 0xa0, 0x39, 0xb4, 0x43, 0x33, 0x76, - 0x1e, 0xc3, 0x8d, 0xe7, 0x1d, 0xff, 0x25, 0xaf, 0x05, 0x98, 0xdf, 0x21, 0x72, 0xbf, 0x1f, 0xb7, - 0x69, 0x1c, 0x65, 0x9c, 0x5c, 0x40, 0x79, 0xa3, 0xe1, 0x63, 0x43, 0x59, 0x68, 0x93, 0xa2, 0x33, - 0xeb, 0x67, 0x9f, 0xce, 0x75, 0x15, 0xff, 0x90, 0x85, 0x64, 0x37, 0x3e, 0x60, 0x59, 0x96, 0x5f, - 0x2c, 0x58, 0x28, 0x98, 0x4d, 0x9e, 0x07, 0x30, 0x1f, 0x92, 0x03, 0xdc, 0xeb, 0xc8, 0x20, 0x66, - 0x21, 0x09, 0x68, 0x7c, 0xc0, 0x8c, 0xc0, 0xdb, 0x79, 0xb6, 0xbc, 0xc9, 0xdd, 0x6d, 0x1d, 0x38, - 0xc8, 0xf1, 0x72, 0x58, 0x34, 0xa0, 0x2f, 0x60, 0x01, 0x73, 0xde, 0xa1, 0x6d, 0xd5, 0xab, 0xc1, - 0x31, 0x49, 0xc4, 0xf0, 0x25, 0x5c, 0x1b, 0x79, 0x73, 0x74, 0xb8, 0x4a, 0x8d, 0x72, 0x79, 0x8c, - 0xdd, 0xf9, 0xc7, 0x82, 0x6a, 0x2e, 0x06, 0x21, 0xb8, 0x12, 0xe3, 0x2e, 0x51, 0x6c, 0x2b, 0xbe, - 0x5a, 0xa3, 0x9b, 0x30, 0x8b, 0x39, 0x0f, 0x94, 0x5d, 0xf7, 0x7d, 0x19, 0x73, 0xfe, 0x30, 0x75, - 0xd9, 0x50, 0xce, 0x08, 0x95, 0xb4, 0xc7, 0x7c, 0xa2, 0x5b, 0x00, 0x11, 0x95, 0x41, 0x9b, 0x75, - 0xbb, 0x54, 0xaa, 0x46, 0xaf, 0xf8, 0x95, 0x88, 0xca, 0x0f, 0x94, 0x21, 0x75, 0xb7, 0x7a, 0xb4, - 0x13, 0x06, 0x12, 0x47, 0xc2, 0xbe, 0xaa, 0xdd, 0xca, 0xf2, 0x29, 0x8e, 0x84, 0x42, 0xb3, 0x81, - 0xd6, 0x19, 0x83, 0x66, 0x86, 0x29, 0xfa, 0x30, 0x43, 0x87, 0x84, 0x0b, 0xbb, 0xac, 0x1e, 0x91, - 0x3b, 0xa3, 0x4a, 0xf1, 0x09, 0x0b, 0x7b, 0x1d, 0x62, 0x76, 0xd9, 0x26, 0x5c, 0x38, 0xf7, 0x61, - 0x46, 0x1b, 0x53, 0xd9, 0x1c, 0xcb, 0xc3, 0x4c, 0x76, 0xba, 0xce, 0x6b, 0x9b, 0x2e, 0x6a, 0x9b, - 0x83, 0x92, 0xe8, 0x75, 0x8d, 0xe2, 0x74, 0xd9, 0x7c, 0x52, 0x81, 0xf2, 0x3e, 0x49, 0x8e, 0x69, - 0x9b, 0xa0, 0x1f, 0x2d, 0xa8, 0xe6, 0xba, 0x02, 0x35, 0x47, 0x11, 0x3b, 0xdb, 0x59, 0xb5, 0x8d, - 0x89, 0x30, 0xba, 0xed, 0x9c, 0xc6, 0x93, 0xdf, 0xff, 0xfe, 0x7e, 0x7a, 0x0d, 0xad, 0x7a, 0x23, - 0x46, 0x8e, 0x41, 0x53, 0xa2, 0x1f, 0x2c, 0x80, 0xe1, 0x45, 0x40, 0x8d, 0x31, 0xb6, 0x2d, 0xde, - 0xa4, 0x5a, 0x73, 0x12, 0x88, 0x21, 0xea, 0x29, 0xa2, 0xab, 0xe8, 0xee, 0x28, 0xa2, 0xe6, 0xfa, - 0xa1, 0x9f, 0x2c, 0x78, 0xa9, 0xf8, 0x86, 0xa0, 0xcd, 0x31, 0xf6, 0x3d, 0xfb, 0x18, 0xd5, 0xde, - 0x98, 0x14, 0x66, 0x28, 0x6f, 0x2a, 0xca, 0x1e, 0x5a, 0x1f, 0x45, 0x59, 0x3d, 0x3a, 0xc2, 0xeb, - 0xa8, 0x1c, 0xe8, 0x67, 0x0b, 0xe6, 0x9e, 0x7f, 0x96, 0xd1, 0xbd, 0x31, 0x38, 0x9c, 0xf7, 0xf6, - 0xd7, 0xde, 0x9c, 0x1c, 0x68, 0xe8, 0xdf, 0x53, 0xf4, 0x1b, 0xc8, 0x1b, 0x93, 0xfe, 0x57, 0xfa, - 0x5f, 0xe5, 0x31, 0xfa, 0xcd, 0xca, 0x3d, 0xeb, 0xf9, 0xff, 0x7c, 0xf4, 0xce, 0xd8, 0x95, 0x3c, - 0x67, 0x26, 0xa9, 0xbd, 0x7b, 0x49, 0xb4, 0xd1, 0xf3, 0x96, 0xd2, 0xb3, 0x81, 0x1a, 0xa3, 0xf4, - 0x0c, 0xc7, 0x85, 0xec, 0x48, 0xfe, 0xb4, 0xd4, 0x9f, 0xeb, 0x79, 0x83, 0x20, 0x7a, 0x6f, 0x0c, - 0x56, 0x2f, 0x18, 0x62, 0x6b, 0xef, 0x5f, 0x1a, 0x6f, 0x74, 0xbd, 0xad, 0x74, 0x6d, 0xa2, 0x8d, - 0x09, 0x74, 0x65, 0x67, 0xb5, 0xb5, 0xf5, 0xeb, 0x49, 0xdd, 0x7a, 0x7a, 0x52, 0xb7, 0xfe, 0x3a, - 0xa9, 0x5b, 0xdf, 0x9d, 0xd6, 0xa7, 0x9e, 0x9e, 0xd6, 0xa7, 0x9e, 0x9d, 0xd6, 0xa7, 0x3e, 0x5f, - 0x89, 0xa8, 0x3c, 0xec, 0xb5, 0xdc, 0x36, 0xeb, 0x66, 0x89, 0xf5, 0xcf, 0xba, 0x08, 0x8f, 0xcc, - 0x6c, 0xaf, 0x66, 0xa5, 0xd6, 0x8c, 0x1a, 0xd8, 0x37, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x20, - 0x61, 0xbc, 0x54, 0xb6, 0x0c, 0x00, 0x00, + 0x14, 0xcf, 0xc6, 0xad, 0x1d, 0x3f, 0x57, 0x90, 0x4c, 0x4a, 0xb3, 0xb5, 0x52, 0x37, 0xec, 0xa1, + 0x4d, 0x88, 0xb2, 0x2b, 0x3b, 0x84, 0x82, 0xf8, 0x27, 0x85, 0x80, 0x1b, 0xb5, 0x54, 0xd1, 0x06, + 0x71, 0x40, 0x48, 0xab, 0xb5, 0x77, 0xb2, 0x19, 0xc5, 0xde, 0x99, 0xee, 0x8c, 0x8d, 0x2c, 0x54, + 0x81, 0xfa, 0x01, 0x10, 0x12, 0x5f, 0x81, 0x0b, 0x5f, 0x80, 0x23, 0xe2, 0xc8, 0x8d, 0x4a, 0x48, + 0xd0, 0x23, 0x4a, 0xf8, 0x14, 0x9c, 0xd0, 0xce, 0xcc, 0xda, 0xbb, 0xcd, 0x1f, 0xdb, 0x39, 0x20, + 0xf5, 0xe4, 0xd9, 0xf7, 0xde, 0xef, 0xcd, 0xef, 0xf7, 0xe6, 0xcd, 0xf3, 0xc0, 0x1b, 0x6d, 0xca, + 0xbb, 0x94, 0x3b, 0x2d, 0x9f, 0x63, 0x47, 0xe0, 0x28, 0xc0, 0x71, 0x97, 0x44, 0xc2, 0xe9, 0xd7, + 0x5b, 0x58, 0xf8, 0x75, 0xe7, 0x71, 0x0f, 0xc7, 0x03, 0x9b, 0xc5, 0x54, 0x50, 0x54, 0x53, 0xb1, + 0x76, 0x12, 0x6b, 0x8f, 0x62, 0x6d, 0x1d, 0x5b, 0xbd, 0x1e, 0xd2, 0x90, 0xca, 0x50, 0x27, 0x59, + 0x29, 0x54, 0x75, 0x39, 0xa4, 0x34, 0xec, 0x60, 0xc7, 0x67, 0xc4, 0xf1, 0xa3, 0x88, 0x0a, 0x5f, + 0x10, 0x1a, 0x71, 0xed, 0xad, 0x66, 0xf6, 0x64, 0x0d, 0xe6, 0x88, 0x01, 0xc3, 0xa9, 0x6f, 0x39, + 0xe3, 0x93, 0x76, 0xa7, 0xd5, 0xa1, 0xed, 0xa3, 0x73, 0xbd, 0x59, 0x6c, 0x4e, 0x97, 0x14, 0x31, + 0x94, 0xc4, 0xfc, 0x90, 0x44, 0x92, 0x84, 0x8a, 0xb5, 0xbe, 0x35, 0xa0, 0xd6, 0xc4, 0xe2, 0x73, + 0xbf, 0x43, 0x02, 0x5f, 0xd0, 0x78, 0x1f, 0x8b, 0xed, 0xc1, 0x7d, 0x4c, 0xc2, 0x43, 0xe1, 0xe2, + 0xc7, 0x3d, 0xcc, 0x05, 0xba, 0x01, 0xc5, 0x43, 0x69, 0x30, 0x8d, 0x15, 0x63, 0xb5, 0xe0, 0xea, + 0x2f, 0xf4, 0x09, 0xc0, 0x28, 0x9d, 0x39, 0xbb, 0x62, 0xac, 0x56, 0x1a, 0x77, 0xec, 0x6c, 0x9d, + 0x54, 0x01, 0xf5, 0xde, 0xf6, 0x9e, 0x1f, 0x62, 0x9d, 0xd3, 0xcd, 0x20, 0xad, 0xe7, 0x06, 0xdc, + 0x3e, 0x97, 0x02, 0x67, 0x34, 0xe2, 0x18, 0xbd, 0x0e, 0xd7, 0xa4, 0x7e, 0x2f, 0xc7, 0xa4, 0x22, + 0x6d, 0x2a, 0x14, 0xed, 0x02, 0xf4, 0xd3, 0x14, 0xdc, 0x9c, 0x5d, 0x29, 0xac, 0x56, 0x1a, 0x6b, + 0xf6, 0xc5, 0xc7, 0x66, 0x0f, 0x37, 0x75, 0x33, 0x60, 0xd4, 0xcc, 0x29, 0x2b, 0x48, 0x65, 0x77, + 0xc7, 0x2a, 0x53, 0x54, 0x73, 0xd2, 0x0e, 0x60, 0xb9, 0x89, 0xc5, 0x43, 0x5f, 0x60, 0x9e, 0xd3, + 0x97, 0x96, 0x36, 0x5f, 0x42, 0xe3, 0xd2, 0x25, 0xfc, 0xd3, 0x80, 0x5b, 0xe7, 0x6c, 0xf4, 0x72, + 0x17, 0xf0, 0x3b, 0x03, 0xca, 0xc3, 0x2d, 0x90, 0x09, 0x25, 0x3f, 0x08, 0x62, 0xcc, 0xb9, 0xe4, + 0x7f, 0xcd, 0x4d, 0x3f, 0xd1, 0x12, 0x94, 0x58, 0xaf, 0xe5, 0x1d, 0xe1, 0x81, 0x6c, 0xc4, 0xb2, + 0x5b, 0x64, 0xbd, 0xd6, 0x03, 0x3c, 0x48, 0x74, 0xf7, 0xa9, 0x20, 0x51, 0xe8, 0x31, 0xfa, 0x15, + 0x8e, 0x25, 0x97, 0x82, 0x5b, 0x51, 0xb6, 0xbd, 0xc4, 0x84, 0xd6, 0x61, 0x81, 0xc5, 0x94, 0x51, + 0x8e, 0x63, 0x8f, 0xc5, 0x84, 0xc6, 0x44, 0x0c, 0xcc, 0x2b, 0x32, 0x6e, 0x3e, 0x75, 0xec, 0x69, + 0xbb, 0x55, 0x87, 0xa5, 0x26, 0x16, 0xdb, 0x49, 0xd9, 0x26, 0xbc, 0x27, 0xd6, 0x37, 0x60, 0x9e, + 0x86, 0xe8, 0x63, 0x79, 0x13, 0xe6, 0xd4, 0xb1, 0x90, 0x40, 0x1f, 0xff, 0xcd, 0x6c, 0x95, 0xd5, + 0xad, 0x96, 0xd0, 0xdd, 0x1d, 0xb7, 0x24, 0x43, 0x77, 0x03, 0xb4, 0x01, 0x57, 0xe5, 0x52, 0x5f, + 0xba, 0xa5, 0x73, 0x20, 0xae, 0x8a, 0xb2, 0x96, 0xe0, 0xb5, 0x61, 0x73, 0x28, 0x87, 0x62, 0x6c, + 0x3d, 0x81, 0x1b, 0x2f, 0x3a, 0xfe, 0x4f, 0x5e, 0x8b, 0xb0, 0xd0, 0xc4, 0x62, 0x7f, 0x10, 0xb5, + 0x49, 0x14, 0xa6, 0x9c, 0x6c, 0x40, 0x59, 0xa3, 0xe6, 0x63, 0x42, 0x89, 0x2b, 0x93, 0xa4, 0x33, + 0xe7, 0xa6, 0x9f, 0xd6, 0x75, 0x19, 0xff, 0x88, 0x06, 0x78, 0x37, 0x3a, 0xa0, 0x69, 0x96, 0x5f, + 0x0d, 0x58, 0xcc, 0x99, 0x75, 0x9e, 0x07, 0xb0, 0x10, 0xe0, 0x03, 0xbf, 0xd7, 0x11, 0x5e, 0x44, + 0x03, 0xec, 0x91, 0xe8, 0x80, 0x6a, 0x81, 0xb7, 0xb3, 0x6c, 0x59, 0x83, 0xd9, 0x3b, 0x2a, 0x70, + 0x98, 0xe3, 0xd5, 0x20, 0x6f, 0x40, 0x5f, 0xc2, 0xa2, 0xcf, 0x58, 0x87, 0xb4, 0x65, 0xaf, 0x7a, + 0x7d, 0x1c, 0xf3, 0xd1, 0x24, 0x5c, 0x1f, 0x7b, 0x73, 0x54, 0xb8, 0x4c, 0x8d, 0x32, 0x79, 0xb4, + 0xdd, 0xfa, 0xd7, 0x80, 0x4a, 0x26, 0x06, 0x21, 0xb8, 0x12, 0xf9, 0x5d, 0x2c, 0xd9, 0x96, 0x5d, + 0xb9, 0x46, 0x37, 0x61, 0xce, 0x67, 0xcc, 0x93, 0x76, 0xd5, 0xf7, 0x25, 0x9f, 0xb1, 0x47, 0x89, + 0xcb, 0x84, 0x52, 0x4a, 0xa8, 0xa0, 0x3c, 0xfa, 0x13, 0xdd, 0x02, 0x08, 0x89, 0xf0, 0xda, 0xb4, + 0xdb, 0x25, 0x42, 0x36, 0x7a, 0xd9, 0x2d, 0x87, 0x44, 0x7c, 0x24, 0x0d, 0x89, 0xbb, 0xd5, 0x23, + 0x9d, 0xc0, 0x13, 0x7e, 0xc8, 0xcd, 0xab, 0xca, 0x2d, 0x2d, 0x9f, 0xf9, 0x21, 0x97, 0x68, 0x3a, + 0xd4, 0x5a, 0xd4, 0x68, 0xaa, 0x99, 0xa2, 0x8f, 0x53, 0x74, 0x80, 0x19, 0x37, 0x4b, 0x72, 0x88, + 0xdc, 0x19, 0x57, 0x8a, 0x4f, 0x69, 0xd0, 0xeb, 0x60, 0xbd, 0xcb, 0x0e, 0x66, 0xdc, 0xba, 0x0f, + 0x45, 0x65, 0x4c, 0x64, 0x33, 0x5f, 0x1c, 0xa6, 0xb2, 0x93, 0x75, 0x56, 0xdb, 0x6c, 0x5e, 0xdb, + 0x3c, 0x14, 0x78, 0xaf, 0xab, 0x15, 0x27, 0xcb, 0xc6, 0xd3, 0x32, 0x94, 0xf6, 0x71, 0xdc, 0x27, + 0x6d, 0x8c, 0x7e, 0x32, 0xa0, 0x92, 0xe9, 0x0a, 0xd4, 0x18, 0x47, 0xec, 0x74, 0x67, 0x55, 0x37, + 0xa7, 0xc2, 0xa8, 0xb6, 0xb3, 0xea, 0x4f, 0xff, 0xf8, 0xe7, 0x87, 0xd9, 0x75, 0xb4, 0xe6, 0x8c, + 0x79, 0x72, 0x0c, 0x9b, 0x12, 0xfd, 0x68, 0x00, 0x8c, 0x2e, 0x02, 0xaa, 0x4f, 0xb0, 0x6d, 0xfe, + 0x26, 0x55, 0x1b, 0xd3, 0x40, 0x34, 0x51, 0x47, 0x12, 0x5d, 0x43, 0x77, 0xc7, 0x11, 0xd5, 0xd7, + 0x0f, 0xfd, 0x6c, 0xc0, 0x2b, 0xf9, 0x19, 0x82, 0xb6, 0x26, 0xd8, 0xf7, 0xf4, 0x30, 0xaa, 0xbe, + 0x35, 0x2d, 0x4c, 0x53, 0xde, 0x92, 0x94, 0x1d, 0xb4, 0x31, 0x8e, 0xb2, 0x1c, 0x3a, 0xdc, 0xe9, + 0xc8, 0x1c, 0xe8, 0x17, 0x03, 0xe6, 0x5f, 0x1c, 0xcb, 0xe8, 0xde, 0x04, 0x1c, 0xce, 0x9a, 0xfd, + 0xd5, 0xb7, 0xa7, 0x07, 0x6a, 0xfa, 0xf7, 0x24, 0xfd, 0x3a, 0x72, 0x26, 0xa4, 0xff, 0xb5, 0xfa, + 0x57, 0x79, 0x82, 0x7e, 0x37, 0x32, 0x63, 0x3d, 0xfb, 0x9f, 0x8f, 0xde, 0x9b, 0xb8, 0x92, 0x67, + 0xbc, 0x49, 0xaa, 0xef, 0x5f, 0x12, 0xad, 0xf5, 0xbc, 0x23, 0xf5, 0x6c, 0xa2, 0xfa, 0x38, 0x3d, + 0xa3, 0xe7, 0x42, 0x7a, 0x24, 0x7f, 0x19, 0xf2, 0xcf, 0xf5, 0xac, 0x87, 0x20, 0xfa, 0x60, 0x02, + 0x56, 0x17, 0x3c, 0x62, 0xab, 0x1f, 0x5e, 0x1a, 0xaf, 0x75, 0xbd, 0x2b, 0x75, 0x6d, 0xa1, 0xcd, + 0x29, 0x74, 0xa5, 0x67, 0xb5, 0xfd, 0xf0, 0xb7, 0xe3, 0x9a, 0xf1, 0xec, 0xb8, 0x66, 0xfc, 0x7d, + 0x5c, 0x33, 0xbe, 0x3f, 0xa9, 0xcd, 0x3c, 0x3b, 0xa9, 0xcd, 0x3c, 0x3f, 0xa9, 0xcd, 0x7c, 0xd1, + 0x08, 0x89, 0x38, 0xec, 0xb5, 0xec, 0x36, 0xed, 0xa6, 0x89, 0xd5, 0xcf, 0x06, 0x0f, 0x8e, 0x9c, + 0x76, 0x87, 0xe0, 0x48, 0x38, 0x61, 0xcc, 0xda, 0x8e, 0xe8, 0x72, 0x35, 0xc6, 0x5a, 0x45, 0xf9, + 0x74, 0xdf, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x82, 0x6b, 0xb0, 0xbd, 0xc0, 0x0c, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2181,7 +2182,7 @@ func (m *GetValidatorSetByHeightRequest) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.Pagination == nil { - m.Pagination = &PageRequest{} + m.Pagination = &query.PageRequest{} } if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -2323,7 +2324,7 @@ func (m *GetValidatorSetByHeightResponse) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.Pagination == nil { - m.Pagination = &PageResponse{} + m.Pagination = &query.PageResponse{} } if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -2412,7 +2413,7 @@ func (m *GetLatestValidatorSetRequest) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.Pagination == nil { - m.Pagination = &PageRequest{} + m.Pagination = &query.PageRequest{} } if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -2554,7 +2555,7 @@ func (m *GetLatestValidatorSetResponse) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.Pagination == nil { - m.Pagination = &PageResponse{} + m.Pagination = &query.PageResponse{} } if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err diff --git a/types/query/query.pb.gw.go b/client/grpc/tmservice/query.pb.gw.go similarity index 99% rename from types/query/query.pb.gw.go rename to client/grpc/tmservice/query.pb.gw.go index 01b943030d1d..1fcd85268212 100644 --- a/types/query/query.pb.gw.go +++ b/client/grpc/tmservice/query.pb.gw.go @@ -2,11 +2,11 @@ // source: cosmos/base/tendermint/v1beta1/query.proto /* -Package query is a reverse proxy. +Package tmservice is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ -package query +package tmservice import ( "context" diff --git a/client/grpc/tmservice/service.go b/client/grpc/tmservice/service.go index b1198eb67331..b4d9f8c95261 100644 --- a/client/grpc/tmservice/service.go +++ b/client/grpc/tmservice/service.go @@ -21,10 +21,10 @@ type queryServer struct { interfaceRegistry codectypes.InterfaceRegistry } -var _ qtypes.ServiceServer = queryServer{} +var _ ServiceServer = queryServer{} // NewQueryServer creates a new tendermint query server. -func NewQueryServer(clientCtx client.Context, interfaceRegistry codectypes.InterfaceRegistry) qtypes.ServiceServer { +func NewQueryServer(clientCtx client.Context, interfaceRegistry codectypes.InterfaceRegistry) ServiceServer { return queryServer{ clientCtx: clientCtx, interfaceRegistry: interfaceRegistry, @@ -32,18 +32,18 @@ func NewQueryServer(clientCtx client.Context, interfaceRegistry codectypes.Inter } // GetSyncing implements ServiceServer.GetSyncing -func (s queryServer) GetSyncing(_ context.Context, _ *qtypes.GetSyncingRequest) (*qtypes.GetSyncingResponse, error) { +func (s queryServer) GetSyncing(_ context.Context, _ *GetSyncingRequest) (*GetSyncingResponse, error) { status, err := getNodeStatus(s.clientCtx) if err != nil { return nil, err } - return &qtypes.GetSyncingResponse{ + return &GetSyncingResponse{ Syncing: status.SyncInfo.CatchingUp, }, nil } // GetLatestBlock implements ServiceServer.GetLatestBlock -func (s queryServer) GetLatestBlock(context.Context, *qtypes.GetLatestBlockRequest) (*qtypes.GetLatestBlockResponse, error) { +func (s queryServer) GetLatestBlock(context.Context, *GetLatestBlockRequest) (*GetLatestBlockResponse, error) { status, err := getBlock(s.clientCtx, nil) if err != nil { return nil, err @@ -55,14 +55,14 @@ func (s queryServer) GetLatestBlock(context.Context, *qtypes.GetLatestBlockReque return nil, err } - return &qtypes.GetLatestBlockResponse{ + return &GetLatestBlockResponse{ BlockId: &protoBlockID, Block: protoBlock, }, nil } // GetBlockByHeight implements ServiceServer.GetBlockByHeight -func (s queryServer) GetBlockByHeight(_ context.Context, req *qtypes.GetBlockByHeightRequest) (*qtypes.GetBlockByHeightResponse, error) { +func (s queryServer) GetBlockByHeight(_ context.Context, req *GetBlockByHeightRequest) (*GetBlockByHeightResponse, error) { chainHeight, err := rpc.GetChainHeight(s.clientCtx) if err != nil { return nil, err @@ -81,14 +81,14 @@ func (s queryServer) GetBlockByHeight(_ context.Context, req *qtypes.GetBlockByH if err != nil { return nil, err } - return &qtypes.GetBlockByHeightResponse{ + return &GetBlockByHeightResponse{ BlockId: &protoBlockID, Block: protoBlock, }, nil } // GetLatestValidatorSet implements ServiceServer.GetLatestValidatorSet -func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *qtypes.GetLatestValidatorSetRequest) (*qtypes.GetLatestValidatorSetResponse, error) { +func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *GetLatestValidatorSetRequest) (*GetLatestValidatorSetResponse, error) { page, limit, err := qtypes.ParsePagination(req.Pagination) if err != nil { return nil, err @@ -99,13 +99,13 @@ func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *qtypes.GetL return nil, err } - outputValidatorsRes := &qtypes.GetLatestValidatorSetResponse{ + outputValidatorsRes := &GetLatestValidatorSetResponse{ BlockHeight: validatorsRes.BlockHeight, - Validators: make([]*qtypes.Validator, len(validatorsRes.Validators)), + Validators: make([]*Validator, len(validatorsRes.Validators)), } for i, validator := range validatorsRes.Validators { - outputValidatorsRes.Validators[i] = &qtypes.Validator{ + outputValidatorsRes.Validators[i] = &Validator{ Address: validator.Address, ProposerPriority: validator.ProposerPriority, PubKey: validator.PubKey, @@ -116,7 +116,7 @@ func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *qtypes.GetL } // GetValidatorSetByHeight implements ServiceServer.GetValidatorSetByHeight -func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *qtypes.GetValidatorSetByHeightRequest) (*qtypes.GetValidatorSetByHeightResponse, error) { +func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *GetValidatorSetByHeightRequest) (*GetValidatorSetByHeightResponse, error) { page, limit, err := qtypes.ParsePagination(req.Pagination) if err != nil { return nil, err @@ -136,13 +136,13 @@ func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *qtypes.Ge return nil, err } - outputValidatorsRes := &qtypes.GetValidatorSetByHeightResponse{ + outputValidatorsRes := &GetValidatorSetByHeightResponse{ BlockHeight: validatorsRes.BlockHeight, - Validators: make([]*qtypes.Validator, len(validatorsRes.Validators)), + Validators: make([]*Validator, len(validatorsRes.Validators)), } for i, validator := range validatorsRes.Validators { - outputValidatorsRes.Validators[i] = &qtypes.Validator{ + outputValidatorsRes.Validators[i] = &Validator{ Address: validator.Address, ProposerPriority: validator.ProposerPriority, PubKey: validator.PubKey, @@ -153,7 +153,7 @@ func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *qtypes.Ge } // GetNodeInfo implements ServiceServer.GetNodeInfo -func (s queryServer) GetNodeInfo(ctx context.Context, req *qtypes.GetNodeInfoRequest) (*qtypes.GetNodeInfoResponse, error) { +func (s queryServer) GetNodeInfo(ctx context.Context, req *GetNodeInfoRequest) (*GetNodeInfoResponse, error) { status, err := getNodeStatus(s.clientCtx) if err != nil { return nil, err @@ -162,19 +162,19 @@ func (s queryServer) GetNodeInfo(ctx context.Context, req *qtypes.GetNodeInfoReq protoNodeInfo := status.NodeInfo.ToProto() nodeInfo := version.NewInfo() - deps := make([]*qtypes.Module, len(nodeInfo.BuildDeps)) + deps := make([]*Module, len(nodeInfo.BuildDeps)) for i, dep := range nodeInfo.BuildDeps { - deps[i] = &qtypes.Module{ + deps[i] = &Module{ Path: dep.Path, Sum: dep.Sum, Version: dep.Version, } } - resp := qtypes.GetNodeInfoResponse{ + resp := GetNodeInfoResponse{ DefaultNodeInfo: protoNodeInfo, - ApplicationVersion: &qtypes.VersionInfo{ + ApplicationVersion: &VersionInfo{ AppName: nodeInfo.AppName, Name: nodeInfo.Name, GitCommit: nodeInfo.GitCommit, @@ -193,7 +193,7 @@ func RegisterTendermintService( clientCtx client.Context, interfaceRegistry codectypes.InterfaceRegistry, ) { - qtypes.RegisterServiceServer( + RegisterServiceServer( qrt, NewQueryServer(clientCtx, interfaceRegistry), ) @@ -202,5 +202,5 @@ func RegisterTendermintService( // RegisterGRPCGatewayRoutes mounts the tendermint service's GRPC-gateway routes on the // given Mux. func RegisterGRPCGatewayRoutes(clientConn gogogrpc.ClientConn, mux *runtime.ServeMux) { - qtypes.RegisterServiceHandlerClient(context.Background(), mux, qtypes.NewServiceClient(clientConn)) + RegisterServiceHandlerClient(context.Background(), mux, NewServiceClient(clientConn)) } diff --git a/client/grpc/tmservice/service_test.go b/client/grpc/tmservice/service_test.go index bb145e6e21ca..2210486f4427 100644 --- a/client/grpc/tmservice/service_test.go +++ b/client/grpc/tmservice/service_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/suite" + "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" "github.com/cosmos/cosmos-sdk/testutil/network" qtypes "github.com/cosmos/cosmos-sdk/types/query" "github.com/cosmos/cosmos-sdk/types/rest" @@ -19,7 +20,7 @@ type IntegrationTestSuite struct { cfg network.Config network *network.Network - queryClient qtypes.ServiceClient + queryClient tmservice.ServiceClient } func (s *IntegrationTestSuite) SetupSuite() { @@ -36,7 +37,7 @@ func (s *IntegrationTestSuite) SetupSuite() { _, err := s.network.WaitForHeight(1) s.Require().NoError(err) - s.queryClient = qtypes.NewServiceClient(s.network.Validators[0].ClientCtx) + s.queryClient = tmservice.NewServiceClient(s.network.Validators[0].ClientCtx) } func (s *IntegrationTestSuite) TearDownSuite() { @@ -47,13 +48,13 @@ func (s *IntegrationTestSuite) TearDownSuite() { func (s IntegrationTestSuite) TestQueryNodeInfo() { val := s.network.Validators[0] - res, err := s.queryClient.GetNodeInfo(context.Background(), &qtypes.GetNodeInfoRequest{}) + res, err := s.queryClient.GetNodeInfo(context.Background(), &tmservice.GetNodeInfoRequest{}) s.Require().NoError(err) s.Require().Equal(res.ApplicationVersion.AppName, version.NewInfo().AppName) restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/node_info", val.APIAddress)) s.Require().NoError(err) - var getInfoRes qtypes.GetNodeInfoResponse + var getInfoRes tmservice.GetNodeInfoResponse s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &getInfoRes)) s.Require().Equal(getInfoRes.ApplicationVersion.AppName, version.NewInfo().AppName) } @@ -61,35 +62,35 @@ func (s IntegrationTestSuite) TestQueryNodeInfo() { func (s IntegrationTestSuite) TestQuerySyncing() { val := s.network.Validators[0] - _, err := s.queryClient.GetSyncing(context.Background(), &qtypes.GetSyncingRequest{}) + _, err := s.queryClient.GetSyncing(context.Background(), &tmservice.GetSyncingRequest{}) s.Require().NoError(err) restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/syncing", val.APIAddress)) s.Require().NoError(err) - var syncingRes qtypes.GetSyncingResponse + var syncingRes tmservice.GetSyncingResponse s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &syncingRes)) } func (s IntegrationTestSuite) TestQueryLatestBlock() { val := s.network.Validators[0] - _, err := s.queryClient.GetLatestBlock(context.Background(), &qtypes.GetLatestBlockRequest{}) + _, err := s.queryClient.GetLatestBlock(context.Background(), &tmservice.GetLatestBlockRequest{}) s.Require().NoError(err) restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/blocks/latest", val.APIAddress)) s.Require().NoError(err) - var blockInfoRes qtypes.GetLatestBlockResponse + var blockInfoRes tmservice.GetLatestBlockResponse s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &blockInfoRes)) } func (s IntegrationTestSuite) TestQueryBlockByHeight() { val := s.network.Validators[0] - _, err := s.queryClient.GetBlockByHeight(context.Background(), &qtypes.GetBlockByHeightRequest{Height: 1}) + _, err := s.queryClient.GetBlockByHeight(context.Background(), &tmservice.GetBlockByHeightRequest{Height: 1}) s.Require().NoError(err) restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/blocks/%d", val.APIAddress, 1)) s.Require().NoError(err) - var blockInfoRes qtypes.GetBlockByHeightResponse + var blockInfoRes tmservice.GetBlockByHeightResponse s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &blockInfoRes)) } @@ -97,13 +98,13 @@ func (s IntegrationTestSuite) TestQueryLatestValidatorSet() { val := s.network.Validators[0] // nil pagination - _, err := s.queryClient.GetLatestValidatorSet(context.Background(), &qtypes.GetLatestValidatorSetRequest{ + _, err := s.queryClient.GetLatestValidatorSet(context.Background(), &tmservice.GetLatestValidatorSetRequest{ Pagination: nil, }) s.Require().NoError(err) //with pagination - _, err = s.queryClient.GetLatestValidatorSet(context.Background(), &qtypes.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{ + _, err = s.queryClient.GetLatestValidatorSet(context.Background(), &tmservice.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{ Offset: 0, Limit: 10, }}) @@ -116,7 +117,7 @@ func (s IntegrationTestSuite) TestQueryLatestValidatorSet() { // rest request with pagination restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validators/latest?pagination.offset=%d&pagination.limit=%d", val.APIAddress, 0, 1)) s.Require().NoError(err) - var validatorSetRes qtypes.GetLatestValidatorSetResponse + var validatorSetRes tmservice.GetLatestValidatorSetResponse s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &validatorSetRes)) } @@ -124,13 +125,13 @@ func (s IntegrationTestSuite) TestQueryValidatorSetByHeight() { val := s.network.Validators[0] // nil pagination - _, err := s.queryClient.GetValidatorSetByHeight(context.Background(), &qtypes.GetValidatorSetByHeightRequest{ + _, err := s.queryClient.GetValidatorSetByHeight(context.Background(), &tmservice.GetValidatorSetByHeightRequest{ Height: 1, Pagination: nil, }) s.Require().NoError(err) - _, err = s.queryClient.GetValidatorSetByHeight(context.Background(), &qtypes.GetValidatorSetByHeightRequest{ + _, err = s.queryClient.GetValidatorSetByHeight(context.Background(), &tmservice.GetValidatorSetByHeightRequest{ Height: 1, Pagination: &qtypes.PageRequest{ Offset: 0, @@ -144,7 +145,7 @@ func (s IntegrationTestSuite) TestQueryValidatorSetByHeight() { // rest query with pagination restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validators/%d?pagination.offset=%d&pagination.limit=%d", val.APIAddress, 1, 0, 1)) - var validatorSetRes qtypes.GetValidatorSetByHeightResponse + var validatorSetRes tmservice.GetValidatorSetByHeightResponse s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &validatorSetRes)) } diff --git a/client/keys/export.go b/client/keys/export.go index 3f75ee2e52e3..ac2b6b476839 100644 --- a/client/keys/export.go +++ b/client/keys/export.go @@ -2,23 +2,45 @@ package keys import ( "bufio" + "fmt" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/input" + "github.com/cosmos/cosmos-sdk/crypto/keyring" +) + +const ( + flagUnarmoredHex = "unarmored-hex" + flagUnsafe = "unsafe" ) // ExportKeyCommand exports private keys from the key store. func ExportKeyCommand() *cobra.Command { - return &cobra.Command{ + cmd := &cobra.Command{ Use: "export ", Short: "Export private keys", - Long: `Export a private key from the local keybase in ASCII-armored encrypted format.`, - Args: cobra.ExactArgs(1), + Long: `Export a private key from the local keyring in ASCII-armored encrypted format. + +When both the --unarmored-hex and --unsafe flags are selected, cryptographic +private key material is exported in an INSECURE fashion that is designed to +allow users to import their keys in hot wallets. This feature is for advanced +users only that are confident about how to handle private keys work and are +FULLY AWARE OF THE RISKS. If you are unsure, you may want to do some research +and export your keys in ASCII-armored encrypted format.`, + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { buf := bufio.NewReader(cmd.InOrStdin()) clientCtx := client.GetClientContextFromCmd(cmd) + unarmored, _ := cmd.Flags().GetBool(flagUnarmoredHex) + unsafe, _ := cmd.Flags().GetBool(flagUnsafe) + + if unarmored && unsafe { + return exportUnsafeUnarmored(cmd, args[0], buf, clientCtx.Keyring) + } else if unarmored || unsafe { + return fmt.Errorf("the flags %s and %s must be used together", flagUnsafe, flagUnarmoredHex) + } encryptPassword, err := input.GetPassword("Enter passphrase to encrypt the exported key:", buf) if err != nil { @@ -31,7 +53,31 @@ func ExportKeyCommand() *cobra.Command { } cmd.Println(armored) + return nil }, } + + cmd.Flags().Bool(flagUnarmoredHex, false, "Export unarmored hex privkey. Requires --unsafe.") + cmd.Flags().Bool(flagUnsafe, false, "Enable unsafe operations. This flag must be switched on along with all unsafe operation-specific options.") + + return cmd +} + +func exportUnsafeUnarmored(cmd *cobra.Command, uid string, buf *bufio.Reader, kr keyring.Keyring) error { + // confirm deletion, unless -y is passed + if yes, err := input.GetConfirmation("WARNING: The private key will be exported as an unarmored hexadecimal string. USE AT YOUR OWN RISK. Continue?", buf, cmd.ErrOrStderr()); err != nil { + return err + } else if !yes { + return nil + } + + hexPrivKey, err := keyring.NewUnsafe(kr).UnsafeExportPrivKeyHex(uid) + if err != nil { + return err + } + + cmd.Println(hexPrivKey) + + return nil } diff --git a/client/keys/export_test.go b/client/keys/export_test.go index 4276db1c124b..b01bbf823023 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -36,15 +36,34 @@ func Test_runExportCmd(t *testing.T) { require.NoError(t, err) // Now enter password - mockIn.Reset("123456789\n123456789\n") - cmd.SetArgs([]string{ + args := []string{ "keyname1", fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), - }) + } + + mockIn.Reset("123456789\n123456789\n") + cmd.SetArgs(args) clientCtx := client.Context{}.WithKeyring(kb) ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx) require.NoError(t, cmd.ExecuteContext(ctx)) + + argsUnsafeOnly := append(args, "--unsafe") + cmd.SetArgs(argsUnsafeOnly) + require.Error(t, cmd.ExecuteContext(ctx)) + + argsUnarmoredHexOnly := append(args, "--unarmored-hex") + cmd.SetArgs(argsUnarmoredHexOnly) + require.Error(t, cmd.ExecuteContext(ctx)) + + argsUnsafeUnarmoredHex := append(args, "--unsafe", "--unarmored-hex") + cmd.SetArgs(argsUnsafeUnarmoredHex) + require.Error(t, cmd.ExecuteContext(ctx)) + + mockIn, mockOut := testutil.ApplyMockIO(cmd) + mockIn.Reset("y\n") + require.NoError(t, cmd.ExecuteContext(ctx)) + require.Equal(t, "2485e33678db4175dc0ecef2d6e1fc493d4a0d7f7ce83324b6ed70afe77f3485\n", mockOut.String()) } diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index d3220b5b43ef..f26a06b93807 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -88,6 +88,13 @@ type Keyring interface { Exporter } +// UnsafeKeyring exposes unsafe operations such as unsafe unarmored export in +// addition to those that are made available by the Keyring interface. +type UnsafeKeyring interface { + Keyring + UnsafeExporter +} + // Signer is implemented by key stores that want to provide signing capabilities. type Signer interface { // Sign sign byte messages with a user key. @@ -110,12 +117,20 @@ type Exporter interface { // Export public key ExportPubKeyArmor(uid string) (string, error) ExportPubKeyArmorByAddress(address sdk.Address) (string, error) + // ExportPrivKey returns a private key in ASCII armored format. // It returns an error if the key does not exist or a wrong encryption passphrase is supplied. ExportPrivKeyArmor(uid, encryptPassphrase string) (armor string, err error) ExportPrivKeyArmorByAddress(address sdk.Address, encryptPassphrase string) (armor string, err error) } +// UnsafeExporter is implemented by key stores that support unsafe export +// of private keys' material. +type UnsafeExporter interface { + // UnsafeExportPrivKeyHex returns a private key in unarmored hex format + UnsafeExportPrivKeyHex(uid string) (string, error) +} + // Option overrides keyring configuration options. type Option func(options *Options) @@ -774,6 +789,29 @@ func (ks keystore) writeMultisigKey(name string, pub types.PubKey) (Info, error) return info, nil } +type unsafeKeystore struct { + keystore +} + +// NewUnsafe returns a new keyring that provides support for unsafe operations. +func NewUnsafe(kr Keyring) UnsafeKeyring { + // The type assertion is against the only keystore + // implementation that is currently provided. + ks := kr.(keystore) + + return unsafeKeystore{ks} +} + +// UnsafeExportPrivKeyHex exports private keys in unarmored hexadecimal format. +func (ks unsafeKeystore) UnsafeExportPrivKeyHex(uid string) (privkey string, err error) { + priv, err := ks.ExportPrivateKeyObject(uid) + if err != nil { + return "", err + } + + return hex.EncodeToString(priv.Bytes()), nil +} + func addrHexKeyAsString(address sdk.Address) string { return fmt.Sprintf("%s.%s", hex.EncodeToString(address.Bytes()), addressSuffix) } diff --git a/crypto/keyring/keyring_test.go b/crypto/keyring/keyring_test.go index 540ea57bf3fe..bcd7eddf39f9 100644 --- a/crypto/keyring/keyring_test.go +++ b/crypto/keyring/keyring_test.go @@ -1,6 +1,7 @@ package keyring import ( + "encoding/hex" "fmt" "strings" "testing" @@ -1092,6 +1093,29 @@ func TestAltKeyring_ImportExportPubKey_ByAddress(t *testing.T) { require.EqualError(t, err, fmt.Sprintf("cannot overwrite key: %s", newUID)) } +func TestAltKeyring_UnsafeExportPrivKeyHex(t *testing.T) { + keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + require.NoError(t, err) + + uid := theID + + _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + + unsafeKeyring := NewUnsafe(keyring) + privKey, err := unsafeKeyring.UnsafeExportPrivKeyHex(uid) + + require.NoError(t, err) + require.Equal(t, 64, len(privKey)) + + _, err = hex.DecodeString(privKey) + require.NoError(t, err) + + // test error on non existing key + _, err = unsafeKeyring.UnsafeExportPrivKeyHex("non-existing") + require.Error(t, err) +} + func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) { keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) require.NoError(t, err) diff --git a/go.mod b/go.mod index 39e28042489b..8163ebbfbe62 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/golang/snappy v0.0.2 // indirect github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 + github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/hashicorp/golang-lru v0.5.4 github.com/magiconair/properties v1.8.4 diff --git a/go.sum b/go.sum index da0703bd69d8..b6ae47006000 100644 --- a/go.sum +++ b/go.sum @@ -247,6 +247,7 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.1/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= diff --git a/proto/cosmos/base/tendermint/v1beta1/query.proto b/proto/cosmos/base/tendermint/v1beta1/query.proto index b5220231ac0b..640522e7a9f2 100644 --- a/proto/cosmos/base/tendermint/v1beta1/query.proto +++ b/proto/cosmos/base/tendermint/v1beta1/query.proto @@ -8,7 +8,7 @@ import "tendermint/types/block.proto"; import "tendermint/types/types.proto"; import "cosmos/base/query/v1beta1/pagination.proto"; -option go_package = "github.com/cosmos/cosmos-sdk/types/query"; +option go_package = "github.com/cosmos/cosmos-sdk/client/grpc/tmservice"; // Service defines the gRPC querier service for tendermint queries. service Service { diff --git a/proto/cosmos/tx/v1beta1/service.proto b/proto/cosmos/tx/v1beta1/service.proto index d78216d031e4..68eaaae83395 100644 --- a/proto/cosmos/tx/v1beta1/service.proto +++ b/proto/cosmos/tx/v1beta1/service.proto @@ -28,8 +28,8 @@ service Service { // GetTxsEventRequest is the request type for the Service.TxsByEvents // RPC method. message GetTxsEventRequest { - // event is the transaction event type. - string event = 1; + // events is the list of transaction event type. + repeated string events = 1; // pagination defines an pagination for the request. cosmos.base.query.v1beta1.PageRequest pagination = 2; } diff --git a/proto/ibc/core/client/v1/genesis.proto b/proto/ibc/core/client/v1/genesis.proto index b1c4247c94ad..06b4bbd06485 100644 --- a/proto/ibc/core/client/v1/genesis.proto +++ b/proto/ibc/core/client/v1/genesis.proto @@ -20,4 +20,6 @@ message GenesisState { Params params = 3 [(gogoproto.nullable) = false]; // create localhost on initialization bool create_localhost = 4 [(gogoproto.moretags) = "yaml:\"create_localhost\""]; + // the sequence for the next generated client identifier + uint64 next_client_sequence = 5 [(gogoproto.moretags) = "yaml:\"next_client_sequence\""]; } diff --git a/proto/ibc/core/client/v1/tx.proto b/proto/ibc/core/client/v1/tx.proto index 1019e15a0345..a30ec8bbf10f 100644 --- a/proto/ibc/core/client/v1/tx.proto +++ b/proto/ibc/core/client/v1/tx.proto @@ -27,15 +27,13 @@ message MsgCreateClient { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; - // client unique identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; // light client state - google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""]; + google.protobuf.Any client_state = 1 [(gogoproto.moretags) = "yaml:\"client_state\""]; // consensus state associated with the client that corresponds to a given // height. - google.protobuf.Any consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; + google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; // signer address - string signer = 4; + string signer = 3; } // MsgCreateClientResponse defines the Msg/CreateClient response type. diff --git a/server/grpc/server_test.go b/server/grpc/server_test.go index bfa39d818523..59c726c6abaf 100644 --- a/server/grpc/server_test.go +++ b/server/grpc/server_test.go @@ -11,13 +11,14 @@ import ( "github.com/stretchr/testify/suite" "google.golang.org/grpc" "google.golang.org/grpc/metadata" - rpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" "github.com/cosmos/cosmos-sdk/testutil/network" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/cosmos/cosmos-sdk/types/tx" + txtypes "github.com/cosmos/cosmos-sdk/types/tx" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) @@ -99,6 +100,19 @@ func (s *IntegrationTestSuite) TestGRPCServer() { } // Make sure the following services are present s.Require().True(servicesMap["cosmos.bank.v1beta1.Query"]) + + // Query the tx via gRPC without pagination. This used to panic, see + // https://github.com/cosmos/cosmos-sdk/issues/8038. + txServiceClient := txtypes.NewServiceClient(conn) + _, err = txServiceClient.GetTxsEvent( + context.Background(), + &tx.GetTxsEventRequest{ + Events: []string{"message.action=send"}, + }, + ) + // TODO Once https://github.com/cosmos/cosmos-sdk/pull/8029 is merged, this + // should not error anymore. + s.Require().NoError(err) } // Test and enforce that we upfront reject any connections to baseapp containing diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 72238cbb1e66..61378a366143 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -549,9 +549,12 @@ func (rs *Store) SetInitialVersion(version int64) error { // Loop through all the stores, if it's an IAVL store, then set initial // version on it. - for _, commitKVStore := range rs.stores { - if storeWithVersion, ok := commitKVStore.(types.StoreWithInitialVersion); ok { - storeWithVersion.SetInitialVersion(version) + for key, store := range rs.stores { + if store.GetStoreType() == types.StoreTypeIAVL { + // If the store is wrapped with an inter-block cache, we must first unwrap + // it to get the underlying IAVL store. + store = rs.GetCommitKVStore(key) + store.(*iavl.Store).SetInitialVersion(version) } } diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index efe2618779a4..7934b514d168 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -657,11 +657,18 @@ func TestSetInitialVersion(t *testing.T) { db := dbm.NewMemDB() multi := newMultiStoreWithMounts(db, types.PruneNothing) + require.NoError(t, multi.LoadLatestVersion()) + multi.SetInitialVersion(5) require.Equal(t, int64(5), multi.initialVersion) multi.Commit() require.Equal(t, int64(5), multi.LastCommitID().Version) + + ckvs := multi.GetCommitKVStore(multi.keysByName["store1"]) + iavlStore, ok := ckvs.(*iavl.Store) + require.True(t, ok) + require.True(t, iavlStore.VersionExists(5)) } func BenchmarkMultistoreSnapshot100K(b *testing.B) { diff --git a/types/errors/abci.go b/types/errors/abci.go index f297e4ca6987..df85f6bc89df 100644 --- a/types/errors/abci.go +++ b/types/errors/abci.go @@ -151,12 +151,14 @@ func errIsNil(err error) bool { return false } +var errPanicWithMsg = Wrapf(ErrPanic, "panic message redacted to hide potentially sensitive system info") + // Redact replaces an error that is not initialized as an ABCI Error with a // generic internal error instance. If the error is an ABCI Error, that error is // simply returned. func Redact(err error) error { if ErrPanic.Is(err) { - return ErrPanic + return errPanicWithMsg } if abciCode(err) == internalABCICode { return errInternal diff --git a/types/errors/abci_test.go b/types/errors/abci_test.go index 18d6b1f2e693..02c12e7bbdd6 100644 --- a/types/errors/abci_test.go +++ b/types/errors/abci_test.go @@ -171,7 +171,7 @@ func (s *abciTestSuite) TestRedact() { }{ "panic looses message": { err: Wrap(ErrPanic, "some secret stack trace"), - changed: ErrPanic, + changed: errPanicWithMsg, }, "sdk errors untouched": { err: Wrap(ErrUnauthorized, "cannot drop db"), @@ -233,7 +233,7 @@ func (s *abciTestSuite) TestABCIInfoSerializeErr() { }, "redact in default encoder": { src: myPanic, - exp: "panic", + exp: "panic message redacted to hide potentially sensitive system info: panic", }, "do not redact in debug encoder": { src: myPanic, diff --git a/types/tx/service.pb.go b/types/tx/service.pb.go index 2302593c5c75..44242b03116d 100644 --- a/types/tx/service.pb.go +++ b/types/tx/service.pb.go @@ -33,8 +33,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GetTxsEventRequest is the request type for the Service.TxsByEvents // RPC method. type GetTxsEventRequest struct { - // event is the transaction event type. - Event string `protobuf:"bytes,1,opt,name=event,proto3" json:"event,omitempty"` + // events is the list of transaction event type. + Events []string `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"` // pagination defines an pagination for the request. Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -72,11 +72,11 @@ func (m *GetTxsEventRequest) XXX_DiscardUnknown() { var xxx_messageInfo_GetTxsEventRequest proto.InternalMessageInfo -func (m *GetTxsEventRequest) GetEvent() string { +func (m *GetTxsEventRequest) GetEvents() []string { if m != nil { - return m.Event + return m.Events } - return "" + return nil } func (m *GetTxsEventRequest) GetPagination() *query.PageRequest { @@ -370,40 +370,40 @@ func init() { proto.RegisterFile("cosmos/tx/v1beta1/service.proto", fileDescript var fileDescriptor_e0b00a618705eca7 = []byte{ // 563 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0xae, 0x1d, 0xfa, 0xc3, 0xa4, 0x08, 0x58, 0x7e, 0x14, 0x99, 0xe2, 0x06, 0xa7, 0x69, 0x23, - 0x24, 0xbc, 0x6a, 0xb8, 0xf4, 0x80, 0x84, 0x84, 0x54, 0x22, 0x6e, 0xc8, 0xed, 0x89, 0x4b, 0xb5, - 0x09, 0x5b, 0xc7, 0x22, 0xf1, 0xba, 0xde, 0x4d, 0xb4, 0x15, 0xf4, 0xc2, 0x91, 0x13, 0x12, 0x2f, - 0xc5, 0x31, 0x12, 0x17, 0x8e, 0x28, 0xe1, 0x0d, 0x78, 0x01, 0xe4, 0xf5, 0x3a, 0x71, 0xa8, 0x4d, - 0x7b, 0xf2, 0xae, 0xfc, 0xfd, 0xcc, 0x37, 0xe3, 0x31, 0x6c, 0xf7, 0x18, 0x1f, 0x32, 0x8e, 0x85, - 0xc4, 0xe3, 0xfd, 0x2e, 0x15, 0x64, 0x1f, 0x73, 0x1a, 0x8f, 0x83, 0x1e, 0x75, 0xa3, 0x98, 0x09, - 0x86, 0xee, 0xa6, 0x00, 0x57, 0x48, 0x57, 0x03, 0xac, 0x2d, 0x9f, 0x31, 0x7f, 0x40, 0x31, 0x89, - 0x02, 0x4c, 0xc2, 0x90, 0x09, 0x22, 0x02, 0x16, 0xf2, 0x94, 0x60, 0x35, 0xb4, 0x62, 0x97, 0x70, - 0x8a, 0x49, 0xb7, 0x17, 0xcc, 0x85, 0x93, 0x8b, 0x06, 0x59, 0x97, 0x6d, 0x85, 0xd4, 0xef, 0x9e, - 0xe6, 0x05, 0xce, 0x46, 0x34, 0x3e, 0x9f, 0x63, 0x22, 0xe2, 0x07, 0xa1, 0x72, 0x4b, 0xb1, 0x4e, - 0x0c, 0xa8, 0x43, 0xc5, 0xb1, 0xe4, 0x87, 0x63, 0x1a, 0x0a, 0x8f, 0x9e, 0x8d, 0x28, 0x17, 0xe8, - 0x3e, 0xac, 0xd2, 0xe4, 0x5e, 0x33, 0xea, 0x46, 0xeb, 0xa6, 0x97, 0x5e, 0xd0, 0x6b, 0x80, 0x05, - 0xbf, 0x66, 0xd6, 0x8d, 0x56, 0xb5, 0xbd, 0xeb, 0xea, 0x78, 0x89, 0x99, 0xab, 0xcc, 0xb2, 0x98, - 0xee, 0x5b, 0xe2, 0x53, 0xad, 0xe8, 0xe5, 0x98, 0xce, 0xc4, 0x80, 0x7b, 0x4b, 0xa6, 0x3c, 0x62, - 0x21, 0xa7, 0x68, 0x0f, 0x2a, 0x42, 0xf2, 0x9a, 0x51, 0xaf, 0xb4, 0xaa, 0xed, 0x07, 0xee, 0xa5, - 0xbe, 0xb9, 0xc7, 0xd2, 0x4b, 0x10, 0xa8, 0x03, 0x9b, 0x42, 0x9e, 0xc4, 0x9a, 0xc7, 0x6b, 0xa6, - 0x62, 0xec, 0x2c, 0x95, 0xa2, 0x7a, 0x95, 0x23, 0x6a, 0xb0, 0x57, 0x15, 0xf3, 0x73, 0x22, 0x94, - 0x4f, 0x54, 0x51, 0x89, 0xf6, 0xae, 0x4c, 0xa4, 0x95, 0xf2, 0x91, 0x0e, 0xe0, 0xf6, 0x51, 0x30, - 0x1c, 0x0d, 0x88, 0xc8, 0x12, 0xa3, 0x26, 0x98, 0x42, 0xaa, 0x06, 0x96, 0x86, 0x31, 0x85, 0x74, - 0xbe, 0x18, 0x70, 0x67, 0x41, 0xd5, 0x9d, 0x78, 0x01, 0x1b, 0x3e, 0xe1, 0x27, 0x41, 0x78, 0xca, - 0xb4, 0xc2, 0x93, 0xf2, 0x70, 0x1d, 0xc2, 0xdf, 0x84, 0xa7, 0xcc, 0x5b, 0xf7, 0xd3, 0x03, 0x3a, - 0x80, 0xb5, 0x98, 0xf2, 0xd1, 0x40, 0xe8, 0x19, 0xd5, 0xcb, 0xb9, 0x9e, 0xc2, 0x79, 0x1a, 0xef, - 0x38, 0xb0, 0xa9, 0x06, 0x93, 0x65, 0x40, 0x70, 0xa3, 0x4f, 0x78, 0x5f, 0x7f, 0x06, 0xea, 0xec, - 0x5c, 0xc0, 0x2d, 0x8d, 0xd1, 0xc5, 0x5e, 0x2f, 0x28, 0x3a, 0x84, 0x6a, 0x6e, 0x68, 0xba, 0xb4, - 0xeb, 0xcd, 0x0c, 0x16, 0x33, 0x6b, 0xff, 0x31, 0x61, 0xfd, 0x28, 0x5d, 0x30, 0x24, 0x61, 0x23, - 0x6b, 0x1d, 0x72, 0x0a, 0x9c, 0xff, 0x19, 0x89, 0xd5, 0xf8, 0x2f, 0x26, 0x35, 0x70, 0x1a, 0x9f, - 0x7f, 0xfc, 0xfe, 0x66, 0x3e, 0x76, 0x1e, 0xe1, 0x82, 0xcd, 0xce, 0xdc, 0x22, 0x58, 0x55, 0x4d, - 0x40, 0xdb, 0x05, 0x92, 0xf9, 0x16, 0x5a, 0xf5, 0x72, 0x80, 0x36, 0xdc, 0x51, 0x86, 0x36, 0xda, - 0xc2, 0x45, 0x3b, 0x8d, 0x3f, 0x26, 0x5d, 0xbf, 0x40, 0x9f, 0xa0, 0x9a, 0xdb, 0x19, 0xd4, 0x2c, - 0x93, 0x5d, 0x5a, 0x64, 0x6b, 0xf7, 0x2a, 0x98, 0xae, 0xc1, 0x56, 0x35, 0xd4, 0xd0, 0xc3, 0xc2, - 0x1a, 0xf8, 0xab, 0x97, 0xdf, 0xa7, 0xb6, 0x31, 0x99, 0xda, 0xc6, 0xaf, 0xa9, 0x6d, 0x7c, 0x9d, - 0xd9, 0x2b, 0x93, 0x99, 0xbd, 0xf2, 0x73, 0x66, 0xaf, 0xbc, 0x6b, 0xfa, 0x81, 0xe8, 0x8f, 0xba, - 0x6e, 0x8f, 0x0d, 0x33, 0x6e, 0xfa, 0x78, 0xc6, 0xdf, 0x7f, 0xc0, 0xe2, 0x3c, 0xa2, 0x89, 0x58, - 0x77, 0x4d, 0xfd, 0x6e, 0x9e, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xae, 0x63, 0xf9, 0x38, 0x2f, + 0x10, 0xae, 0x1d, 0x48, 0xdb, 0x49, 0x11, 0xb0, 0x88, 0x2a, 0x32, 0xc5, 0x0d, 0x4e, 0xd3, 0x56, + 0x48, 0xd8, 0x6a, 0xb8, 0xf4, 0x80, 0x84, 0x84, 0x54, 0x22, 0x6e, 0xc8, 0xed, 0x89, 0x4b, 0xb5, + 0x09, 0x5b, 0xc7, 0x22, 0xf1, 0xba, 0xd9, 0x49, 0xb4, 0x15, 0xf4, 0xc2, 0x91, 0x13, 0x12, 0x2f, + 0xc5, 0x31, 0x12, 0x17, 0x8e, 0x28, 0xe1, 0x0d, 0x78, 0x01, 0xe4, 0xf5, 0x3a, 0x71, 0x68, 0x4c, + 0x7b, 0xca, 0x8e, 0xf2, 0xfd, 0xcc, 0x37, 0xa3, 0x31, 0x6c, 0x77, 0xb8, 0xe8, 0x73, 0xe1, 0xa1, + 0xf4, 0x46, 0x07, 0x6d, 0x86, 0xf4, 0xc0, 0x13, 0x6c, 0x30, 0x0a, 0x3b, 0xcc, 0x8d, 0x07, 0x1c, + 0x39, 0xb9, 0x9f, 0x02, 0x5c, 0x94, 0xae, 0x06, 0x58, 0x5b, 0x01, 0xe7, 0x41, 0x8f, 0x79, 0x34, + 0x0e, 0x3d, 0x1a, 0x45, 0x1c, 0x29, 0x86, 0x3c, 0x12, 0x29, 0xc1, 0xaa, 0x6b, 0xc5, 0x36, 0x15, + 0xcc, 0xa3, 0xed, 0x4e, 0x38, 0x13, 0x4e, 0x0a, 0x0d, 0xb2, 0xae, 0xda, 0xa2, 0xd4, 0xff, 0x3d, + 0xcd, 0x0b, 0x9c, 0x0f, 0xd9, 0xe0, 0x62, 0x86, 0x89, 0x69, 0x10, 0x46, 0xca, 0x2d, 0xc5, 0x3a, + 0x08, 0xa4, 0xc5, 0xf0, 0x44, 0x8a, 0xa3, 0x11, 0x8b, 0xd0, 0x67, 0xe7, 0x43, 0x26, 0x90, 0x6c, + 0x42, 0x99, 0x25, 0xb5, 0xa8, 0x1a, 0xb5, 0xd2, 0xfe, 0xba, 0xaf, 0x2b, 0xf2, 0x1a, 0x60, 0xae, + 0x50, 0x35, 0x6b, 0xc6, 0x7e, 0xa5, 0xb9, 0xeb, 0xea, 0x80, 0x89, 0x9d, 0xab, 0xec, 0xb2, 0xa0, + 0xee, 0x5b, 0x1a, 0x30, 0xad, 0xe9, 0xe7, 0x98, 0xce, 0xd8, 0x80, 0x07, 0x0b, 0xb6, 0x22, 0xe6, + 0x91, 0x60, 0x64, 0x0f, 0x4a, 0x28, 0x53, 0xd3, 0x4a, 0xf3, 0xa1, 0x7b, 0x65, 0x72, 0xee, 0x89, + 0xf4, 0x13, 0x04, 0x69, 0xc1, 0x06, 0xca, 0xd3, 0x81, 0xe6, 0x89, 0xaa, 0xa9, 0x18, 0x3b, 0x0b, + 0xad, 0xa8, 0x69, 0xe5, 0x88, 0x1a, 0xec, 0x57, 0x70, 0xf6, 0x4e, 0x84, 0xf2, 0x89, 0x4a, 0x2a, + 0xd1, 0xde, 0xb5, 0x89, 0xb4, 0x52, 0x3e, 0xd2, 0x21, 0xdc, 0x3d, 0x0e, 0xfb, 0xc3, 0x1e, 0xc5, + 0x2c, 0x31, 0x69, 0x80, 0x89, 0xb2, 0x6a, 0x28, 0xcd, 0x82, 0x30, 0x26, 0x4a, 0xe7, 0x8b, 0x01, + 0xf7, 0xe6, 0x54, 0x3d, 0x89, 0x17, 0xb0, 0x16, 0x50, 0x71, 0x1a, 0x46, 0x67, 0x5c, 0x2b, 0x3c, + 0x29, 0x0e, 0xd7, 0xa2, 0xe2, 0x4d, 0x74, 0xc6, 0xfd, 0xd5, 0x20, 0x7d, 0x90, 0x43, 0x28, 0x0f, + 0x98, 0x18, 0xf6, 0x50, 0xef, 0xa8, 0x56, 0xcc, 0xf5, 0x15, 0xce, 0xd7, 0x78, 0xc7, 0x81, 0x0d, + 0xb5, 0x98, 0x2c, 0x03, 0x81, 0x5b, 0x5d, 0x2a, 0xba, 0xaa, 0x87, 0x75, 0x5f, 0xbd, 0x9d, 0x4b, + 0xb8, 0xa3, 0x31, 0xba, 0xd9, 0x9b, 0x05, 0x25, 0x47, 0x50, 0xc9, 0x2d, 0x4d, 0xb7, 0x76, 0xb3, + 0x9d, 0xc1, 0x7c, 0x67, 0xcd, 0x3f, 0x26, 0xac, 0x1e, 0xa7, 0x27, 0x46, 0x24, 0xac, 0x65, 0xa3, + 0x23, 0xce, 0x12, 0xe7, 0x7f, 0x56, 0x62, 0xd5, 0xff, 0x8b, 0x49, 0x0d, 0x9c, 0xfa, 0xe7, 0x1f, + 0xbf, 0xbf, 0x99, 0x8f, 0x9d, 0x47, 0xde, 0x92, 0xdb, 0xce, 0xdc, 0x62, 0xb8, 0xad, 0x86, 0x40, + 0xb6, 0x97, 0x48, 0xe6, 0x47, 0x68, 0xd5, 0x8a, 0x01, 0xda, 0x70, 0x47, 0x19, 0xda, 0x64, 0xcb, + 0x5b, 0x76, 0xd5, 0xde, 0xc7, 0x64, 0xea, 0x97, 0xe4, 0x13, 0x54, 0x72, 0x37, 0x43, 0x1a, 0x45, + 0xb2, 0x0b, 0xa7, 0x6c, 0xed, 0x5e, 0x07, 0xd3, 0x3d, 0xd8, 0xaa, 0x87, 0x2a, 0xd9, 0x5c, 0xda, + 0x83, 0x78, 0xf5, 0xf2, 0xfb, 0xc4, 0x36, 0xc6, 0x13, 0xdb, 0xf8, 0x35, 0xb1, 0x8d, 0xaf, 0x53, + 0x7b, 0x65, 0x3c, 0xb5, 0x57, 0x7e, 0x4e, 0xed, 0x95, 0x77, 0x8d, 0x20, 0xc4, 0xee, 0xb0, 0xed, + 0x76, 0x78, 0x3f, 0xe3, 0xa6, 0x3f, 0xcf, 0xc4, 0xfb, 0x0f, 0x1e, 0x5e, 0xc4, 0x2c, 0x11, 0x6b, + 0x97, 0xd5, 0x07, 0xe7, 0xf9, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x62, 0x59, 0xdc, 0x70, 0x31, 0x05, 0x00, 0x00, } @@ -597,12 +597,14 @@ func (m *GetTxsEventRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if len(m.Event) > 0 { - i -= len(m.Event) - copy(dAtA[i:], m.Event) - i = encodeVarintService(dAtA, i, uint64(len(m.Event))) - i-- - dAtA[i] = 0xa + if len(m.Events) > 0 { + for iNdEx := len(m.Events) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Events[iNdEx]) + copy(dAtA[i:], m.Events[iNdEx]) + i = encodeVarintService(dAtA, i, uint64(len(m.Events[iNdEx]))) + i-- + dAtA[i] = 0xa + } } return len(dAtA) - i, nil } @@ -846,9 +848,11 @@ func (m *GetTxsEventRequest) Size() (n int) { } var l int _ = l - l = len(m.Event) - if l > 0 { - n += 1 + l + sovService(uint64(l)) + if len(m.Events) > 0 { + for _, s := range m.Events { + l = len(s) + n += 1 + l + sovService(uint64(l)) + } } if m.Pagination != nil { l = m.Pagination.Size() @@ -979,7 +983,7 @@ func (m *GetTxsEventRequest) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Event", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Events", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1007,7 +1011,7 @@ func (m *GetTxsEventRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Event = string(dAtA[iNdEx:postIndex]) + m.Events = append(m.Events, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex case 2: if wireType != 2 { diff --git a/x/auth/client/rest/rest_test.go b/x/auth/client/rest/rest_test.go index 1d7cac6848bf..671df87a8b9c 100644 --- a/x/auth/client/rest/rest_test.go +++ b/x/auth/client/rest/rest_test.go @@ -453,7 +453,6 @@ func (s *IntegrationTestSuite) TestLegacyRestErrMessages() { "Successful IBC message", ibcsolomachinecli.NewCreateClientCmd(), []string{ - "21212121212", // dummy client-id "1", // dummy sequence consensusJSON.Name(), // path to consensus json, fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), diff --git a/x/auth/tx/service.go b/x/auth/tx/service.go index b12808a16403..751c8fbb22b2 100644 --- a/x/auth/tx/service.go +++ b/x/auth/tx/service.go @@ -49,32 +49,17 @@ const ( // TxsByEvents implements the ServiceServer.TxsByEvents RPC method. func (s txServer) GetTxsEvent(ctx context.Context, req *txtypes.GetTxsEventRequest) (*txtypes.GetTxsEventResponse, error) { - offset := int(req.Pagination.Offset) - limit := int(req.Pagination.Limit) - if offset < 0 { - return nil, status.Error(codes.InvalidArgument, "offset must greater than 0") - } - if len(req.Event) == 0 { - return nil, status.Error(codes.InvalidArgument, "must declare at least one event to search") + page, limit, err := pagination.ParsePagination(req.Pagination) + if err != nil { + return nil, err } - if limit < 0 { - return nil, status.Error(codes.InvalidArgument, "limit must greater than 0") - } else if limit == 0 { - limit = pagination.DefaultLimit + if len(req.Events) == 0 { + return nil, status.Error(codes.InvalidArgument, "must declare at least one event to search") } - page := offset/limit + 1 - - var events []string - - if strings.Contains(req.Event, "&") { - events = strings.Split(req.Event, "&") - } else { - events = append(events, req.Event) - } - tmEvents := make([]string, len(events)) - for i, event := range events { + tmEvents := make([]string, len(req.Events)) + for i, event := range req.Events { if !strings.Contains(event, "=") { return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid event; event %s should be of the format: %s", event, eventFormat)) } else if strings.Count(event, "=") > 1 { diff --git a/x/auth/tx/service_test.go b/x/auth/tx/service_test.go index a1bacb55cb40..480529541794 100644 --- a/x/auth/tx/service_test.go +++ b/x/auth/tx/service_test.go @@ -124,10 +124,18 @@ func (s IntegrationTestSuite) TestGetTxEvents() { s.Require().NoError(s.network.WaitForNextBlock()) + // Query the tx via gRPC empty params. + _, err = s.queryClient.GetTxsEvent( + context.Background(), + &tx.GetTxsEventRequest{}, + ) + s.Require().Error(err) + // Query the tx via gRPC. grpcRes, err := s.queryClient.GetTxsEvent( context.Background(), - &tx.GetTxsEventRequest{Event: "message.action=send", + &tx.GetTxsEventRequest{ + Events: []string{"message.action=send"}, Pagination: &query.PageRequest{ CountTotal: false, Offset: 0, @@ -139,14 +147,70 @@ func (s IntegrationTestSuite) TestGetTxEvents() { s.Require().Equal(len(grpcRes.Txs), 1) s.Require().Equal("foobar", grpcRes.Txs[0].Body.Memo) - // Query the tx via grpc-gateway. - restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?event=%s&pagination.offset=%d&pagination.limit=%d", val.APIAddress, "message.action=send", 0, 1)) + // Query the tx via gRPC without pagination. This used to panic, see + // https://github.com/cosmos/cosmos-sdk/issues/8038. + grpcRes, err = s.queryClient.GetTxsEvent( + context.Background(), + &tx.GetTxsEventRequest{ + Events: []string{"message.action=send"}, + }, + ) + // TODO Once https://github.com/cosmos/cosmos-sdk/pull/8029 is merged, this + // should not error anymore. s.Require().NoError(err) - var getTxRes tx.GetTxsEventResponse - s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &getTxRes)) - s.Require().Equal(len(grpcRes.Txs), 1) - s.Require().Equal("foobar", getTxRes.Txs[0].Body.Memo) - s.Require().NotZero(grpcRes.TxResponses[0].Height) + + rpcTests := []struct { + name string + url string + expectErr bool + expErrMsg string + }{ + { + "empty params", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs", val.APIAddress), + true, + "must declare at least one event to search", + }, + { + "without pagination", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s", val.APIAddress, "message.action=send"), + false, + "", + }, + { + "with pagination", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&pagination.offset=%d&pagination.limit=%d", val.APIAddress, "message.action=send", 0, 10), + false, + "", + }, + { + "expect pass with multiple-events", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&events=%s", val.APIAddress, "message.action=send", "message.module=bank"), + false, + "", + }, + { + "expect pass with escape event", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s", val.APIAddress, "message.action%3Dsend"), + false, + "", + }, + } + for _, tc := range rpcTests { + s.Run(tc.name, func() { + res, err := rest.GetRequest(tc.url) + s.Require().NoError(err) + if tc.expectErr { + s.Require().Contains(string(res), tc.expErrMsg) + } else { + var result tx.GetTxsEventResponse + val.ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result) + s.Require().GreaterOrEqual(len(result.Txs), 1) + s.Require().Equal("foobar", result.Txs[0].Body.Memo) + s.Require().NotZero(result.TxResponses[0].Height) + } + }) + } } func (s IntegrationTestSuite) TestGetTx() { diff --git a/x/ibc/core/02-client/genesis.go b/x/ibc/core/02-client/genesis.go index ef00930f0b83..6e77b20e36f9 100644 --- a/x/ibc/core/02-client/genesis.go +++ b/x/ibc/core/02-client/genesis.go @@ -7,7 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/keeper" "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/core/exported" - localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/09-localhost/types" ) // InitGenesis initializes the ibc client submodule's state from a provided genesis @@ -39,29 +38,10 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) { } } - if !gs.CreateLocalhost { - return - } - - // NOTE: return if the localhost client was already imported. The chain-id and - // block height will be overwriten to the correct values during BeginBlock. - if _, found := k.GetClientState(ctx, exported.Localhost); found { - return - } - - // client id is always "localhost" - revision := types.ParseChainID(ctx.ChainID()) - clientState := localhosttypes.NewClientState( - ctx.ChainID(), types.NewHeight(revision, uint64(ctx.BlockHeight())), - ) + k.SetNextClientSequence(ctx, gs.NextClientSequence) - if err := clientState.Validate(); err != nil { - panic(err) - } - - if err := k.CreateClient(ctx, exported.Localhost, clientState, nil); err != nil { - panic(err) - } + // NOTE: localhost creation is specifically disallowed for the time being. + // Issue: https://github.com/cosmos/cosmos-sdk/issues/7871 } // ExportGenesis returns the ibc client submodule's exported genesis. diff --git a/x/ibc/core/02-client/keeper/client.go b/x/ibc/core/02-client/keeper/client.go index ddb742563c1d..49d5a04eb361 100644 --- a/x/ibc/core/02-client/keeper/client.go +++ b/x/ibc/core/02-client/keeper/client.go @@ -15,20 +15,17 @@ import ( // // CONTRACT: ClientState was constructed correctly from given initial consensusState func (k Keeper) CreateClient( - ctx sdk.Context, clientID string, clientState exported.ClientState, consensusState exported.ConsensusState, -) error { + ctx sdk.Context, clientState exported.ClientState, consensusState exported.ConsensusState, +) (string, error) { params := k.GetParams(ctx) if !params.IsAllowedClient(clientState.ClientType()) { - return sdkerrors.Wrapf( + return "", sdkerrors.Wrapf( types.ErrInvalidClientType, "client state type %s is not registered in the allowlist", clientState.ClientType(), ) } - _, found := k.GetClientState(ctx, clientID) - if found { - return sdkerrors.Wrapf(types.ErrClientExists, "cannot create client with ID %s", clientID) - } + clientID := k.GenerateClientIdentifier(ctx, clientState.ClientType()) // check if consensus state is nil in case the created client is Localhost if consensusState != nil { @@ -46,7 +43,7 @@ func (k Keeper) CreateClient( ) }() - return nil + return clientID, nil } // UpdateClient updates the consensus state and the state root from a provided header. diff --git a/x/ibc/core/02-client/keeper/client_test.go b/x/ibc/core/02-client/keeper/client_test.go index 736a34d1e480..3d772761cc51 100644 --- a/x/ibc/core/02-client/keeper/client_test.go +++ b/x/ibc/core/02-client/keeper/client_test.go @@ -19,36 +19,23 @@ import ( func (suite *KeeperTestSuite) TestCreateClient() { cases := []struct { - msg string - clientID string - expPass bool - expPanic bool + msg string + clientState exported.ClientState + expPass bool }{ - {"success", testClientID, true, false}, - {"client ID exists", testClientID, false, false}, + {"success", ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), true}, + {"client type not supported", localhosttypes.NewClientState(testChainID, clienttypes.NewHeight(0, 1)), false}, } for i, tc := range cases { - tc := tc - i := i - if tc.expPanic { - suite.Require().Panics(func() { - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - suite.keeper.CreateClient(suite.ctx, tc.clientID, clientState, suite.consensusState) - }, "Msg %d didn't panic: %s", i, tc.msg) - } else { - clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - if tc.expPass { - suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.msg) - } - // If we were able to NewClientState clientstate successfully, try persisting it to state - err := suite.keeper.CreateClient(suite.ctx, tc.clientID, clientState, suite.consensusState) - if tc.expPass { - suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) - } else { - suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) - } + clientID, err := suite.keeper.CreateClient(suite.ctx, tc.clientState, suite.consensusState) + if tc.expPass { + suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) + suite.Require().NotNil(clientID, "valid test case %d failed: %s", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) + suite.Require().Equal("", clientID, "invalid test case %d passed: %s", i, tc.msg) } } } @@ -72,6 +59,8 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { var ( updateHeader *ibctmtypes.Header clientState *ibctmtypes.ClientState + clientID string + err error ) cases := []struct { @@ -81,7 +70,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { }{ {"valid update", func() error { clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) + clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) // store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height incrementedClientHeight := testClientHeight.Increment() @@ -89,17 +78,17 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { Timestamp: suite.now.Add(time.Minute), NextValidatorsHash: suite.valSetHash, } - suite.keeper.SetClientConsensusState(suite.ctx, testClientID, incrementedClientHeight, intermediateConsState) + suite.keeper.SetClientConsensusState(suite.ctx, clientID, incrementedClientHeight, intermediateConsState) clientState.LatestHeight = incrementedClientHeight - suite.keeper.SetClientState(suite.ctx, testClientID, clientState) + suite.keeper.SetClientState(suite.ctx, clientID, clientState) updateHeader = createFutureUpdateFn(suite) return err }, true}, {"valid past update", func() error { clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) + clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) suite.Require().NoError(err) height1 := types.NewHeight(0, 1) @@ -109,7 +98,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { Timestamp: suite.past, NextValidatorsHash: suite.valSetHash, } - suite.keeper.SetClientConsensusState(suite.ctx, testClientID, height1, prevConsState) + suite.keeper.SetClientConsensusState(suite.ctx, clientID, height1, prevConsState) height2 := types.NewHeight(0, 2) @@ -118,7 +107,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { Timestamp: suite.past.Add(time.Minute), NextValidatorsHash: suite.valSetHash, } - suite.keeper.SetClientConsensusState(suite.ctx, testClientID, height2, intermediateConsState) + suite.keeper.SetClientConsensusState(suite.ctx, clientID, height2, intermediateConsState) // updateHeader will fill in consensus state between prevConsState and suite.consState // clientState should not be updated @@ -147,7 +136,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { {"valid past update before client was frozen", func() error { clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) clientState.FrozenHeight = types.NewHeight(0, testClientHeight.RevisionHeight-1) - err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) + clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) suite.Require().NoError(err) height1 := types.NewHeight(0, 1) @@ -157,7 +146,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { Timestamp: suite.past, NextValidatorsHash: suite.valSetHash, } - suite.keeper.SetClientConsensusState(suite.ctx, testClientID, height1, prevConsState) + suite.keeper.SetClientConsensusState(suite.ctx, clientID, height1, prevConsState) // updateHeader will fill in consensus state between prevConsState and suite.consState // clientState should not be updated @@ -166,7 +155,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { }, true}, {"invalid header", func() error { clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) + _, err := suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) suite.Require().NoError(err) updateHeader = createPastUpdateFn(suite) @@ -179,13 +168,14 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { i := i suite.Run(fmt.Sprintf("Case %s", tc.name), func() { suite.SetupTest() + clientID = testClientID // must be explicitly changed err := tc.malleate() suite.Require().NoError(err) suite.ctx = suite.ctx.WithBlockTime(updateHeader.Header.Time.Add(time.Minute)) - err = suite.keeper.UpdateClient(suite.ctx, testClientID, updateHeader) + err = suite.keeper.UpdateClient(suite.ctx, clientID, updateHeader) if tc.expPass { suite.Require().NoError(err, err) @@ -196,10 +186,10 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { NextValidatorsHash: updateHeader.Header.NextValidatorsHash, } - newClientState, found := suite.keeper.GetClientState(suite.ctx, testClientID) + newClientState, found := suite.keeper.GetClientState(suite.ctx, clientID) suite.Require().True(found, "valid test case %d failed: %s", i, tc.name) - consensusState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, updateHeader.GetHeight()) + consensusState, found := suite.keeper.GetClientConsensusState(suite.ctx, clientID, updateHeader.GetHeight()) suite.Require().True(found, "valid test case %d failed: %s", i, tc.name) // Determine if clientState should be updated or not @@ -399,6 +389,11 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { } func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { + var ( + clientID string + err error + ) + altPrivVal := ibctestingmock.NewPV() altPubKey, err := altPrivVal.GetPubKey() suite.Require().NoError(err) @@ -437,12 +432,12 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { &ibctmtypes.Misbehaviour{ Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, altTime, bothValSet, bothValSet, bothSigners), Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), - ClientId: testClientID, + ClientId: clientID, }, func() error { suite.consensusState.NextValidatorsHash = bothValsHash clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) + clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) return err }, @@ -453,22 +448,22 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { &ibctmtypes.Misbehaviour{ Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), testClientHeight, altTime, bothValSet, valSet, bothSigners), Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners), - ClientId: testClientID, + ClientId: clientID, }, func() error { suite.consensusState.NextValidatorsHash = valsHash clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) + clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) // store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height intermediateConsState := &ibctmtypes.ConsensusState{ Timestamp: suite.now.Add(time.Minute), NextValidatorsHash: suite.valSetHash, } - suite.keeper.SetClientConsensusState(suite.ctx, testClientID, heightPlus3, intermediateConsState) + suite.keeper.SetClientConsensusState(suite.ctx, clientID, heightPlus3, intermediateConsState) clientState.LatestHeight = heightPlus3 - suite.keeper.SetClientState(suite.ctx, testClientID, clientState) + suite.keeper.SetClientState(suite.ctx, clientID, clientState) return err }, @@ -479,22 +474,22 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { &ibctmtypes.Misbehaviour{ Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), testClientHeight, altTime, bothValSet, valSet, bothSigners), Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), - ClientId: testClientID, + ClientId: clientID, }, func() error { suite.consensusState.NextValidatorsHash = valsHash clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) + clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) // store trusted consensus state for Header2 intermediateConsState := &ibctmtypes.ConsensusState{ Timestamp: suite.now.Add(time.Minute), NextValidatorsHash: bothValsHash, } - suite.keeper.SetClientConsensusState(suite.ctx, testClientID, heightPlus3, intermediateConsState) + suite.keeper.SetClientConsensusState(suite.ctx, clientID, heightPlus3, intermediateConsState) clientState.LatestHeight = heightPlus3 - suite.keeper.SetClientState(suite.ctx, testClientID, clientState) + suite.keeper.SetClientState(suite.ctx, clientID, clientState) return err }, @@ -505,12 +500,12 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { &ibctmtypes.Misbehaviour{ Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), heightPlus3, altTime, bothValSet, bothValSet, bothSigners), Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners), - ClientId: testClientID, + ClientId: clientID, }, func() error { suite.consensusState.NextValidatorsHash = valsHash clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) + clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) // intermediate consensus state at height + 3 is not created return err }, @@ -521,12 +516,12 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { &ibctmtypes.Misbehaviour{ Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), testClientHeight, altTime, bothValSet, valSet, bothSigners), Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), - ClientId: testClientID, + ClientId: clientID, }, func() error { suite.consensusState.NextValidatorsHash = valsHash clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) + clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) // intermediate consensus state at height + 3 is not created return err }, @@ -543,15 +538,15 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { &ibctmtypes.Misbehaviour{ Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, altTime, bothValSet, bothValSet, bothSigners), Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), - ClientId: testClientID, + ClientId: clientID, }, func() error { suite.consensusState.NextValidatorsHash = bothValsHash clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) + clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) clientState.FrozenHeight = types.NewHeight(0, 1) - suite.keeper.SetClientState(suite.ctx, testClientID, clientState) + suite.keeper.SetClientState(suite.ctx, clientID, clientState) return err }, @@ -562,14 +557,14 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { &ibctmtypes.Misbehaviour{ Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, altTime, bothValSet, bothValSet, bothSigners), Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners), - ClientId: testClientID, + ClientId: clientID, }, func() error { clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) if err != nil { return err } - err = suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState) + clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) return err }, @@ -580,18 +575,22 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { for i, tc := range testCases { tc := tc i := i + suite.Run(tc.name, func() { - suite.SetupTest() // reset + suite.SetupTest() // reset + clientID = testClientID // must be explicitly changed err := tc.malleate() suite.Require().NoError(err) + tc.misbehaviour.ClientId = clientID + err = suite.keeper.CheckMisbehaviourAndUpdateState(suite.ctx, tc.misbehaviour) if tc.expPass { suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - clientState, found := suite.keeper.GetClientState(suite.ctx, testClientID) + clientState, found := suite.keeper.GetClientState(suite.ctx, clientID) 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(tc.misbehaviour.GetHeight(), clientState.GetFrozenHeight(), diff --git a/x/ibc/core/02-client/keeper/keeper.go b/x/ibc/core/02-client/keeper/keeper.go index accf48bb14c7..18cb4afd68d8 100644 --- a/x/ibc/core/02-client/keeper/keeper.go +++ b/x/ibc/core/02-client/keeper/keeper.go @@ -50,6 +50,16 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", host.ModuleName, types.SubModuleName)) } +// GenerateClientIdentifier returns the next client identifier. +func (k Keeper) GenerateClientIdentifier(ctx sdk.Context, clientType string) string { + nextClientSeq := k.GetNextClientSequence(ctx) + clientID := types.FormatClientIdentifier(clientType, nextClientSeq) + + nextClientSeq++ + k.SetNextClientSequence(ctx, nextClientSeq) + return clientID +} + // GetClientState gets a particular client from the store func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) { store := k.ClientStore(ctx, clientID) @@ -87,6 +97,24 @@ func (k Keeper) SetClientConsensusState(ctx sdk.Context, clientID string, height store.Set(host.ConsensusStateKey(height), k.MustMarshalConsensusState(consensusState)) } +// GetNextClientSequence gets the next client sequence from the store. +func (k Keeper) GetNextClientSequence(ctx sdk.Context) uint64 { + store := ctx.KVStore(k.storeKey) + bz := store.Get([]byte(types.KeyNextClientSequence)) + if bz == nil { + panic("next client sequence is nil") + } + + return sdk.BigEndianToUint64(bz) +} + +// SetNextClientSequence sets the next client sequence to the store. +func (k Keeper) SetNextClientSequence(ctx sdk.Context, sequence uint64) { + store := ctx.KVStore(k.storeKey) + bz := sdk.Uint64ToBigEndian(sequence) + store.Set([]byte(types.KeyNextClientSequence), bz) +} + // IterateConsensusStates provides an iterator over all stored consensus states. // objects. For each State object, cb will be called. If the cb returns true, // the iterator will close and stop. diff --git a/x/ibc/core/02-client/keeper/keeper_test.go b/x/ibc/core/02-client/keeper/keeper_test.go index 45ff4f674e39..ec3c0229ca58 100644 --- a/x/ibc/core/02-client/keeper/keeper_test.go +++ b/x/ibc/core/02-client/keeper/keeper_test.go @@ -30,9 +30,9 @@ const ( testChainID = "gaiahub-0" testChainIDRevision1 = "gaiahub-1" - testClientID = "gaiachain" - testClientID2 = "ethbridge" - testClientID3 = "ethermint" + testClientID = "tendermint-0" + testClientID2 = "tendermint-1" + testClientID3 = "tendermint-2" height = 5 diff --git a/x/ibc/core/02-client/types/client.go b/x/ibc/core/02-client/types/client.go index 305b07cec471..1c44d6e2b9c2 100644 --- a/x/ibc/core/02-client/types/client.go +++ b/x/ibc/core/02-client/types/client.go @@ -2,11 +2,15 @@ package types import ( "fmt" + "math" "sort" + "strings" proto "github.com/gogo/protobuf/proto" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host" "github.com/cosmos/cosmos-sdk/x/ibc/core/exported" ) @@ -80,3 +84,28 @@ func NewConsensusStateWithHeight(height Height, consensusState exported.Consensu func (cswh ConsensusStateWithHeight) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { return unpacker.UnpackAny(cswh.ConsensusState, new(exported.ConsensusState)) } + +// ValidateClientType validates the client type. It cannot be blank or empty. It must be a valid +// client identifier when used with '0' or the maximum uint64 as the sequence. +func ValidateClientType(clientType string) error { + if strings.TrimSpace(clientType) == "" { + return sdkerrors.Wrap(ErrInvalidClientType, "client type cannot be blank") + } + + smallestPossibleClientID := FormatClientIdentifier(clientType, 0) + largestPossibleClientID := FormatClientIdentifier(clientType, math.MaxUint64) + + // IsValidClientID will check client type format and if the sequence is a uint64 + if !IsValidClientID(smallestPossibleClientID) { + return sdkerrors.Wrap(ErrInvalidClientType, "") + } + + if err := host.ClientIdentifierValidator(smallestPossibleClientID); err != nil { + return sdkerrors.Wrap(err, "client type results in smallest client identifier being invalid") + } + if err := host.ClientIdentifierValidator(largestPossibleClientID); err != nil { + return sdkerrors.Wrap(err, "client type results in largest client identifier being invalid") + } + + return nil +} diff --git a/x/ibc/core/02-client/types/client_test.go b/x/ibc/core/02-client/types/client_test.go index 409ab53050aa..2dfd3967d288 100644 --- a/x/ibc/core/02-client/types/client_test.go +++ b/x/ibc/core/02-client/types/client_test.go @@ -1,6 +1,10 @@ package types_test import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/core/exported" ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" @@ -54,3 +58,30 @@ func (suite *TypesTestSuite) TestMarshalConsensusStateWithHeight() { }) } } + +func TestValidateClientType(t *testing.T) { + testCases := []struct { + name string + clientType string + expPass bool + }{ + {"valid", "tendermint", true}, + {"valid solomachine", "solomachine-v1", true}, + {"too large", "tenderminttenderminttenderminttenderminttendermintt", false}, + {"too short", "t", false}, + {"blank id", " ", false}, + {"empty id", "", false}, + {"ends with dash", "tendermint-", false}, + } + + for _, tc := range testCases { + + err := types.ValidateClientType(tc.clientType) + + if tc.expPass { + require.NoError(t, err, tc.name) + } else { + require.Error(t, err, tc.name) + } + } +} diff --git a/x/ibc/core/02-client/types/genesis.go b/x/ibc/core/02-client/types/genesis.go index 4da2f5e92064..f7939c478933 100644 --- a/x/ibc/core/02-client/types/genesis.go +++ b/x/ibc/core/02-client/types/genesis.go @@ -67,23 +67,25 @@ func (ccs ClientConsensusStates) UnpackInterfaces(unpacker codectypes.AnyUnpacke // NewGenesisState creates a GenesisState instance. func NewGenesisState( clients []IdentifiedClientState, clientsConsensus ClientsConsensusStates, - params Params, createLocalhost bool, + params Params, createLocalhost bool, nextClientSequence uint64, ) GenesisState { return GenesisState{ - Clients: clients, - ClientsConsensus: clientsConsensus, - Params: params, - CreateLocalhost: createLocalhost, + Clients: clients, + ClientsConsensus: clientsConsensus, + Params: params, + CreateLocalhost: createLocalhost, + NextClientSequence: nextClientSequence, } } // DefaultGenesisState returns the ibc client submodule's default genesis state. func DefaultGenesisState() GenesisState { return GenesisState{ - Clients: []IdentifiedClientState{}, - ClientsConsensus: ClientsConsensusStates{}, - Params: DefaultParams(), - CreateLocalhost: false, + Clients: []IdentifiedClientState{}, + ClientsConsensus: ClientsConsensusStates{}, + Params: DefaultParams(), + CreateLocalhost: false, + NextClientSequence: 0, } } diff --git a/x/ibc/core/02-client/types/genesis.pb.go b/x/ibc/core/02-client/types/genesis.pb.go index 4c72edfe5e75..becfa1baba15 100644 --- a/x/ibc/core/02-client/types/genesis.pb.go +++ b/x/ibc/core/02-client/types/genesis.pb.go @@ -32,6 +32,8 @@ type GenesisState struct { Params Params `protobuf:"bytes,3,opt,name=params,proto3" json:"params"` // create localhost on initialization CreateLocalhost bool `protobuf:"varint,4,opt,name=create_localhost,json=createLocalhost,proto3" json:"create_localhost,omitempty" yaml:"create_localhost"` + // the sequence for the next generated client identifier + NextClientSequence uint64 `protobuf:"varint,5,opt,name=next_client_sequence,json=nextClientSequence,proto3" json:"next_client_sequence,omitempty" yaml:"next_client_sequence"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -95,6 +97,13 @@ func (m *GenesisState) GetCreateLocalhost() bool { return false } +func (m *GenesisState) GetNextClientSequence() uint64 { + if m != nil { + return m.NextClientSequence + } + return 0 +} + func init() { proto.RegisterType((*GenesisState)(nil), "ibc.core.client.v1.GenesisState") } @@ -102,30 +111,32 @@ func init() { func init() { proto.RegisterFile("ibc/core/client/v1/genesis.proto", fileDescriptor_bcd0c0f1f2e6a91a) } var fileDescriptor_bcd0c0f1f2e6a91a = []byte{ - // 362 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xc1, 0x4e, 0xea, 0x40, - 0x14, 0x86, 0xdb, 0x0b, 0xe1, 0xde, 0x94, 0x9b, 0x88, 0x8d, 0xd1, 0x06, 0x93, 0xb6, 0xe9, 0x0a, - 0x17, 0xcc, 0x08, 0x2e, 0x34, 0x2c, 0x4b, 0xa2, 0x31, 0x71, 0xa1, 0x75, 0xe7, 0x86, 0xb4, 0xc3, - 0x58, 0x26, 0xb6, 0x1d, 0xd2, 0x33, 0x10, 0x79, 0x05, 0x57, 0xc6, 0xc7, 0xf0, 0x49, 0x58, 0xb2, - 0x74, 0x85, 0x06, 0xde, 0x80, 0x27, 0x30, 0xed, 0x14, 0x17, 0x80, 0xab, 0x39, 0xf9, 0xe7, 0xff, - 0xfe, 0xff, 0x24, 0x47, 0xb3, 0x59, 0x40, 0x30, 0xe1, 0x29, 0xc5, 0x24, 0x62, 0x34, 0x11, 0x78, - 0xdc, 0xc2, 0x21, 0x4d, 0x28, 0x30, 0x40, 0xc3, 0x94, 0x0b, 0xae, 0xeb, 0x2c, 0x20, 0x28, 0x73, - 0x20, 0xe9, 0x40, 0xe3, 0x56, 0xdd, 0xda, 0x41, 0x15, 0xbf, 0x39, 0x54, 0x3f, 0x08, 0x79, 0xc8, - 0xf3, 0x11, 0x67, 0x93, 0x54, 0x9d, 0x97, 0x92, 0xf6, 0xff, 0x4a, 0x86, 0xdf, 0x0b, 0x5f, 0x50, - 0x9d, 0x68, 0x7f, 0x25, 0x06, 0x86, 0x6a, 0x97, 0x1a, 0xd5, 0xf6, 0x09, 0xda, 0x6e, 0x43, 0xd7, - 0x7d, 0x9a, 0x08, 0xf6, 0xc8, 0x68, 0xbf, 0x9b, 0x6b, 0x39, 0xeb, 0x9a, 0xd3, 0xb9, 0xa5, 0xbc, - 0x7f, 0x5a, 0x87, 0x3b, 0xbf, 0xc1, 0x5b, 0x27, 0xeb, 0x6f, 0xaa, 0xb6, 0x5f, 0xcc, 0x3d, 0xc2, - 0x13, 0xa0, 0x09, 0x8c, 0xc0, 0xf8, 0xf3, 0x7b, 0x9f, 0x8c, 0xe9, 0xae, 0xad, 0x32, 0xcf, 0xed, - 0x64, 0x7d, 0xab, 0xb9, 0x65, 0x4c, 0xfc, 0x38, 0xea, 0x38, 0x5b, 0x89, 0x4e, 0xb6, 0x8b, 0x44, - 0x61, 0x83, 0xf5, 0x6a, 0x64, 0x43, 0xd7, 0x2f, 0xb4, 0xca, 0xd0, 0x4f, 0xfd, 0x18, 0x8c, 0x92, - 0xad, 0x36, 0xaa, 0xed, 0xfa, 0xae, 0x45, 0x6e, 0x73, 0x87, 0x5b, 0xce, 0x9a, 0xbd, 0xc2, 0xaf, - 0x5f, 0x6a, 0x35, 0x92, 0x52, 0x5f, 0xd0, 0x5e, 0xc4, 0x89, 0x1f, 0x0d, 0x38, 0x08, 0xa3, 0x6c, - 0xab, 0x8d, 0x7f, 0xee, 0xf1, 0x6a, 0x6e, 0x1d, 0x15, 0xdb, 0x6d, 0x38, 0x1c, 0x6f, 0x4f, 0x4a, - 0x37, 0x6b, 0xc5, 0xbd, 0x9b, 0x2e, 0x4c, 0x75, 0xb6, 0x30, 0xd5, 0xaf, 0x85, 0xa9, 0xbe, 0x2e, - 0x4d, 0x65, 0xb6, 0x34, 0x95, 0x8f, 0xa5, 0xa9, 0x3c, 0x9c, 0x87, 0x4c, 0x0c, 0x46, 0x01, 0x22, - 0x3c, 0xc6, 0x84, 0x43, 0xcc, 0xa1, 0x78, 0x9a, 0xd0, 0x7f, 0xc2, 0xcf, 0xf8, 0xe7, 0xf8, 0xa7, - 0xed, 0x66, 0x71, 0x7f, 0x31, 0x19, 0x52, 0x08, 0x2a, 0xf9, 0x99, 0xcf, 0xbe, 0x03, 0x00, 0x00, - 0xff, 0xff, 0x8d, 0xa4, 0x74, 0xd6, 0x55, 0x02, 0x00, 0x00, + // 400 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x8e, 0x9a, 0x40, + 0x1c, 0xc6, 0x99, 0x6a, 0x6d, 0x83, 0x4d, 0x6a, 0x27, 0xa6, 0x25, 0x9a, 0x00, 0xe1, 0x44, 0x0f, + 0x32, 0xd5, 0x1e, 0xda, 0x78, 0xc4, 0xa4, 0x4d, 0x93, 0x1e, 0x2a, 0xbd, 0xf5, 0x42, 0x60, 0x9c, + 0x22, 0x29, 0x30, 0x96, 0x19, 0x8d, 0xbe, 0xc5, 0x66, 0x1f, 0x63, 0x9f, 0xc4, 0xa3, 0xc7, 0xbd, + 0x2c, 0xbb, 0xd1, 0x37, 0xf0, 0x09, 0x36, 0x30, 0xe3, 0x1e, 0x94, 0x3d, 0xf1, 0xcf, 0x37, 0xbf, + 0xef, 0xfb, 0xfe, 0x21, 0x7f, 0xd5, 0x8c, 0x43, 0x8c, 0x30, 0xcd, 0x09, 0xc2, 0x49, 0x4c, 0x32, + 0x8e, 0x56, 0x43, 0x14, 0x91, 0x8c, 0xb0, 0x98, 0x39, 0x8b, 0x9c, 0x72, 0x0a, 0x61, 0x1c, 0x62, + 0xa7, 0x24, 0x1c, 0x41, 0x38, 0xab, 0x61, 0xcf, 0xa8, 0x71, 0xc9, 0xd7, 0xca, 0xd4, 0xeb, 0x46, + 0x34, 0xa2, 0xd5, 0x88, 0xca, 0x49, 0xa8, 0xd6, 0x5d, 0x43, 0x7d, 0xf3, 0x5d, 0x84, 0xff, 0xe6, + 0x01, 0x27, 0x10, 0xab, 0xaf, 0x84, 0x8d, 0x69, 0xc0, 0x6c, 0xd8, 0xed, 0xd1, 0x47, 0xe7, 0xb2, + 0xcd, 0xf9, 0x31, 0x23, 0x19, 0x8f, 0xff, 0xc6, 0x64, 0x36, 0xa9, 0xb4, 0xca, 0xeb, 0xea, 0xdb, + 0xc2, 0x50, 0x6e, 0xee, 0x8d, 0xf7, 0xb5, 0xcf, 0xcc, 0x3b, 0x25, 0xc3, 0x6b, 0xa0, 0xbe, 0x93, + 0xb3, 0x8f, 0x69, 0xc6, 0x48, 0xc6, 0x96, 0x4c, 0x7b, 0xf1, 0x7c, 0x9f, 0x88, 0x99, 0x9c, 0x50, + 0x91, 0xe7, 0x8e, 0xcb, 0xbe, 0x63, 0x61, 0x68, 0x9b, 0x20, 0x4d, 0xc6, 0xd6, 0x45, 0xa2, 0x55, + 0xee, 0x22, 0xac, 0xec, 0xcc, 0xeb, 0x75, 0xf0, 0x99, 0x0e, 0xbf, 0xaa, 0xad, 0x45, 0x90, 0x07, + 0x29, 0xd3, 0x1a, 0x26, 0xb0, 0xdb, 0xa3, 0x5e, 0xdd, 0x22, 0xbf, 0x2a, 0xc2, 0x6d, 0x96, 0xcd, + 0x9e, 0xe4, 0xe1, 0x37, 0xb5, 0x83, 0x73, 0x12, 0x70, 0xe2, 0x27, 0x14, 0x07, 0xc9, 0x9c, 0x32, + 0xae, 0x35, 0x4d, 0x60, 0xbf, 0x76, 0xfb, 0xc7, 0xc2, 0xf8, 0x20, 0xb7, 0x3b, 0x23, 0x2c, 0xef, + 0xad, 0x90, 0x7e, 0x9e, 0x14, 0x38, 0x55, 0xbb, 0x19, 0x59, 0x73, 0x5f, 0xd4, 0xf9, 0x8c, 0xfc, + 0x5f, 0x92, 0x0c, 0x13, 0xed, 0xa5, 0x09, 0xec, 0xa6, 0x6b, 0x1c, 0x0b, 0xa3, 0x2f, 0xb2, 0xea, + 0x28, 0xcb, 0x83, 0xa5, 0x2c, 0x7f, 0xb8, 0x14, 0xdd, 0xe9, 0x76, 0xaf, 0x83, 0xdd, 0x5e, 0x07, + 0x0f, 0x7b, 0x1d, 0x5c, 0x1d, 0x74, 0x65, 0x77, 0xd0, 0x95, 0xdb, 0x83, 0xae, 0xfc, 0xf9, 0x12, + 0xc5, 0x7c, 0xbe, 0x0c, 0x1d, 0x4c, 0x53, 0x84, 0x29, 0x4b, 0x29, 0x93, 0x9f, 0x01, 0x9b, 0xfd, + 0x43, 0x6b, 0xf4, 0x74, 0x4f, 0x9f, 0x46, 0x03, 0x79, 0x52, 0x7c, 0xb3, 0x20, 0x2c, 0x6c, 0x55, + 0x97, 0xf3, 0xf9, 0x31, 0x00, 0x00, 0xff, 0xff, 0x7c, 0xcd, 0xe7, 0x85, 0xa8, 0x02, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -148,6 +159,11 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.NextClientSequence != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.NextClientSequence)) + i-- + dAtA[i] = 0x28 + } if m.CreateLocalhost { i-- if m.CreateLocalhost { @@ -233,6 +249,9 @@ func (m *GenesisState) Size() (n int) { if m.CreateLocalhost { n += 2 } + if m.NextClientSequence != 0 { + n += 1 + sovGenesis(uint64(m.NextClientSequence)) + } return n } @@ -392,6 +411,25 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } } m.CreateLocalhost = bool(v != 0) + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NextClientSequence", wireType) + } + m.NextClientSequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NextClientSequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/ibc/core/02-client/types/genesis_test.go b/x/ibc/core/02-client/types/genesis_test.go index 7d131bae6192..81eff78335de 100644 --- a/x/ibc/core/02-client/types/genesis_test.go +++ b/x/ibc/core/02-client/types/genesis_test.go @@ -90,6 +90,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, types.NewParams(exported.Tendermint, exported.Localhost), false, + 0, ), expPass: true, }, @@ -119,6 +120,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, types.NewParams(exported.Tendermint), false, + 0, ), expPass: false, }, @@ -134,6 +136,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { nil, types.NewParams(exported.Tendermint), false, + 0, ), expPass: false, }, @@ -163,6 +166,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, types.NewParams(exported.Tendermint), false, + 0, ), expPass: false, }, @@ -192,6 +196,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, types.NewParams(exported.Tendermint), false, + 0, ), expPass: false, }, @@ -221,6 +226,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, types.NewParams(exported.Tendermint), false, + 0, ), expPass: false, }, @@ -250,6 +256,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, types.NewParams(exported.Solomachine), false, + 0, ), expPass: false, }, @@ -279,6 +286,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, types.NewParams(" "), false, + 0, ), expPass: false, }, @@ -308,6 +316,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, types.NewParams(" "), true, + 0, ), expPass: false, }, @@ -337,6 +346,7 @@ func (suite *TypesTestSuite) TestValidateGenesis() { }, types.NewParams(exported.Tendermint), true, + 0, ), expPass: false, }, diff --git a/x/ibc/core/02-client/types/height.go b/x/ibc/core/02-client/types/height.go index d507ddea8c80..9ac6fec75592 100644 --- a/x/ibc/core/02-client/types/height.go +++ b/x/ibc/core/02-client/types/height.go @@ -17,7 +17,7 @@ var _ exported.Height = (*Height)(nil) // IsRevisionFormat checks if a chainID is in the format required for parsing revisions // The chainID must be in the form: `{chainID}-{revision} // 24-host may enforce stricter checks on chainID -var IsRevisionFormat = regexp.MustCompile(`^.+[^-]-{1}[1-9][0-9]*$`).MatchString +var IsRevisionFormat = regexp.MustCompile(`^.*[^-]-{1}[1-9][0-9]*$`).MatchString // ZeroHeight is a helper function which returns an uninitialized height. func ZeroHeight() Height { diff --git a/x/ibc/core/02-client/types/height_test.go b/x/ibc/core/02-client/types/height_test.go index f2615c8c1d77..a455b7f58d49 100644 --- a/x/ibc/core/02-client/types/height_test.go +++ b/x/ibc/core/02-client/types/height_test.go @@ -104,6 +104,7 @@ func TestParseChainID(t *testing.T) { formatted bool }{ {"gaiamainnet-3", 3, true}, + {"a-1", 1, true}, {"gaia-mainnet-40", 40, true}, {"gaiamainnet-3-39", 39, true}, {"gaiamainnet--", 0, false}, @@ -111,10 +112,13 @@ func TestParseChainID(t *testing.T) { {"gaiamainnet--4", 0, false}, {"gaiamainnet-3.4", 0, false}, {"gaiamainnet", 0, false}, + {"a--1", 0, false}, + {"-1", 0, false}, + {"--1", 0, false}, } for i, tc := range cases { - require.Equal(t, tc.formatted, types.IsRevisionFormat(tc.chainID), "case %d does not match expected format", i) + require.Equal(t, tc.formatted, types.IsRevisionFormat(tc.chainID), "id %s does not match expected format", tc.chainID) revision := types.ParseChainID(tc.chainID) require.Equal(t, tc.revision, revision, "case %d returns incorrect revision", i) diff --git a/x/ibc/core/02-client/types/keys.go b/x/ibc/core/02-client/types/keys.go index f360393335d5..321f5e3ffa3c 100644 --- a/x/ibc/core/02-client/types/keys.go +++ b/x/ibc/core/02-client/types/keys.go @@ -1,5 +1,15 @@ package types +import ( + "fmt" + "regexp" + "strconv" + "strings" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host" +) + const ( // SubModuleName defines the IBC client name SubModuleName string = "client" @@ -9,4 +19,47 @@ const ( // QuerierRoute is the querier route for IBC client QuerierRoute string = SubModuleName + + // KeyNextClientSequence is the key used to store the next client sequence in + // the keeper. + KeyNextClientSequence = "nextClientSequence" ) + +// FormatClientIdentifier returns the client identifier with the sequence appended. +// This is a SDK specific format not enforced by IBC protocol. +func FormatClientIdentifier(clientType string, sequence uint64) string { + return fmt.Sprintf("%s-%d", clientType, sequence) +} + +// IsClientIDFormat checks if a clientID is in the format required on the SDK for +// parsing client identifiers. The client identifier must be in the form: `{client-type}-{N} +var IsClientIDFormat = regexp.MustCompile(`^.*[^-]-[0-9]{1,20}$`).MatchString + +// IsValidClientID checks if the clientID is valid and can be parsed into the client +// identifier format. +func IsValidClientID(clientID string) bool { + _, _, err := ParseClientIdentifier(clientID) + return err == nil +} + +// ParseClientIdentifier parses the client type and sequence from the client identifier. +func ParseClientIdentifier(clientID string) (string, uint64, error) { + if !IsClientIDFormat(clientID) { + return "", 0, sdkerrors.Wrapf(host.ErrInvalidID, "invalid client identifier %s is not in format: `{client-type}-{N}`", clientID) + } + + splitStr := strings.Split(clientID, "-") + lastIndex := len(splitStr) - 1 + + clientType := strings.Join(splitStr[:lastIndex], "-") + if strings.TrimSpace(clientType) == "" { + return "", 0, sdkerrors.Wrap(host.ErrInvalidID, "client identifier must be in format: `{client-type}-{N}` and client type cannot be blank") + } + + sequence, err := strconv.ParseUint(splitStr[lastIndex], 10, 64) + if err != nil { + return "", 0, sdkerrors.Wrap(err, "failed to parse client identifier sequence") + } + + return clientType, sequence, nil +} diff --git a/x/ibc/core/02-client/types/keys_test.go b/x/ibc/core/02-client/types/keys_test.go new file mode 100644 index 000000000000..dbe56657ad84 --- /dev/null +++ b/x/ibc/core/02-client/types/keys_test.go @@ -0,0 +1,53 @@ +package types_test + +import ( + "math" + "testing" + + "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types" + "github.com/stretchr/testify/require" +) + +// tests ParseClientIdentifier and IsValidClientID +func TestParseClientIdentifier(t *testing.T) { + testCases := []struct { + name string + clientID string + clientType string + expSeq uint64 + expPass bool + }{ + {"valid 0", "tendermint-0", "tendermint", 0, true}, + {"valid 1", "tendermint-1", "tendermint", 1, true}, + {"valid solemachine", "solomachine-v1-1", "solomachine-v1", 1, true}, + {"valid large sequence", types.FormatClientIdentifier("tendermint", math.MaxUint64), "tendermint", math.MaxUint64, true}, + {"valid short client type", "t-0", "t", 0, true}, + // one above uint64 max + {"invalid uint64", "tendermint-18446744073709551616", "tendermint", 0, false}, + // uint64 == 20 characters + {"invalid large sequence", "tendermint-2345682193567182931243", "tendermint", 0, false}, + {"missing dash", "tendermint0", "tendermint", 0, false}, + {"blank id", " ", " ", 0, false}, + {"empty id", "", "", 0, false}, + {"negative sequence", "tendermint--1", "tendermint", 0, false}, + {"invalid format", "tendermint-tm", "tendermint", 0, false}, + {"empty clientype", " -100", "tendermint", 0, false}, + } + + for _, tc := range testCases { + + clientType, seq, err := types.ParseClientIdentifier(tc.clientID) + valid := types.IsValidClientID(tc.clientID) + require.Equal(t, tc.expSeq, seq, tc.clientID) + + if tc.expPass { + require.NoError(t, err, tc.name) + require.True(t, valid) + require.Equal(t, tc.clientType, clientType) + } else { + require.Error(t, err, tc.name, tc.clientID) + require.False(t, valid) + require.Equal(t, "", clientType) + } + } +} diff --git a/x/ibc/core/02-client/types/msgs.go b/x/ibc/core/02-client/types/msgs.go index d1d084ddadd3..1e884123d74b 100644 --- a/x/ibc/core/02-client/types/msgs.go +++ b/x/ibc/core/02-client/types/msgs.go @@ -31,7 +31,7 @@ var ( // NewMsgCreateClient creates a new MsgCreateClient instance //nolint:interfacer func NewMsgCreateClient( - id string, clientState exported.ClientState, consensusState exported.ConsensusState, signer sdk.AccAddress, + clientState exported.ClientState, consensusState exported.ConsensusState, signer sdk.AccAddress, ) (*MsgCreateClient, error) { anyClientState, err := PackClientState(clientState) @@ -45,7 +45,6 @@ func NewMsgCreateClient( } return &MsgCreateClient{ - ClientId: id, ClientState: anyClientState, ConsensusState: anyConsensusState, Signer: signer.String(), @@ -75,17 +74,20 @@ func (msg MsgCreateClient) ValidateBasic() error { if err := clientState.Validate(); err != nil { return err } - if clientState.ClientType() == exported.Localhost || msg.ClientId == exported.Localhost { + if clientState.ClientType() == exported.Localhost { return sdkerrors.Wrap(ErrInvalidClient, "localhost client can only be created on chain initialization") } consensusState, err := UnpackConsensusState(msg.ConsensusState) if err != nil { return err } - if err := consensusState.ValidateBasic(); err != nil { - return err + if clientState.ClientType() != consensusState.ClientType() { + return sdkerrors.Wrap(ErrInvalidClientType, "client type for client state and consensus state do not match") } - return host.ClientIdentifierValidator(msg.ClientId) + if err := ValidateClientType(clientState.ClientType()); err != nil { + return sdkerrors.Wrap(err, "client type does not meet naming constraints") + } + return consensusState.ValidateBasic() } // GetSignBytes implements sdk.Msg. The function will panic since it is used diff --git a/x/ibc/core/02-client/types/msgs_test.go b/x/ibc/core/02-client/types/msgs_test.go index 7d2da65d2cdd..e42725bae26f 100644 --- a/x/ibc/core/02-client/types/msgs_test.go +++ b/x/ibc/core/02-client/types/msgs_test.go @@ -12,7 +12,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/core/exported" solomachinetypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine/types" ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/09-localhost/types" ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" ) @@ -50,14 +49,14 @@ func (suite *TypesTestSuite) TestMarshalMsgCreateClient() { { "solo machine client", func() { soloMachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2) - msg, err = types.NewMsgCreateClient(soloMachine.ClientID, soloMachine.ClientState(), soloMachine.ConsensusState(), suite.chainA.SenderAccount.GetAddress()) + msg, err = types.NewMsgCreateClient(soloMachine.ClientState(), soloMachine.ConsensusState(), suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) }, }, { "tendermint client", func() { tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - msg, err = types.NewMsgCreateClient("tendermint", tendermintClient, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress()) + msg, err = types.NewMsgCreateClient(tendermintClient, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) }, }, @@ -98,18 +97,11 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { malleate func() expPass bool }{ - { - "invalid client-id", - func() { - msg.ClientId = "" - }, - false, - }, { "valid - tendermint client", func() { tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - msg, err = types.NewMsgCreateClient("tendermint", tendermintClient, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress()) + msg, err = types.NewMsgCreateClient(tendermintClient, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) }, true, @@ -117,7 +109,7 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { { "invalid tendermint client", func() { - msg, err = types.NewMsgCreateClient("tendermint", &ibctmtypes.ClientState{}, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress()) + msg, err = types.NewMsgCreateClient(&ibctmtypes.ClientState{}, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) }, false, @@ -133,7 +125,7 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { "failed to unpack consensus state", func() { tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) - msg, err = types.NewMsgCreateClient("tendermint", tendermintClient, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress()) + msg, err = types.NewMsgCreateClient(tendermintClient, suite.chainA.CurrentTMClientHeader().ConsensusState(), suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) msg.ConsensusState = nil }, @@ -150,7 +142,7 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { "valid - solomachine client", func() { soloMachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2) - msg, err = types.NewMsgCreateClient(soloMachine.ClientID, soloMachine.ClientState(), soloMachine.ConsensusState(), suite.chainA.SenderAccount.GetAddress()) + msg, err = types.NewMsgCreateClient(soloMachine.ClientState(), soloMachine.ConsensusState(), suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) }, true, @@ -159,7 +151,7 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { "invalid solomachine client", func() { soloMachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2) - msg, err = types.NewMsgCreateClient(soloMachine.ClientID, &solomachinetypes.ClientState{}, soloMachine.ConsensusState(), suite.chainA.SenderAccount.GetAddress()) + msg, err = types.NewMsgCreateClient(&solomachinetypes.ClientState{}, soloMachine.ConsensusState(), suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) }, false, @@ -168,16 +160,17 @@ func (suite *TypesTestSuite) TestMsgCreateClient_ValidateBasic() { "invalid solomachine consensus state", func() { soloMachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2) - msg, err = types.NewMsgCreateClient(soloMachine.ClientID, soloMachine.ClientState(), &solomachinetypes.ConsensusState{}, suite.chainA.SenderAccount.GetAddress()) + msg, err = types.NewMsgCreateClient(soloMachine.ClientState(), &solomachinetypes.ConsensusState{}, suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) }, false, }, { - "unsupported - localhost client", + "invalid - client state and consensus state client types do not match", func() { - localhostClient := localhosttypes.NewClientState(suite.chainA.ChainID, types.NewHeight(0, uint64(suite.chainA.LastHeader.Header.Height))) - msg, err = types.NewMsgCreateClient("localhost", localhostClient, suite.chainA.LastHeader.ConsensusState(), suite.chainA.SenderAccount.GetAddress()) + tendermintClient := ibctmtypes.NewClientState(suite.chainA.ChainID, ibctesting.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) + soloMachine := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, "solomachine", "", 2) + msg, err = types.NewMsgCreateClient(tendermintClient, soloMachine.ConsensusState(), suite.chainA.SenderAccount.GetAddress()) suite.Require().NoError(err) }, false, diff --git a/x/ibc/core/02-client/types/tx.pb.go b/x/ibc/core/02-client/types/tx.pb.go index 2a1a6b8885ca..b0bf22d0cc11 100644 --- a/x/ibc/core/02-client/types/tx.pb.go +++ b/x/ibc/core/02-client/types/tx.pb.go @@ -31,15 +31,13 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // MsgCreateClient defines a message to create an IBC client type MsgCreateClient struct { - // client unique identifier - ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` // light client state - ClientState *types.Any `protobuf:"bytes,2,opt,name=client_state,json=clientState,proto3" json:"client_state,omitempty" yaml:"client_state"` + ClientState *types.Any `protobuf:"bytes,1,opt,name=client_state,json=clientState,proto3" json:"client_state,omitempty" yaml:"client_state"` // consensus state associated with the client that corresponds to a given // height. - ConsensusState *types.Any `protobuf:"bytes,3,opt,name=consensus_state,json=consensusState,proto3" json:"consensus_state,omitempty" yaml:"consensus_state"` + ConsensusState *types.Any `protobuf:"bytes,2,opt,name=consensus_state,json=consensusState,proto3" json:"consensus_state,omitempty" yaml:"consensus_state"` // signer address - Signer string `protobuf:"bytes,4,opt,name=signer,proto3" json:"signer,omitempty"` + Signer string `protobuf:"bytes,3,opt,name=signer,proto3" json:"signer,omitempty"` } func (m *MsgCreateClient) Reset() { *m = MsgCreateClient{} } @@ -374,45 +372,45 @@ func init() { func init() { proto.RegisterFile("ibc/core/client/v1/tx.proto", fileDescriptor_cb5dc4651eb49a04) } var fileDescriptor_cb5dc4651eb49a04 = []byte{ - // 598 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x55, 0x3f, 0x6f, 0xd3, 0x4e, - 0x18, 0x8e, 0x9b, 0xdf, 0x2f, 0x6a, 0xaf, 0x81, 0x56, 0x26, 0xb4, 0xa9, 0xab, 0xda, 0x95, 0xe9, - 0x10, 0x44, 0xeb, 0x23, 0x61, 0x00, 0x75, 0x23, 0x9d, 0x18, 0x22, 0x51, 0x57, 0x0c, 0xb0, 0x04, - 0xff, 0xb9, 0x5e, 0xac, 0x26, 0xbe, 0xc8, 0x67, 0x47, 0xcd, 0x37, 0x60, 0x44, 0x82, 0x0f, 0x50, - 0x31, 0xf0, 0x59, 0x18, 0x3b, 0x30, 0x30, 0x45, 0x28, 0x59, 0x98, 0xf3, 0x09, 0x90, 0xef, 0x1c, - 0xcb, 0x76, 0xed, 0x28, 0x82, 0x91, 0xc9, 0x7e, 0xef, 0x7d, 0xee, 0x79, 0x9e, 0x7b, 0xdf, 0xf7, - 0x6c, 0xb0, 0xef, 0x98, 0x16, 0xb4, 0x88, 0x87, 0xa0, 0xd5, 0x77, 0x90, 0xeb, 0xc3, 0x51, 0x13, - 0xfa, 0xd7, 0xda, 0xd0, 0x23, 0x3e, 0x11, 0x45, 0xc7, 0xb4, 0xb4, 0x30, 0xa9, 0xf1, 0xa4, 0x36, - 0x6a, 0x4a, 0x35, 0x4c, 0x30, 0x61, 0x69, 0x18, 0xbe, 0x71, 0xa4, 0xb4, 0x87, 0x09, 0xc1, 0x7d, - 0x04, 0x59, 0x64, 0x06, 0x97, 0xd0, 0x70, 0xc7, 0x51, 0x4a, 0xc9, 0x51, 0x88, 0xe8, 0x18, 0x40, - 0xfd, 0xb4, 0x06, 0xb6, 0x3a, 0x14, 0x9f, 0x79, 0xc8, 0xf0, 0xd1, 0x19, 0xcb, 0x88, 0x4d, 0xb0, - 0xc1, 0x31, 0x5d, 0xc7, 0xae, 0x0b, 0x87, 0x42, 0x63, 0xa3, 0x5d, 0x9b, 0x4f, 0x94, 0xed, 0xb1, - 0x31, 0xe8, 0x9f, 0xaa, 0x71, 0x4a, 0xd5, 0xd7, 0xf9, 0xfb, 0x2b, 0x5b, 0x7c, 0x0d, 0xaa, 0xd1, - 0x3a, 0xf5, 0x0d, 0x1f, 0xd5, 0xd7, 0x0e, 0x85, 0xc6, 0x66, 0xab, 0xa6, 0x71, 0x67, 0xda, 0xc2, - 0x99, 0xf6, 0xd2, 0x1d, 0xb7, 0x77, 0xe7, 0x13, 0xe5, 0x41, 0x8a, 0x8b, 0xed, 0x51, 0xf5, 0x4d, - 0x1e, 0x5e, 0x84, 0x91, 0xf8, 0x16, 0x6c, 0x59, 0xc4, 0xa5, 0xc8, 0xa5, 0x01, 0x8d, 0x48, 0xcb, - 0x4b, 0x48, 0xa5, 0xf9, 0x44, 0xd9, 0x89, 0x48, 0xd3, 0xdb, 0x54, 0xfd, 0x7e, 0xbc, 0xc2, 0xa9, - 0x77, 0x40, 0x85, 0x3a, 0xd8, 0x45, 0x5e, 0xfd, 0xbf, 0xf0, 0x70, 0x7a, 0x14, 0x9d, 0xae, 0x7f, - 0xb8, 0x51, 0x4a, 0xbf, 0x6e, 0x94, 0x92, 0xba, 0x07, 0x76, 0x33, 0x45, 0xd1, 0x11, 0x1d, 0x86, - 0x2c, 0xea, 0x67, 0x81, 0x15, 0xec, 0xcd, 0xd0, 0xfe, 0xab, 0x82, 0x1d, 0x83, 0x4a, 0x0f, 0x19, - 0x36, 0xf2, 0x96, 0x95, 0x4a, 0x8f, 0x30, 0x09, 0xc7, 0xe5, 0xa5, 0x8e, 0x93, 0xae, 0x62, 0xc7, - 0xdf, 0xcb, 0x60, 0x9b, 0xe5, 0xb0, 0x67, 0xd8, 0xff, 0x4a, 0x8f, 0xcf, 0x41, 0x6d, 0xe8, 0x11, - 0x72, 0xd9, 0x0d, 0xf8, 0xb1, 0xbb, 0x5c, 0x97, 0x75, 0xbc, 0xda, 0x56, 0xe6, 0x13, 0x65, 0x9f, - 0x33, 0xe5, 0xa1, 0x54, 0x5d, 0x64, 0xcb, 0xe9, 0x92, 0x5d, 0x81, 0x83, 0x0c, 0x38, 0xe3, 0xfd, - 0x7f, 0xc6, 0xdd, 0x98, 0x4f, 0x94, 0xa3, 0x5c, 0xee, 0xac, 0x67, 0x29, 0x25, 0x52, 0x34, 0xa3, - 0x95, 0x82, 0x8e, 0x4b, 0xa0, 0x9e, 0xed, 0x6a, 0xdc, 0xf2, 0xaf, 0x02, 0x78, 0xd8, 0xa1, 0xf8, - 0x22, 0x30, 0x07, 0x8e, 0xdf, 0x71, 0xa8, 0x89, 0x7a, 0xc6, 0xc8, 0x21, 0x81, 0xf7, 0x27, 0x7d, - 0x7f, 0x01, 0xaa, 0x83, 0x04, 0xc5, 0xd2, 0x81, 0x4d, 0x21, 0x57, 0x18, 0x5b, 0x05, 0x1c, 0xe4, - 0xfa, 0x5c, 0x9c, 0xa4, 0xf5, 0xa5, 0x0c, 0xca, 0x1d, 0x8a, 0xc5, 0xf7, 0xa0, 0x9a, 0xfa, 0x46, - 0x3d, 0xd2, 0xee, 0x7e, 0x1e, 0xb5, 0xcc, 0x9d, 0x95, 0x9e, 0xac, 0x00, 0x5a, 0x28, 0x85, 0x0a, - 0xa9, 0x4b, 0x5d, 0xa4, 0x90, 0x04, 0x15, 0x2a, 0xe4, 0x5d, 0x44, 0xd1, 0x02, 0xf7, 0xd2, 0x13, - 0x75, 0x54, 0xb8, 0x3b, 0x81, 0x92, 0x8e, 0x57, 0x41, 0xc5, 0x22, 0x1e, 0x10, 0x73, 0xda, 0xfe, - 0xb8, 0x80, 0xe3, 0x2e, 0x54, 0x6a, 0xae, 0x0c, 0x5d, 0x68, 0xb6, 0xcf, 0xbf, 0x4d, 0x65, 0xe1, - 0x76, 0x2a, 0x0b, 0x3f, 0xa7, 0xb2, 0xf0, 0x71, 0x26, 0x97, 0x6e, 0x67, 0x72, 0xe9, 0xc7, 0x4c, - 0x2e, 0xbd, 0x7b, 0x8e, 0x1d, 0xbf, 0x17, 0x98, 0x9a, 0x45, 0x06, 0xd0, 0x22, 0x74, 0x40, 0x68, - 0xf4, 0x38, 0xa1, 0xf6, 0x15, 0xbc, 0x86, 0xf1, 0xef, 0xe9, 0x69, 0xeb, 0x24, 0xfa, 0x43, 0xf9, - 0xe3, 0x21, 0xa2, 0x66, 0x85, 0x8d, 0xd5, 0xb3, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd2, 0x19, - 0x59, 0x52, 0x23, 0x07, 0x00, 0x00, + // 601 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x3f, 0x6f, 0xd3, 0x40, + 0x1c, 0x8d, 0x1b, 0x88, 0x9a, 0x6b, 0xa0, 0x95, 0x09, 0x6d, 0xea, 0xaa, 0x76, 0x64, 0x3a, 0x04, + 0xd1, 0xfa, 0x48, 0x18, 0x40, 0xdd, 0x48, 0x27, 0x86, 0x48, 0xd4, 0x15, 0x03, 0x2c, 0xc1, 0x7f, + 0xae, 0x97, 0x53, 0x13, 0x5f, 0xe4, 0xb3, 0xa3, 0xe6, 0x1b, 0x30, 0x32, 0xf0, 0x01, 0x2a, 0x06, + 0x3e, 0x0b, 0x63, 0x07, 0x06, 0xa6, 0xa8, 0x4a, 0x16, 0xe6, 0x7c, 0x02, 0x14, 0x9f, 0x13, 0x62, + 0xd7, 0x8e, 0x2c, 0xa0, 0x53, 0x7c, 0xfe, 0xbd, 0x7b, 0xef, 0xf7, 0xf2, 0x7e, 0xe7, 0x03, 0x7b, + 0xc4, 0xb4, 0xa0, 0x45, 0x5d, 0x04, 0xad, 0x2e, 0x41, 0x8e, 0x07, 0x07, 0x75, 0xe8, 0x5d, 0x6a, + 0x7d, 0x97, 0x7a, 0x54, 0x14, 0x89, 0x69, 0x69, 0xb3, 0xa2, 0xc6, 0x8b, 0xda, 0xa0, 0x2e, 0x95, + 0x31, 0xc5, 0x34, 0x28, 0xc3, 0xd9, 0x13, 0x47, 0x4a, 0xbb, 0x98, 0x52, 0xdc, 0x45, 0x30, 0x58, + 0x99, 0xfe, 0x39, 0x34, 0x9c, 0x61, 0x58, 0x52, 0x12, 0x14, 0x42, 0xba, 0x00, 0xa0, 0xde, 0x08, + 0x60, 0xb3, 0xc5, 0xf0, 0x89, 0x8b, 0x0c, 0x0f, 0x9d, 0x04, 0x15, 0xf1, 0x2d, 0x28, 0x71, 0x4c, + 0x9b, 0x79, 0x86, 0x87, 0x2a, 0x42, 0x55, 0xa8, 0x6d, 0x34, 0xca, 0x1a, 0x97, 0xd1, 0xe6, 0x32, + 0xda, 0x6b, 0x67, 0xd8, 0xdc, 0x99, 0x8e, 0x94, 0x47, 0x43, 0xa3, 0xd7, 0x3d, 0x56, 0x97, 0xf7, + 0xa8, 0xfa, 0x06, 0x5f, 0x9e, 0xcd, 0x56, 0xe2, 0x7b, 0xb0, 0x69, 0x51, 0x87, 0x21, 0x87, 0xf9, + 0x2c, 0x24, 0x5d, 0x5b, 0x41, 0x2a, 0x4d, 0x47, 0xca, 0x76, 0x48, 0x1a, 0xdd, 0xa6, 0xea, 0x0f, + 0x17, 0x6f, 0x38, 0xf5, 0x36, 0x28, 0x30, 0x82, 0x1d, 0xe4, 0x56, 0xf2, 0x55, 0xa1, 0x56, 0xd4, + 0xc3, 0xd5, 0xf1, 0xfa, 0xa7, 0x2b, 0x25, 0xf7, 0xeb, 0x4a, 0xc9, 0xa9, 0xbb, 0x60, 0x27, 0xe6, + 0x50, 0x47, 0xac, 0x3f, 0x63, 0x51, 0xbf, 0x70, 0xf7, 0xef, 0xfa, 0xf6, 0x1f, 0xf7, 0x75, 0x50, + 0x0c, 0x9d, 0x10, 0x3b, 0xb0, 0x5e, 0x6c, 0x96, 0xa7, 0x23, 0x65, 0x2b, 0x62, 0x92, 0xd8, 0xaa, + 0xbe, 0xce, 0x9f, 0xdf, 0xd8, 0xe2, 0x21, 0x28, 0x74, 0x90, 0x61, 0x23, 0x77, 0x95, 0x2b, 0x3d, + 0xc4, 0x64, 0xee, 0x78, 0xb9, 0xab, 0x45, 0xc7, 0x3f, 0xf2, 0x60, 0x2b, 0xa8, 0x61, 0xd7, 0xb0, + 0xff, 0xa1, 0xe5, 0x78, 0xc6, 0x6b, 0x77, 0x91, 0x71, 0xfe, 0x3f, 0x65, 0x7c, 0x0a, 0xca, 0x7d, + 0x97, 0xd2, 0xf3, 0xb6, 0xcf, 0x6d, 0xb7, 0xb9, 0x6e, 0xe5, 0x5e, 0x55, 0xa8, 0x95, 0x9a, 0xca, + 0x74, 0xa4, 0xec, 0x71, 0xa6, 0x24, 0x94, 0xaa, 0x8b, 0xc1, 0xeb, 0xe8, 0x5f, 0x76, 0x01, 0xf6, + 0x63, 0xe0, 0x58, 0xef, 0xf7, 0x03, 0xee, 0xda, 0x74, 0xa4, 0x1c, 0x24, 0x72, 0xc7, 0x7b, 0x96, + 0x22, 0x22, 0x69, 0x33, 0x5a, 0x48, 0x49, 0x5c, 0x02, 0x95, 0x78, 0xaa, 0x8b, 0xc8, 0xbf, 0x09, + 0xe0, 0x71, 0x8b, 0xe1, 0x33, 0xdf, 0xec, 0x11, 0xaf, 0x45, 0x98, 0x89, 0x3a, 0xc6, 0x80, 0x50, + 0xdf, 0xfd, 0x9b, 0xdc, 0x5f, 0x81, 0x52, 0x6f, 0x89, 0x62, 0xe5, 0xc0, 0x46, 0x90, 0x19, 0xc6, + 0x56, 0x01, 0xfb, 0x89, 0x7d, 0xce, 0x9d, 0x34, 0xbe, 0xe6, 0x41, 0xbe, 0xc5, 0xb0, 0xf8, 0x11, + 0x94, 0x22, 0x1f, 0x9c, 0x27, 0xda, 0xed, 0x6f, 0x9d, 0x16, 0x3b, 0xb3, 0xd2, 0xb3, 0x0c, 0xa0, + 0xb9, 0xd2, 0x4c, 0x21, 0x72, 0xa8, 0xd3, 0x14, 0x96, 0x41, 0xa9, 0x0a, 0x49, 0x07, 0x51, 0xb4, + 0xc0, 0x83, 0xe8, 0x44, 0x1d, 0xa4, 0xee, 0x5e, 0x42, 0x49, 0x87, 0x59, 0x50, 0x0b, 0x11, 0x17, + 0x88, 0x09, 0xb1, 0x3f, 0x4d, 0xe1, 0xb8, 0x0d, 0x95, 0xea, 0x99, 0xa1, 0x73, 0xcd, 0xe6, 0xe9, + 0xf7, 0xb1, 0x2c, 0x5c, 0x8f, 0x65, 0xe1, 0x66, 0x2c, 0x0b, 0x9f, 0x27, 0x72, 0xee, 0x7a, 0x22, + 0xe7, 0x7e, 0x4e, 0xe4, 0xdc, 0x87, 0x97, 0x98, 0x78, 0x1d, 0xdf, 0xd4, 0x2c, 0xda, 0x83, 0x16, + 0x65, 0x3d, 0xca, 0xc2, 0x9f, 0x23, 0x66, 0x5f, 0xc0, 0x4b, 0xb8, 0xb8, 0x6b, 0x9e, 0x37, 0x8e, + 0xc2, 0xeb, 0xc6, 0x1b, 0xf6, 0x11, 0x33, 0x0b, 0xc1, 0x58, 0xbd, 0xf8, 0x1d, 0x00, 0x00, 0xff, + 0xff, 0xf4, 0xf1, 0xa7, 0x9a, 0xf0, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -636,7 +634,7 @@ func (m *MsgCreateClient) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.Signer) i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) i-- - dAtA[i] = 0x22 + dAtA[i] = 0x1a } if m.ConsensusState != nil { { @@ -648,7 +646,7 @@ func (m *MsgCreateClient) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTx(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a + dAtA[i] = 0x12 } if m.ClientState != nil { { @@ -660,13 +658,6 @@ func (m *MsgCreateClient) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTx(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x12 - } - if len(m.ClientId) > 0 { - i -= len(m.ClientId) - copy(dAtA[i:], m.ClientId) - i = encodeVarintTx(dAtA, i, uint64(len(m.ClientId))) - i-- dAtA[i] = 0xa } return len(dAtA) - i, nil @@ -954,10 +945,6 @@ func (m *MsgCreateClient) Size() (n int) { } var l int _ = l - l = len(m.ClientId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } if m.ClientState != nil { l = m.ClientState.Size() n += 1 + l + sovTx(uint64(l)) @@ -1120,38 +1107,6 @@ func (m *MsgCreateClient) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ClientId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ClientState", wireType) } @@ -1187,7 +1142,7 @@ func (m *MsgCreateClient) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 3: + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ConsensusState", wireType) } @@ -1223,7 +1178,7 @@ func (m *MsgCreateClient) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 4: + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } diff --git a/x/ibc/core/03-connection/keeper/handshake_test.go b/x/ibc/core/03-connection/keeper/handshake_test.go index eb9ca5c401b5..d70fd013dcc8 100644 --- a/x/ibc/core/03-connection/keeper/handshake_test.go +++ b/x/ibc/core/03-connection/keeper/handshake_test.go @@ -41,8 +41,9 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { version = &types.Version{} }, false}, {"couldn't add connection to client", func() { - // swap client identifiers to result in client that does not exist - clientB, clientA = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Tendermint) + clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, exported.Tendermint) + // set clientA to invalid client identifier + clientA = "clientidentifier" }, false}, } diff --git a/x/ibc/core/03-connection/types/keys.go b/x/ibc/core/03-connection/types/keys.go index c44602203e51..65af565c2abb 100644 --- a/x/ibc/core/03-connection/types/keys.go +++ b/x/ibc/core/03-connection/types/keys.go @@ -2,10 +2,10 @@ package types import ( "fmt" - "strconv" - "strings" + "regexp" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host" ) const ( @@ -30,11 +30,17 @@ const ( ) // FormatConnectionIdentifier returns the connection identifier with the sequence appended. +// This is a SDK specific format not enforced by IBC protocol. func FormatConnectionIdentifier(sequence uint64) string { return fmt.Sprintf("%s%d", ConnectionPrefix, sequence) } -// IsValidConnectionID return true if the connection identifier is valid. +// IsConnectionIDFormat checks if a connectionID is in the format required on the SDK for +// parsing connection identifiers. The connection identifier must be in the form: `connection-{N} +var IsConnectionIDFormat = regexp.MustCompile(`^connection-[0-9]{1,20}$`).MatchString + +// IsValidConnectionID checks if the connection identifier is valid and can be parsed to +// the connection identifier format. func IsValidConnectionID(connectionID string) bool { _, err := ParseConnectionSequence(connectionID) return err == nil @@ -42,18 +48,14 @@ func IsValidConnectionID(connectionID string) bool { // ParseConnectionSequence parses the connection sequence from the connection identifier. func ParseConnectionSequence(connectionID string) (uint64, error) { - if !strings.HasPrefix(connectionID, ConnectionPrefix) { - return 0, sdkerrors.Wrapf(ErrInvalidConnectionIdentifier, "doesn't contain prefix `%s`", ConnectionPrefix) - } - - splitStr := strings.Split(connectionID, ConnectionPrefix) - if len(splitStr) != 2 { - return 0, sdkerrors.Wrap(ErrInvalidConnectionIdentifier, "connection identifier must be in format: `connection-{N}`") + if !IsConnectionIDFormat(connectionID) { + return 0, sdkerrors.Wrap(host.ErrInvalidID, "connection identifier is not in the format: `connection-{N}`") } - sequence, err := strconv.ParseUint(splitStr[1], 10, 64) + sequence, err := host.ParseIdentifier(connectionID, ConnectionPrefix) if err != nil { - return 0, sdkerrors.Wrap(err, "failed to parse connection identifier sequence") + return 0, sdkerrors.Wrap(err, "invalid connection identifier") } + return sequence, nil } diff --git a/x/ibc/core/03-connection/types/keys_test.go b/x/ibc/core/03-connection/types/keys_test.go index 261bd2895fbb..c899dc3c53ab 100644 --- a/x/ibc/core/03-connection/types/keys_test.go +++ b/x/ibc/core/03-connection/types/keys_test.go @@ -1,6 +1,7 @@ package types_test import ( + "math" "testing" "github.com/cosmos/cosmos-sdk/x/ibc/core/03-connection/types" @@ -17,10 +18,13 @@ func TestParseConnectionSequence(t *testing.T) { }{ {"valid 0", "connection-0", 0, true}, {"valid 1", "connection-1", 1, true}, - {"valid large sequence", "connection-234568219356718293", 234568219356718293, true}, + {"valid large sequence", types.FormatConnectionIdentifier(math.MaxUint64), math.MaxUint64, true}, + // one above uint64 max + {"invalid uint64", "connection-18446744073709551616", 0, false}, // uint64 == 20 characters {"invalid large sequence", "connection-2345682193567182931243", 0, false}, {"capital prefix", "Connection-0", 0, false}, + {"double prefix", "connection-connection-0", 0, false}, {"missing dash", "connection0", 0, false}, {"blank id", " ", 0, false}, {"empty id", "", 0, false}, diff --git a/x/ibc/core/04-channel/types/keys.go b/x/ibc/core/04-channel/types/keys.go index b6c5745dda12..d3a6cde24d56 100644 --- a/x/ibc/core/04-channel/types/keys.go +++ b/x/ibc/core/04-channel/types/keys.go @@ -2,10 +2,10 @@ package types import ( "fmt" - "strconv" - "strings" + "regexp" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host" ) const ( @@ -30,11 +30,17 @@ const ( ) // FormatChannelIdentifier returns the channel identifier with the sequence appended. +// This is a SDK specific format not enforced by IBC protocol. func FormatChannelIdentifier(sequence uint64) string { return fmt.Sprintf("%s%d", ChannelPrefix, sequence) } -// IsValidChannelID return true if the channel identifier is valid. +// IsChannelIDFormat checks if a channelID is in the format required on the SDK for +// parsing channel identifiers. The channel identifier must be in the form: `channel-{N} +var IsChannelIDFormat = regexp.MustCompile(`^channel-[0-9]{1,20}$`).MatchString + +// IsValidChannelID checks if a channelID is valid and can be parsed to the channel +// identifier format. func IsValidChannelID(channelID string) bool { _, err := ParseChannelSequence(channelID) return err == nil @@ -42,18 +48,14 @@ func IsValidChannelID(channelID string) bool { // ParseChannelSequence parses the channel sequence from the channel identifier. func ParseChannelSequence(channelID string) (uint64, error) { - if !strings.HasPrefix(channelID, ChannelPrefix) { - return 0, sdkerrors.Wrapf(ErrInvalidChannelIdentifier, "doesn't contain prefix `%s`", ChannelPrefix) - } - - splitStr := strings.Split(channelID, ChannelPrefix) - if len(splitStr) != 2 { - return 0, sdkerrors.Wrap(ErrInvalidChannelIdentifier, "channel identifier must be in format: `channel-{N}`") + if !IsChannelIDFormat(channelID) { + return 0, sdkerrors.Wrap(host.ErrInvalidID, "channel identifier is not in the format: `channel-{N}`") } - sequence, err := strconv.ParseUint(splitStr[1], 10, 64) + sequence, err := host.ParseIdentifier(channelID, ChannelPrefix) if err != nil { - return 0, sdkerrors.Wrap(err, "failed to parse channel identifier sequence") + return 0, sdkerrors.Wrap(err, "invalid channel identifier") } + return sequence, nil } diff --git a/x/ibc/core/04-channel/types/keys_test.go b/x/ibc/core/04-channel/types/keys_test.go index 418174cb0406..86e4e61aa2c8 100644 --- a/x/ibc/core/04-channel/types/keys_test.go +++ b/x/ibc/core/04-channel/types/keys_test.go @@ -18,6 +18,8 @@ func TestParseChannelSequence(t *testing.T) { {"valid 0", "channel-0", 0, true}, {"valid 1", "channel-1", 1, true}, {"valid large sequence", "channel-234568219356718293", 234568219356718293, true}, + // one above uint64 max + {"invalid uint64", "channel-18446744073709551616", 0, false}, // uint64 == 20 characters {"invalid large sequence", "channel-2345682193567182931243", 0, false}, {"capital prefix", "Channel-0", 0, false}, diff --git a/x/ibc/core/24-host/parse.go b/x/ibc/core/24-host/parse.go index 7e6301a391fd..8c3459500d92 100644 --- a/x/ibc/core/24-host/parse.go +++ b/x/ibc/core/24-host/parse.go @@ -1,11 +1,37 @@ package host import ( + "strconv" "strings" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) +// ParseIdentifier parses the sequence from the identifier using the provided prefix. This function +// does not need to be used by counterparty chains. SDK generated connection and channel identifiers +// are required to use this format. +func ParseIdentifier(identifier, prefix string) (uint64, error) { + if !strings.HasPrefix(identifier, prefix) { + return 0, sdkerrors.Wrapf(ErrInvalidID, "identifier doesn't contain prefix `%s`", prefix) + } + + splitStr := strings.Split(identifier, prefix) + if len(splitStr) != 2 { + return 0, sdkerrors.Wrapf(ErrInvalidID, "identifier must be in format: `%s{N}`", prefix) + } + + // sanity check + if splitStr[0] != "" { + return 0, sdkerrors.Wrapf(ErrInvalidID, "identifier must begin with prefix %s", prefix) + } + + sequence, err := strconv.ParseUint(splitStr[1], 10, 64) + if err != nil { + return 0, sdkerrors.Wrap(err, "failed to parse identifier sequence") + } + return sequence, nil +} + // ParseConnectionPath returns the connection ID from a full path. It returns // an error if the provided path is invalid. func ParseConnectionPath(path string) (string, error) { diff --git a/x/ibc/core/24-host/parse_test.go b/x/ibc/core/24-host/parse_test.go new file mode 100644 index 000000000000..cbee37ddbcb0 --- /dev/null +++ b/x/ibc/core/24-host/parse_test.go @@ -0,0 +1,47 @@ +package host_test + +import ( + "math" + "testing" + + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/core/03-connection/types" + host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host" + "github.com/stretchr/testify/require" +) + +func TestParseIdentifier(t *testing.T) { + testCases := []struct { + name string + identifier string + prefix string + expSeq uint64 + expPass bool + }{ + {"valid 0", "connection-0", "connection-", 0, true}, + {"valid 1", "connection-1", "connection-", 1, true}, + {"valid large sequence", connectiontypes.FormatConnectionIdentifier(math.MaxUint64), "connection-", math.MaxUint64, true}, + // one above uint64 max + {"invalid uint64", "connection-18446744073709551616", "connection-", 0, false}, + // uint64 == 20 characters + {"invalid large sequence", "connection-2345682193567182931243", "conenction-", 0, false}, + {"capital prefix", "Connection-0", "connection-", 0, false}, + {"double prefix", "connection-connection-0", "connection-", 0, false}, + {"doesn't have prefix", "connection-0", "prefix", 0, false}, + {"missing dash", "connection0", "connection-", 0, false}, + {"blank id", " ", "connection-", 0, false}, + {"empty id", "", "connection-", 0, false}, + {"negative sequence", "connection--1", "connection-", 0, false}, + } + + for _, tc := range testCases { + + seq, err := host.ParseIdentifier(tc.identifier, tc.prefix) + require.Equal(t, tc.expSeq, seq) + + if tc.expPass { + require.NoError(t, err, tc.name) + } else { + require.Error(t, err, tc.name) + } + } +} diff --git a/x/ibc/core/genesis_test.go b/x/ibc/core/genesis_test.go index 29a26aad7402..bc4c5834d3e5 100644 --- a/x/ibc/core/genesis_test.go +++ b/x/ibc/core/genesis_test.go @@ -97,6 +97,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() { }, clienttypes.NewParams(exported.Tendermint, exported.Localhost), true, + 0, ), ConnectionGenesis: connectiontypes.NewGenesisState( []connectiontypes.IdentifiedConnection{ @@ -154,6 +155,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() { nil, clienttypes.NewParams(exported.Tendermint), false, + 0, ), ConnectionGenesis: connectiontypes.DefaultGenesisState(), }, @@ -239,6 +241,7 @@ func (suite *IBCTestSuite) TestInitGenesis() { }, clienttypes.NewParams(exported.Tendermint, exported.Localhost), true, + 0, ), ConnectionGenesis: connectiontypes.NewGenesisState( []connectiontypes.IdentifiedConnection{ diff --git a/x/ibc/core/keeper/msg_server.go b/x/ibc/core/keeper/msg_server.go index 2b655ff9a2fc..78f822e4d5ad 100644 --- a/x/ibc/core/keeper/msg_server.go +++ b/x/ibc/core/keeper/msg_server.go @@ -32,14 +32,15 @@ func (k Keeper) CreateClient(goCtx context.Context, msg *clienttypes.MsgCreateCl return nil, err } - if err = k.ClientKeeper.CreateClient(ctx, msg.ClientId, clientState, consensusState); err != nil { + clientID, err := k.ClientKeeper.CreateClient(ctx, clientState, consensusState) + if err != nil { return nil, err } ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( clienttypes.EventTypeCreateClient, - sdk.NewAttribute(clienttypes.AttributeKeyClientID, msg.ClientId), + sdk.NewAttribute(clienttypes.AttributeKeyClientID, clientID), sdk.NewAttribute(clienttypes.AttributeKeyClientType, clientState.ClientType()), sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, clientState.GetLatestHeight().String()), ), diff --git a/x/ibc/core/spec/01_concepts.md b/x/ibc/core/spec/01_concepts.md index c3059e5f5876..045508999d39 100644 --- a/x/ibc/core/spec/01_concepts.md +++ b/x/ibc/core/spec/01_concepts.md @@ -10,11 +10,11 @@ this [document](https://github.com/cosmos/ics/blob/master/ibc/1_IBC_TERMINOLOGY. ## Client Creation, Updates, and Upgrades IBC clients are on chain light clients. The light client is responsible for verifying -counterparty state. A light client can be created by any user submitting a client -identifier and a valid initial `ClientState` and `ConsensusState`. The client identifier -must not already be used. Clients are given a client identifier prefixed store to -store their associated client state and consensus states. Consensus states are -stored using their associated height. +counterparty state. A light client can be created by any user submitting a valid initial +`ClientState` and `ConsensusState`. The client identifier is auto generated using the +client type and the global client counter appended in the format: `{client-type}-{N}`. +Clients are given a client identifier prefixed store to store their associated client +state and consensus states. Consensus states are stored using their associated height. Clients can be updated by any user submitting a valid `Header`. The client state callback to `CheckHeaderAndUpdateState` is responsible for verifying the header against previously diff --git a/x/ibc/core/spec/02_state.md b/x/ibc/core/spec/02_state.md index 54eb41bc4bca..2c85a525a953 100644 --- a/x/ibc/core/spec/02_state.md +++ b/x/ibc/core/spec/02_state.md @@ -13,9 +13,12 @@ The client type is not stored since it can be obtained through the client state. | "0/" | "clients/{identifier}/clientState" | ClientState | | "0/" | "clients/{identifier}/consensusStates/{height}" | ConsensusState | | "0/" | "clients/{identifier}/connections" | []string | +| "0/" | "nextClientSequence | uint64 | | "0/" | "connections/{identifier}" | ConnectionEnd | +| "0/" | "nextConnectionSequence" | uint64 | | "0/" | "ports/{identifier}" | CapabilityKey | | "0/" | "channelEnds/ports/{identifier}/channels/{identifier}" | ChannelEnd | +| "0/" | "nextChannelSequence" | uint64 | | "0/" | "capabilities/ports/{identifier}/channels/{identifier}" | CapabilityKey | | "0/" | "nextSequenceSend/ports/{identifier}/channels/{identifier}" | uint64 | | "0/" | "nextSequenceRecv/ports/{identifier}/channels/{identifier}" | uint64 | diff --git a/x/ibc/core/spec/03_state_transitions.md b/x/ibc/core/spec/03_state_transitions.md index de31957d66ea..be3b508b795c 100644 --- a/x/ibc/core/spec/03_state_transitions.md +++ b/x/ibc/core/spec/03_state_transitions.md @@ -9,7 +9,7 @@ The described state transitions assume successful message exection. ## Create Client `MsgCreateClient` will initialize and store a `ClientState` and `ConsensusState` in the sub-store -created using the given client identifier. +created using a generated client identifier. ## Update Client diff --git a/x/ibc/core/spec/04_messages.md b/x/ibc/core/spec/04_messages.md index 34d68200b284..3728e6d6f323 100644 --- a/x/ibc/core/spec/04_messages.md +++ b/x/ibc/core/spec/04_messages.md @@ -14,7 +14,6 @@ A light client is created using the `MsgCreateClient`. ```go type MsgCreateClient struct { - ClientId string ClientState *types.Any // proto-packed client state ConsensusState *types.Any // proto-packed consensus state Signer sdk.AccAddress @@ -23,13 +22,11 @@ type MsgCreateClient struct { This message is expected to fail if: -- `ClientId` is invalid (see naming requirements) - `ClientState` is empty or invalid - `ConsensusState` is empty or invalid - `Signer` is empty -- A light client with the provided id and type already exist -The message creates and stores a light client with an initial consensus state for the given client +The message creates and stores a light client with an initial consensus state using a generated client identifier. ### MsgUpdateClient @@ -112,7 +109,6 @@ A connection is initialized on a light client using the `MsgConnectionOpenInit`. ```go type MsgConnectionOpenInit struct { ClientId string - ConnectionId string Counterparty Counterparty Version string Signer sdk.AccAddress @@ -121,7 +117,6 @@ type MsgConnectionOpenInit struct { This message is expected to fail if: - `ClientId` is invalid (see naming requirements) -- `ConnectionId` is invalid (see naming requirements) - `Counterparty` is empty - 'Version' is not empty and invalid - `Signer` is empty @@ -138,8 +133,7 @@ using the `MsgConnectionOpenTry`. ```go type MsgConnectionOpenTry struct { ClientId string - DesiredConnectionId string - CounterpartyChosenConnectionId string + PreviousConnectionId string ClientState *types.Any // proto-packed counterparty client Counterparty Counterparty CounterpartyVersions []string @@ -155,8 +149,7 @@ type MsgConnectionOpenTry struct { This message is expected to fail if: - `ClientId` is invalid (see naming requirements) -- `DesiredConnectionId` is invalid (see naming requirements) -- `CounterpartyChosenConnectionId` is not empty and doesn't match `DesiredConnectionId` +- `PreviousConnectionId` is not empty and invalid (see naming requirements) - `ClientState` is not a valid client of the executing chain - `Counterparty` is empty - `CounterpartyVersions` is empty @@ -167,15 +160,13 @@ This message is expected to fail if: - `ConsensusHeight` is zero - `Signer` is empty - A Client hasn't been created for the given ID -- A Connection for the given ID already exists +- If a previous connection exists but does not match the supplied parameters. - `ProofInit` does not prove that the counterparty connection is in state INIT - `ProofClient` does not prove that the counterparty has stored the `ClientState` provided in message - `ProofConsensus` does not prove that the counterparty has the correct consensus state for this chain -The message creates a connection for the given ID with an TRYOPEN State. The `CounterpartyChosenConnectionID` -represents the connection ID the counterparty set under `connection.Counterparty.ConnectionId` -to represent the connection ID this chain should use. An empty string indicates the connection -identifier is flexible and gives this chain an opportunity to choose its own identifier. +The message creates a connection for a generated connection ID with an TRYOPEN State. If a previous +connection already exists, it updates the connection state from INIT to TRYOPEN. ### MsgConnectionOpenAck @@ -251,7 +242,6 @@ message. ```go type MsgChannelOpenInit struct { PortId string - ChannelId string Channel Channel Signer sdk.AccAddress } @@ -260,12 +250,11 @@ type MsgChannelOpenInit struct { This message is expected to fail if: - `PortId` is invalid (see naming requirements) -- `ChannelId` is invalid (see naming requirements) - `Channel` is empty - `Signer` is empty - A Channel End exists for the given Channel ID and Port ID -The message creates a channel on chain A with an INIT state for the given Channel ID +The message creates a channel on chain A with an INIT state for a generated Channel ID and Port ID. ### MsgChannelOpenTry @@ -276,8 +265,7 @@ the `MsgChannelOpenTry` message. ```go type MsgChannelOpenTry struct { PortId string - DesiredChannelId string - CounterpartyChosenChannelId string + PreviousChannelId string Channel Channel CounterpartyVersion string ProofInit []byte @@ -289,21 +277,18 @@ type MsgChannelOpenTry struct { This message is expected to fail if: - `PortId` is invalid (see naming requirements) -- `DesiredChannelId` is invalid (see naming requirements) -- `CounterpartyChosenChannelId` is not empty and not equal to `ChannelId` +- `PreviousChannelId` is not empty and invalid (see naming requirements) - `Channel` is empty - `CounterpartyVersion` is empty - `ProofInit` is empty - `ProofHeight` is zero - `Signer` is empty -- A Channel End exists for the given Channel and Port ID +- A previous channel exists and does not match the provided parameters. - `ProofInit` does not prove that the counterparty's Channel state is in INIT -The message creates a channel on chain B with an TRYOPEN state for the given Channel ID -and Port ID. The `CounterpartyChosenChannelId` represents the channel ID the counterparty set under -`connection.Counterparty.ChannelId` to represent the channel ID this chain should use. -An empty string indicates the channel identifier is flexible and gives this chain an -opportunity to choose its own identifier. +The message creates a channel on chain B with an TRYOPEN state for using a generated Channel ID +and given Port ID if the previous channel does not already exist. Otherwise it udates the +previous channel state from INIT to TRYOPEN. ### MsgChannelOpenAck diff --git a/x/ibc/light-clients/06-solomachine/client/cli/tx.go b/x/ibc/light-clients/06-solomachine/client/cli/tx.go index 37db768a3025..8d1709fc279f 100644 --- a/x/ibc/light-clients/06-solomachine/client/cli/tx.go +++ b/x/ibc/light-clients/06-solomachine/client/cli/tx.go @@ -24,12 +24,12 @@ const ( // NewCreateClientCmd defines the command to create a new solo machine client. func NewCreateClientCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "create [client-id] [sequence] [path/to/consensus_state.json]", + Use: "create [sequence] [path/to/consensus_state.json]", Short: "create new solo machine client", Long: `create a new solo machine client with the specified identifier and public key - ConsensusState json example: {"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A/3SXL2ONYaOkxpdR5P8tHTlSlPv1AwQwSFxKRee5JQW"},"diversifier":"diversifier","timestamp":"10"}`, - Example: fmt.Sprintf("%s tx ibc %s create [client-id] [sequence] [path/to/consensus_state] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), - Args: cobra.ExactArgs(3), + Example: fmt.Sprintf("%s tx ibc %s create [sequence] [path/to/consensus_state] --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags()) @@ -37,9 +37,7 @@ func NewCreateClientCmd() *cobra.Command { return err } - clientID := args[0] - - sequence, err := strconv.ParseUint(args[1], 10, 64) + sequence, err := strconv.ParseUint(args[0], 10, 64) if err != nil { return err } @@ -48,10 +46,10 @@ func NewCreateClientCmd() *cobra.Command { // attempt to unmarshal consensus state argument consensusState := &types.ConsensusState{} - if err := cdc.UnmarshalJSON([]byte(args[2]), consensusState); err != nil { + if err := cdc.UnmarshalJSON([]byte(args[1]), consensusState); err != nil { // check for file path if JSON input is not provided - contents, err := ioutil.ReadFile(args[2]) + contents, err := ioutil.ReadFile(args[1]) if err != nil { return errors.Wrap(err, "neither JSON input nor path to .json file for consensus state were provided") } @@ -64,7 +62,7 @@ func NewCreateClientCmd() *cobra.Command { allowUpdateAfterProposal, _ := cmd.Flags().GetBool(flagAllowUpdateAfterProposal) clientState := types.NewClientState(sequence, consensusState, allowUpdateAfterProposal) - msg, err := clienttypes.NewMsgCreateClient(clientID, clientState, consensusState, clientCtx.GetFromAddress()) + msg, err := clienttypes.NewMsgCreateClient(clientState, consensusState, clientCtx.GetFromAddress()) if err != nil { return err } diff --git a/x/ibc/light-clients/07-tendermint/client/cli/tx.go b/x/ibc/light-clients/07-tendermint/client/cli/tx.go index 3bd2f0c0b737..04a274aceca9 100644 --- a/x/ibc/light-clients/07-tendermint/client/cli/tx.go +++ b/x/ibc/light-clients/07-tendermint/client/cli/tx.go @@ -34,15 +34,15 @@ const ( // in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create func NewCreateClientCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "create [client-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period] [max_clock_drift]", + Use: "create [path/to/consensus_state.json] [trusting_period] [unbonding_period] [max_clock_drift]", Short: "create new tendermint client", Long: `Create a new tendermint IBC client. - 'trust-level' flag can be a fraction (eg: '1/3') or 'default' - 'proof-specs' flag can be JSON input, a path to a .json file or 'default' - 'upgrade-path' flag is a string specifying the upgrade path for this chain where a future upgraded client will be stored. The path is a comma-separated list representing the keys in order of the keyPath to the committed upgraded client. e.g. 'upgrade/upgradedClient'`, - Example: fmt.Sprintf("%s tx ibc %s create [client-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period] [max_clock_drift] --trust-level default --consensus-params [path/to/consensus-params.json] --proof-specs [path/to/proof-specs.json] --upgrade-path upgrade/upgradedClient --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), - Args: cobra.ExactArgs(5), + Example: fmt.Sprintf("%s tx ibc %s create [path/to/consensus_state.json] [trusting_period] [unbonding_period] [max_clock_drift] --trust-level default --consensus-params [path/to/consensus-params.json] --proof-specs [path/to/proof-specs.json] --upgrade-path upgrade/upgradedClient --from node0 --home ../node0/cli --chain-id $CID", version.AppName, types.SubModuleName), + Args: cobra.ExactArgs(4), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags()) @@ -50,15 +50,13 @@ func NewCreateClientCmd() *cobra.Command { return err } - clientID := args[0] - cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry) legacyAmino := codec.NewLegacyAmino() var header *types.Header - if err := cdc.UnmarshalJSON([]byte(args[1]), header); err != nil { + if err := cdc.UnmarshalJSON([]byte(args[0]), header); err != nil { // check for file path if JSON input is not provided - contents, err := ioutil.ReadFile(args[1]) + contents, err := ioutil.ReadFile(args[0]) if err != nil { return errors.New("neither JSON input nor path to .json file were provided for consensus header") } @@ -83,17 +81,17 @@ func NewCreateClientCmd() *cobra.Command { } } - trustingPeriod, err := time.ParseDuration(args[2]) + trustingPeriod, err := time.ParseDuration(args[1]) if err != nil { return err } - ubdPeriod, err := time.ParseDuration(args[3]) + ubdPeriod, err := time.ParseDuration(args[2]) if err != nil { return err } - maxClockDrift, err := time.ParseDuration(args[4]) + maxClockDrift, err := time.ParseDuration(args[3]) if err != nil { return err } @@ -137,7 +135,7 @@ func NewCreateClientCmd() *cobra.Command { consensusState := header.ConsensusState() msg, err := clienttypes.NewMsgCreateClient( - clientID, clientState, consensusState, clientCtx.GetFromAddress(), + clientState, consensusState, clientCtx.GetFromAddress(), ) if err != nil { return err diff --git a/x/ibc/testing/chain.go b/x/ibc/testing/chain.go index b63e72c3e9d2..4dc8ec4f25eb 100644 --- a/x/ibc/testing/chain.go +++ b/x/ibc/testing/chain.go @@ -369,8 +369,8 @@ func (chain *TestChain) GetPrefix() commitmenttypes.MerklePrefix { // NewClientID appends a new clientID string in the format: // ClientFor -func (chain *TestChain) NewClientID(counterpartyChainID string) string { - clientID := "client" + strconv.Itoa(len(chain.ClientIDs)) + "For" + counterpartyChainID +func (chain *TestChain) NewClientID(clientType string) string { + clientID := fmt.Sprintf("%s-%s", clientType, strconv.Itoa(len(chain.ClientIDs))) chain.ClientIDs = append(chain.ClientIDs, clientID) return clientID } @@ -460,7 +460,7 @@ func (chain *TestChain) ConstructMsgCreateClient(counterparty *TestChain, client } msg, err := clienttypes.NewMsgCreateClient( - clientID, clientState, consensusState, chain.SenderAccount.GetAddress(), + clientState, consensusState, chain.SenderAccount.GetAddress(), ) require.NoError(chain.t, err) return msg diff --git a/x/ibc/testing/chain_test.go b/x/ibc/testing/chain_test.go index bf5af6de6367..361a9c4c15af 100644 --- a/x/ibc/testing/chain_test.go +++ b/x/ibc/testing/chain_test.go @@ -33,6 +33,7 @@ func TestCreateSortedSignerArray(t *testing.T) { // smaller address validator1.Address = []byte{1} + validator2.Address = []byte{2} validator2.VotingPower = 1 expected = []tmtypes.PrivValidator{privVal1, privVal2} diff --git a/x/ibc/testing/coordinator.go b/x/ibc/testing/coordinator.go index aecdcd4b704b..95b59a1db9bf 100644 --- a/x/ibc/testing/coordinator.go +++ b/x/ibc/testing/coordinator.go @@ -95,7 +95,7 @@ func (coord *Coordinator) CreateClient( ) (clientID string, err error) { coord.CommitBlock(source, counterparty) - clientID = source.NewClientID(counterparty.ChainID) + clientID = source.NewClientID(clientType) switch clientType { case exported.Tendermint: