diff --git a/Makefile b/Makefile index d7b8a1fa8cfd..d636befa179f 100644 --- a/Makefile +++ b/Makefile @@ -315,7 +315,7 @@ test-cover: test-rosetta: docker build -t rosetta-ci:latest -f contrib/rosetta/node/Dockerfile . - docker-compose -f contrib/rosetta/docker-compose.yaml up --abort-on-container-exit --exit-code-from test_rosetta --build + docker-compose -f contrib/rosetta/docker-compose.yaml up .PHONY: test-rosetta benchmark: @@ -373,7 +373,7 @@ proto-all: proto-format proto-lint proto-gen proto-gen: @echo "Generating Protobuf files" - $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace tendermintdev/sdk-proto-gen:v0.1 sh ./scripts/protocgen.sh + docker run --rm -v "$(CURDIR)":/workspace --workdir /workspace tendermintdev/sdk-proto-gen:v0.1 sh ./scripts/protocgen.sh proto-format: @echo "Formatting Protobuf files" diff --git a/baseapp/grpcrouter.go b/baseapp/grpcrouter.go index 95186f0b16da..686dd8fc1188 100644 --- a/baseapp/grpcrouter.go +++ b/baseapp/grpcrouter.go @@ -141,7 +141,7 @@ func (qrt *GRPCQueryRouter) SetInterfaceRegistry(interfaceRegistry codectypes.In // registry reflection gRPC service. reflection.RegisterReflectionServiceServer( qrt, - reflection.NewReflectionServiceServer(interfaceRegistry), + reflection.NewReflectionServiceServer(interfaceRegistry, qrt), ) } @@ -157,3 +157,12 @@ func (qrt *GRPCQueryRouter) returnTypeOf(method string) (reflect.Type, error) { return returnType, nil } + +// ListServices provides the list of registered services +func (qrt *GRPCQueryRouter) ListServices() []*grpc.ServiceDesc { + svcDesc := make([]*grpc.ServiceDesc, len(qrt.serviceData)) + for i, svc := range qrt.serviceData { + svcDesc[i] = svc.serviceDesc + } + return svcDesc +} diff --git a/client/grpc/reflection/reflection.go b/client/grpc/reflection/reflection.go index eb07ea86bd73..735338f8c97e 100644 --- a/client/grpc/reflection/reflection.go +++ b/client/grpc/reflection/reflection.go @@ -2,6 +2,14 @@ package reflection import ( "context" + "fmt" + "log" + "reflect" + + "github.com/gogo/protobuf/proto" + "google.golang.org/grpc" + + sdktypes "github.com/cosmos/cosmos-sdk/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -11,18 +19,25 @@ import ( type reflectionServiceServer struct { interfaceRegistry types.InterfaceRegistry + infoProvider ServiceInfoProvider + + queries []*grpc.ServiceDesc +} + +type ServiceInfoProvider interface { + ListServices() []*grpc.ServiceDesc } // NewReflectionServiceServer creates a new reflectionServiceServer. -func NewReflectionServiceServer(interfaceRegistry types.InterfaceRegistry) ReflectionServiceServer { - return &reflectionServiceServer{interfaceRegistry: interfaceRegistry} +func NewReflectionServiceServer(interfaceRegistry types.InterfaceRegistry, infoProvider ServiceInfoProvider) ReflectionServiceServer { + return &reflectionServiceServer{interfaceRegistry: interfaceRegistry, infoProvider: infoProvider} } var _ ReflectionServiceServer = (*reflectionServiceServer)(nil) // ListAllInterfaces implements the ListAllInterfaces method of the // ReflectionServiceServer interface. -func (r reflectionServiceServer) ListAllInterfaces(_ context.Context, _ *ListAllInterfacesRequest) (*ListAllInterfacesResponse, error) { +func (r *reflectionServiceServer) ListAllInterfaces(_ context.Context, _ *ListAllInterfacesRequest) (*ListAllInterfacesResponse, error) { ifaces := r.interfaceRegistry.ListAllInterfaces() return &ListAllInterfacesResponse{InterfaceNames: ifaces}, nil @@ -30,7 +45,7 @@ func (r reflectionServiceServer) ListAllInterfaces(_ context.Context, _ *ListAll // ListImplementations implements the ListImplementations method of the // ReflectionServiceServer interface. -func (r reflectionServiceServer) ListImplementations(_ context.Context, req *ListImplementationsRequest) (*ListImplementationsResponse, error) { +func (r *reflectionServiceServer) ListImplementations(_ context.Context, req *ListImplementationsRequest) (*ListImplementationsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } @@ -40,6 +55,139 @@ func (r reflectionServiceServer) ListImplementations(_ context.Context, req *Lis } impls := r.interfaceRegistry.ListImplementations(req.InterfaceName) + protoNames := make([]string, len(impls)) + + for i, impl := range impls { + pb, err := r.interfaceRegistry.Resolve(impl) + // we should panic but let's return an error + if err != nil { + return nil, status.Errorf(codes.NotFound, "can not solve %s: %s", impl, err.Error()) + } + // we should panic here too + name := proto.MessageName(pb) + if name == "" { + return nil, status.Errorf(codes.NotFound, "can not get proto name for %s") + } + protoNames[i] = name + } + return &ListImplementationsResponse{ + ImplementationMessageNames: impls, + ImplementationMessageProtoNames: protoNames, + }, nil +} + +func (r *reflectionServiceServer) ListDeliverables(_ context.Context, _ *ListDeliverablesRequest) (*ListDeliverablesResponse, error) { + implementersName := r.interfaceRegistry.ListImplementations(sdktypes.ServiceMsgInterfaceName) + + deliverables := make([]*DeliverableDescriptor, len(implementersName)) + + for i, name := range implementersName { + resolved, err := r.interfaceRegistry.Resolve(name) + if err != nil { + return nil, status.Error(codes.Unknown, err.Error()) + } + msg := resolved.(sdktypes.MsgRequest) + deliverables[i] = &DeliverableDescriptor{ + Method: name, + ProtoName: proto.MessageName(msg), + } + } + return &ListDeliverablesResponse{Deliverables: deliverables}, nil +} + +func (r *reflectionServiceServer) ListQueryServices(ctx context.Context, request *ListQueriesRequest) (*ListQueriesResponse, error) { + defer func() { + r := recover() + if r != nil { + log.Printf("%#v", r) + } + }() + svcs := r.infoProvider.ListServices() + queries := make([]*QueryDescriptor, len(svcs)) + for i, q := range svcs { + queries[i] = &QueryDescriptor{ + ServiceName: q.ServiceName, + ProtoFile: q.Metadata.(string), + } + } + return &ListQueriesResponse{Queries: queries}, nil +} + +func (r *reflectionServiceServer) ResolveProtoType(ctx context.Context, request *ResolveProtoTypeRequest) (*ResolveProtoTypeResponse, error) { + typ, err := func() (typ reflect.Type, err error) { + defer func() { + r := recover() + if r != nil { + err = fmt.Errorf("type is not a recognized protobuf type: %s", request.Name) + } + }() + + typ = proto.MessageType(request.Name) + return + }() + if err != nil { + return nil, status.Errorf(codes.NotFound, err.Error()) + } + + if typ == nil { + return nil, status.Errorf(codes.InvalidArgument, "resolution of type %s returned null", request.Name) + } + + v := reflect.New(typ).Elem() + + ok := v.CanInterface() + if !ok { + return nil, status.Errorf(codes.InvalidArgument, "type cannot be cast to interface: %s", request.Name) + } + + vIf := v.Interface() + + pbMsg, ok := vIf.(proto.Message) + if !ok { + return nil, status.Errorf(codes.InvalidArgument, "type %T does not implement proto message: %s", vIf, request.Name) + } + + // get descriptor + type descriptor interface { + Descriptor() ([]byte, []int) + } + + pbDescriptor, ok := pbMsg.(descriptor) + if !ok { + return nil, status.Errorf(codes.InvalidArgument, "type does not implement the Descriptor interface: %s", request.Name) + } + rawDesc, pos := pbDescriptor.Descriptor() + return &ResolveProtoTypeResponse{ + RawDescriptor: rawDesc, + Indexes: func() []int64 { + pos64 := make([]int64, len(pos)) + for i, p := range pos { + pos64[i] = int64(p) + } + + return pos64 + }(), + }, nil +} + +func (r *reflectionServiceServer) ResolveService(ctx context.Context, request *ResolveServiceRequest) (*ResolveServiceResponse, error) { + rawDesc, err := func() (rawDesc []byte, err error) { + defer func() { + r := recover() + if r != nil { + err = fmt.Errorf("%#v", err) + } + + rawDesc = proto.FileDescriptor(request.FileName) + return + }() + + return + }() + + if err != nil { + return nil, status.Errorf(codes.NotFound, "service from file was not found: %s", request.FileName) + } - return &ListImplementationsResponse{ImplementationMessageNames: impls}, nil + return &ResolveServiceResponse{RawDescriptor: rawDesc}, nil } diff --git a/client/grpc/reflection/reflection.pb.go b/client/grpc/reflection/reflection.pb.go index 66dbef0c7105..cfedb4728995 100644 --- a/client/grpc/reflection/reflection.pb.go +++ b/client/grpc/reflection/reflection.pb.go @@ -28,22 +28,22 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// ListAllInterfacesRequest is the request type of the ListAllInterfaces RPC. -type ListAllInterfacesRequest struct { +type ResolveProtoTypeRequest struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } -func (m *ListAllInterfacesRequest) Reset() { *m = ListAllInterfacesRequest{} } -func (m *ListAllInterfacesRequest) String() string { return proto.CompactTextString(m) } -func (*ListAllInterfacesRequest) ProtoMessage() {} -func (*ListAllInterfacesRequest) Descriptor() ([]byte, []int) { +func (m *ResolveProtoTypeRequest) Reset() { *m = ResolveProtoTypeRequest{} } +func (m *ResolveProtoTypeRequest) String() string { return proto.CompactTextString(m) } +func (*ResolveProtoTypeRequest) ProtoMessage() {} +func (*ResolveProtoTypeRequest) Descriptor() ([]byte, []int) { return fileDescriptor_d48c054165687f5c, []int{0} } -func (m *ListAllInterfacesRequest) XXX_Unmarshal(b []byte) error { +func (m *ResolveProtoTypeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ListAllInterfacesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *ResolveProtoTypeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ListAllInterfacesRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_ResolveProtoTypeRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -53,36 +53,42 @@ func (m *ListAllInterfacesRequest) XXX_Marshal(b []byte, deterministic bool) ([] return b[:n], nil } } -func (m *ListAllInterfacesRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListAllInterfacesRequest.Merge(m, src) +func (m *ResolveProtoTypeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResolveProtoTypeRequest.Merge(m, src) } -func (m *ListAllInterfacesRequest) XXX_Size() int { +func (m *ResolveProtoTypeRequest) XXX_Size() int { return m.Size() } -func (m *ListAllInterfacesRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ListAllInterfacesRequest.DiscardUnknown(m) +func (m *ResolveProtoTypeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ResolveProtoTypeRequest.DiscardUnknown(m) } -var xxx_messageInfo_ListAllInterfacesRequest proto.InternalMessageInfo +var xxx_messageInfo_ResolveProtoTypeRequest proto.InternalMessageInfo -// ListAllInterfacesResponse is the response type of the ListAllInterfaces RPC. -type ListAllInterfacesResponse struct { - // interface_names is an array of all the registered interfaces. - InterfaceNames []string `protobuf:"bytes,1,rep,name=interface_names,json=interfaceNames,proto3" json:"interface_names,omitempty"` +func (m *ResolveProtoTypeRequest) GetName() string { + if m != nil { + return m.Name + } + return "" } -func (m *ListAllInterfacesResponse) Reset() { *m = ListAllInterfacesResponse{} } -func (m *ListAllInterfacesResponse) String() string { return proto.CompactTextString(m) } -func (*ListAllInterfacesResponse) ProtoMessage() {} -func (*ListAllInterfacesResponse) Descriptor() ([]byte, []int) { +type ResolveProtoTypeResponse struct { + RawDescriptor []byte `protobuf:"bytes,1,opt,name=raw_descriptor,json=rawDescriptor,proto3" json:"raw_descriptor,omitempty"` + Indexes []int64 `protobuf:"varint,2,rep,packed,name=indexes,proto3" json:"indexes,omitempty"` +} + +func (m *ResolveProtoTypeResponse) Reset() { *m = ResolveProtoTypeResponse{} } +func (m *ResolveProtoTypeResponse) String() string { return proto.CompactTextString(m) } +func (*ResolveProtoTypeResponse) ProtoMessage() {} +func (*ResolveProtoTypeResponse) Descriptor() ([]byte, []int) { return fileDescriptor_d48c054165687f5c, []int{1} } -func (m *ListAllInterfacesResponse) XXX_Unmarshal(b []byte) error { +func (m *ResolveProtoTypeResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ListAllInterfacesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *ResolveProtoTypeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ListAllInterfacesResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_ResolveProtoTypeResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -92,44 +98,48 @@ func (m *ListAllInterfacesResponse) XXX_Marshal(b []byte, deterministic bool) ([ return b[:n], nil } } -func (m *ListAllInterfacesResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListAllInterfacesResponse.Merge(m, src) +func (m *ResolveProtoTypeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResolveProtoTypeResponse.Merge(m, src) } -func (m *ListAllInterfacesResponse) XXX_Size() int { +func (m *ResolveProtoTypeResponse) XXX_Size() int { return m.Size() } -func (m *ListAllInterfacesResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ListAllInterfacesResponse.DiscardUnknown(m) +func (m *ResolveProtoTypeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ResolveProtoTypeResponse.DiscardUnknown(m) } -var xxx_messageInfo_ListAllInterfacesResponse proto.InternalMessageInfo +var xxx_messageInfo_ResolveProtoTypeResponse proto.InternalMessageInfo -func (m *ListAllInterfacesResponse) GetInterfaceNames() []string { +func (m *ResolveProtoTypeResponse) GetRawDescriptor() []byte { if m != nil { - return m.InterfaceNames + return m.RawDescriptor } return nil } -// ListImplementationsRequest is the request type of the ListImplementations -// RPC. -type ListImplementationsRequest struct { - // interface_name defines the interface to query the implementations for. - InterfaceName string `protobuf:"bytes,1,opt,name=interface_name,json=interfaceName,proto3" json:"interface_name,omitempty"` +func (m *ResolveProtoTypeResponse) GetIndexes() []int64 { + if m != nil { + return m.Indexes + } + return nil } -func (m *ListImplementationsRequest) Reset() { *m = ListImplementationsRequest{} } -func (m *ListImplementationsRequest) String() string { return proto.CompactTextString(m) } -func (*ListImplementationsRequest) ProtoMessage() {} -func (*ListImplementationsRequest) Descriptor() ([]byte, []int) { +type ResolveServiceRequest struct { + FileName string `protobuf:"bytes,1,opt,name=file_name,json=fileName,proto3" json:"file_name,omitempty"` +} + +func (m *ResolveServiceRequest) Reset() { *m = ResolveServiceRequest{} } +func (m *ResolveServiceRequest) String() string { return proto.CompactTextString(m) } +func (*ResolveServiceRequest) ProtoMessage() {} +func (*ResolveServiceRequest) Descriptor() ([]byte, []int) { return fileDescriptor_d48c054165687f5c, []int{2} } -func (m *ListImplementationsRequest) XXX_Unmarshal(b []byte) error { +func (m *ResolveServiceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ListImplementationsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *ResolveServiceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ListImplementationsRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_ResolveServiceRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -139,43 +149,41 @@ func (m *ListImplementationsRequest) XXX_Marshal(b []byte, deterministic bool) ( return b[:n], nil } } -func (m *ListImplementationsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListImplementationsRequest.Merge(m, src) +func (m *ResolveServiceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResolveServiceRequest.Merge(m, src) } -func (m *ListImplementationsRequest) XXX_Size() int { +func (m *ResolveServiceRequest) XXX_Size() int { return m.Size() } -func (m *ListImplementationsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ListImplementationsRequest.DiscardUnknown(m) +func (m *ResolveServiceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ResolveServiceRequest.DiscardUnknown(m) } -var xxx_messageInfo_ListImplementationsRequest proto.InternalMessageInfo +var xxx_messageInfo_ResolveServiceRequest proto.InternalMessageInfo -func (m *ListImplementationsRequest) GetInterfaceName() string { +func (m *ResolveServiceRequest) GetFileName() string { if m != nil { - return m.InterfaceName + return m.FileName } return "" } -// ListImplementationsResponse is the response type of the ListImplementations -// RPC. -type ListImplementationsResponse struct { - ImplementationMessageNames []string `protobuf:"bytes,1,rep,name=implementation_message_names,json=implementationMessageNames,proto3" json:"implementation_message_names,omitempty"` +type ResolveServiceResponse struct { + RawDescriptor []byte `protobuf:"bytes,1,opt,name=raw_descriptor,json=rawDescriptor,proto3" json:"raw_descriptor,omitempty"` } -func (m *ListImplementationsResponse) Reset() { *m = ListImplementationsResponse{} } -func (m *ListImplementationsResponse) String() string { return proto.CompactTextString(m) } -func (*ListImplementationsResponse) ProtoMessage() {} -func (*ListImplementationsResponse) Descriptor() ([]byte, []int) { +func (m *ResolveServiceResponse) Reset() { *m = ResolveServiceResponse{} } +func (m *ResolveServiceResponse) String() string { return proto.CompactTextString(m) } +func (*ResolveServiceResponse) ProtoMessage() {} +func (*ResolveServiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor_d48c054165687f5c, []int{3} } -func (m *ListImplementationsResponse) XXX_Unmarshal(b []byte) error { +func (m *ResolveServiceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ListImplementationsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *ResolveServiceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ListImplementationsResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_ResolveServiceResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -185,374 +193,2401 @@ func (m *ListImplementationsResponse) XXX_Marshal(b []byte, deterministic bool) return b[:n], nil } } -func (m *ListImplementationsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ListImplementationsResponse.Merge(m, src) +func (m *ResolveServiceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResolveServiceResponse.Merge(m, src) } -func (m *ListImplementationsResponse) XXX_Size() int { +func (m *ResolveServiceResponse) XXX_Size() int { return m.Size() } -func (m *ListImplementationsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ListImplementationsResponse.DiscardUnknown(m) +func (m *ResolveServiceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ResolveServiceResponse.DiscardUnknown(m) } -var xxx_messageInfo_ListImplementationsResponse proto.InternalMessageInfo +var xxx_messageInfo_ResolveServiceResponse proto.InternalMessageInfo -func (m *ListImplementationsResponse) GetImplementationMessageNames() []string { +func (m *ResolveServiceResponse) GetRawDescriptor() []byte { if m != nil { - return m.ImplementationMessageNames + return m.RawDescriptor } return nil } -func init() { - proto.RegisterType((*ListAllInterfacesRequest)(nil), "cosmos.base.reflection.v1beta1.ListAllInterfacesRequest") - proto.RegisterType((*ListAllInterfacesResponse)(nil), "cosmos.base.reflection.v1beta1.ListAllInterfacesResponse") - proto.RegisterType((*ListImplementationsRequest)(nil), "cosmos.base.reflection.v1beta1.ListImplementationsRequest") - proto.RegisterType((*ListImplementationsResponse)(nil), "cosmos.base.reflection.v1beta1.ListImplementationsResponse") +type ListDeliverablesRequest struct { } -func init() { - proto.RegisterFile("cosmos/base/reflection/v1beta1/reflection.proto", fileDescriptor_d48c054165687f5c) +func (m *ListDeliverablesRequest) Reset() { *m = ListDeliverablesRequest{} } +func (m *ListDeliverablesRequest) String() string { return proto.CompactTextString(m) } +func (*ListDeliverablesRequest) ProtoMessage() {} +func (*ListDeliverablesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d48c054165687f5c, []int{4} } - -var fileDescriptor_d48c054165687f5c = []byte{ - // 395 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4f, 0xce, 0x2f, 0xce, - 0xcd, 0x2f, 0xd6, 0x4f, 0x4a, 0x2c, 0x4e, 0xd5, 0x2f, 0x4a, 0x4d, 0xcb, 0x49, 0x4d, 0x2e, 0xc9, - 0xcc, 0xcf, 0xd3, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0x44, 0x12, 0xd2, 0x2b, 0x28, 0xca, - 0x2f, 0xc9, 0x17, 0x92, 0x83, 0x68, 0xd0, 0x03, 0x69, 0xd0, 0x43, 0x92, 0x85, 0x6a, 0x90, 0x92, - 0x49, 0xcf, 0xcf, 0x4f, 0xcf, 0x49, 0xd5, 0x4f, 0x2c, 0xc8, 0xd4, 0x4f, 0xcc, 0xcb, 0xcb, 0x2f, - 0x49, 0x04, 0x49, 0x17, 0x43, 0x74, 0x2b, 0x49, 0x71, 0x49, 0xf8, 0x64, 0x16, 0x97, 0x38, 0xe6, - 0xe4, 0x78, 0xe6, 0x95, 0xa4, 0x16, 0xa5, 0x25, 0x26, 0xa7, 0x16, 0x07, 0xa5, 0x16, 0x96, 0xa6, - 0x16, 0x97, 0x28, 0xb9, 0x70, 0x49, 0x62, 0x91, 0x2b, 0x2e, 0xc8, 0xcf, 0x2b, 0x4e, 0x15, 0x52, - 0xe7, 0xe2, 0xcf, 0x84, 0x89, 0xc6, 0xe7, 0x25, 0xe6, 0xa6, 0x16, 0x4b, 0x30, 0x2a, 0x30, 0x6b, - 0x70, 0x06, 0xf1, 0xc1, 0x85, 0xfd, 0x40, 0xa2, 0x4a, 0xce, 0x5c, 0x52, 0x20, 0x53, 0x3c, 0x73, - 0x0b, 0x72, 0x52, 0x73, 0x53, 0xf3, 0xa0, 0xd6, 0x43, 0xed, 0x10, 0x52, 0xe5, 0xe2, 0x43, 0x35, - 0x46, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x88, 0x17, 0xc5, 0x14, 0xa5, 0x78, 0x2e, 0x69, 0xac, - 0x86, 0x40, 0x1d, 0xe3, 0xc0, 0x25, 0x93, 0x89, 0x22, 0x15, 0x9f, 0x9b, 0x5a, 0x5c, 0x9c, 0x98, - 0x8e, 0xea, 0x32, 0x29, 0x54, 0x35, 0xbe, 0x10, 0x25, 0x60, 0x57, 0x1a, 0xed, 0x60, 0xe6, 0x12, - 0x0c, 0x82, 0x07, 0x5e, 0x70, 0x6a, 0x51, 0x59, 0x66, 0x72, 0xaa, 0xd0, 0x1e, 0x46, 0x2e, 0x41, - 0x8c, 0x20, 0x10, 0xb2, 0xd0, 0xc3, 0x1f, 0xe4, 0x7a, 0xb8, 0x42, 0x54, 0xca, 0x92, 0x0c, 0x9d, - 0x10, 0x2f, 0x2a, 0x19, 0x35, 0x5d, 0x7e, 0x32, 0x99, 0x49, 0x47, 0x48, 0x8b, 0x50, 0x02, 0xc9, - 0x44, 0x38, 0xf4, 0x31, 0x23, 0x97, 0x30, 0x96, 0x60, 0x13, 0xb2, 0x22, 0xc6, 0x19, 0xd8, 0x23, - 0x4c, 0xca, 0x9a, 0x2c, 0xbd, 0x50, 0x4f, 0x04, 0x83, 0x3d, 0xe1, 0x2b, 0xe4, 0x4d, 0xbc, 0x27, - 0xf4, 0xab, 0x51, 0xd3, 0x47, 0xad, 0x3e, 0x6a, 0x2c, 0x16, 0x3b, 0xf9, 0x9e, 0x78, 0x24, 0xc7, - 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, - 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x71, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, - 0x7e, 0x2e, 0xcc, 0x42, 0x08, 0xa5, 0x5b, 0x9c, 0x92, 0xad, 0x9f, 0x9c, 0x93, 0x99, 0x9a, 0x57, - 0xa2, 0x9f, 0x5e, 0x54, 0x90, 0x8c, 0xe4, 0x84, 0x24, 0x36, 0x70, 0xc6, 0x30, 0x06, 0x04, 0x00, - 0x00, 0xff, 0xff, 0x32, 0x5b, 0x2b, 0x51, 0x89, 0x03, 0x00, 0x00, +func (m *ListDeliverablesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListDeliverablesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListDeliverablesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListDeliverablesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListDeliverablesRequest.Merge(m, src) +} +func (m *ListDeliverablesRequest) XXX_Size() int { + return m.Size() +} +func (m *ListDeliverablesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListDeliverablesRequest.DiscardUnknown(m) } -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +var xxx_messageInfo_ListDeliverablesRequest proto.InternalMessageInfo -// ReflectionServiceClient is the client API for ReflectionService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type ReflectionServiceClient interface { - // ListAllInterfaces lists all the interfaces registered in the interface - // registry. - ListAllInterfaces(ctx context.Context, in *ListAllInterfacesRequest, opts ...grpc.CallOption) (*ListAllInterfacesResponse, error) - // ListImplementations list all the concrete types that implement a given - // interface. - ListImplementations(ctx context.Context, in *ListImplementationsRequest, opts ...grpc.CallOption) (*ListImplementationsResponse, error) +type ListDeliverablesResponse struct { + Deliverables []*DeliverableDescriptor `protobuf:"bytes,1,rep,name=deliverables,proto3" json:"deliverables,omitempty"` } -type reflectionServiceClient struct { - cc grpc1.ClientConn +func (m *ListDeliverablesResponse) Reset() { *m = ListDeliverablesResponse{} } +func (m *ListDeliverablesResponse) String() string { return proto.CompactTextString(m) } +func (*ListDeliverablesResponse) ProtoMessage() {} +func (*ListDeliverablesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d48c054165687f5c, []int{5} } - -func NewReflectionServiceClient(cc grpc1.ClientConn) ReflectionServiceClient { - return &reflectionServiceClient{cc} +func (m *ListDeliverablesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) } - -func (c *reflectionServiceClient) ListAllInterfaces(ctx context.Context, in *ListAllInterfacesRequest, opts ...grpc.CallOption) (*ListAllInterfacesResponse, error) { - out := new(ListAllInterfacesResponse) - err := c.cc.Invoke(ctx, "/cosmos.base.reflection.v1beta1.ReflectionService/ListAllInterfaces", in, out, opts...) - if err != nil { - return nil, err +func (m *ListDeliverablesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListDeliverablesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return out, nil +} +func (m *ListDeliverablesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListDeliverablesResponse.Merge(m, src) +} +func (m *ListDeliverablesResponse) XXX_Size() int { + return m.Size() +} +func (m *ListDeliverablesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListDeliverablesResponse.DiscardUnknown(m) } -func (c *reflectionServiceClient) ListImplementations(ctx context.Context, in *ListImplementationsRequest, opts ...grpc.CallOption) (*ListImplementationsResponse, error) { - out := new(ListImplementationsResponse) - err := c.cc.Invoke(ctx, "/cosmos.base.reflection.v1beta1.ReflectionService/ListImplementations", in, out, opts...) - if err != nil { - return nil, err +var xxx_messageInfo_ListDeliverablesResponse proto.InternalMessageInfo + +func (m *ListDeliverablesResponse) GetDeliverables() []*DeliverableDescriptor { + if m != nil { + return m.Deliverables } - return out, nil + return nil } -// ReflectionServiceServer is the server API for ReflectionService service. -type ReflectionServiceServer interface { - // ListAllInterfaces lists all the interfaces registered in the interface - // registry. - ListAllInterfaces(context.Context, *ListAllInterfacesRequest) (*ListAllInterfacesResponse, error) - // ListImplementations list all the concrete types that implement a given - // interface. - ListImplementations(context.Context, *ListImplementationsRequest) (*ListImplementationsResponse, error) +type DeliverableDescriptor struct { + Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` + ProtoName string `protobuf:"bytes,2,opt,name=proto_name,json=protoName,proto3" json:"proto_name,omitempty"` } -// UnimplementedReflectionServiceServer can be embedded to have forward compatible implementations. -type UnimplementedReflectionServiceServer struct { +func (m *DeliverableDescriptor) Reset() { *m = DeliverableDescriptor{} } +func (m *DeliverableDescriptor) String() string { return proto.CompactTextString(m) } +func (*DeliverableDescriptor) ProtoMessage() {} +func (*DeliverableDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_d48c054165687f5c, []int{6} } - -func (*UnimplementedReflectionServiceServer) ListAllInterfaces(ctx context.Context, req *ListAllInterfacesRequest) (*ListAllInterfacesResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ListAllInterfaces not implemented") +func (m *DeliverableDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) } -func (*UnimplementedReflectionServiceServer) ListImplementations(ctx context.Context, req *ListImplementationsRequest) (*ListImplementationsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ListImplementations not implemented") +func (m *DeliverableDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DeliverableDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } } - -func RegisterReflectionServiceServer(s grpc1.Server, srv ReflectionServiceServer) { - s.RegisterService(&_ReflectionService_serviceDesc, srv) +func (m *DeliverableDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeliverableDescriptor.Merge(m, src) +} +func (m *DeliverableDescriptor) XXX_Size() int { + return m.Size() +} +func (m *DeliverableDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_DeliverableDescriptor.DiscardUnknown(m) } -func _ReflectionService_ListAllInterfaces_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ListAllInterfacesRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ReflectionServiceServer).ListAllInterfaces(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/cosmos.base.reflection.v1beta1.ReflectionService/ListAllInterfaces", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ReflectionServiceServer).ListAllInterfaces(ctx, req.(*ListAllInterfacesRequest)) +var xxx_messageInfo_DeliverableDescriptor proto.InternalMessageInfo + +func (m *DeliverableDescriptor) GetMethod() string { + if m != nil { + return m.Method } - return interceptor(ctx, in, info, handler) + return "" } -func _ReflectionService_ListImplementations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ListImplementationsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ReflectionServiceServer).ListImplementations(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/cosmos.base.reflection.v1beta1.ReflectionService/ListImplementations", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ReflectionServiceServer).ListImplementations(ctx, req.(*ListImplementationsRequest)) +func (m *DeliverableDescriptor) GetProtoName() string { + if m != nil { + return m.ProtoName } - return interceptor(ctx, in, info, handler) + return "" } -var _ReflectionService_serviceDesc = grpc.ServiceDesc{ - ServiceName: "cosmos.base.reflection.v1beta1.ReflectionService", - HandlerType: (*ReflectionServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "ListAllInterfaces", - Handler: _ReflectionService_ListAllInterfaces_Handler, - }, - { - MethodName: "ListImplementations", - Handler: _ReflectionService_ListImplementations_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "cosmos/base/reflection/v1beta1/reflection.proto", +type ListQueriesRequest struct { } -func (m *ListAllInterfacesRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil +func (m *ListQueriesRequest) Reset() { *m = ListQueriesRequest{} } +func (m *ListQueriesRequest) String() string { return proto.CompactTextString(m) } +func (*ListQueriesRequest) ProtoMessage() {} +func (*ListQueriesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d48c054165687f5c, []int{7} } - -func (m *ListAllInterfacesRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (m *ListQueriesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) } - -func (m *ListAllInterfacesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil +func (m *ListQueriesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListQueriesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListQueriesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListQueriesRequest.Merge(m, src) +} +func (m *ListQueriesRequest) XXX_Size() int { + return m.Size() +} +func (m *ListQueriesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListQueriesRequest.DiscardUnknown(m) } -func (m *ListAllInterfacesResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err +var xxx_messageInfo_ListQueriesRequest proto.InternalMessageInfo + +type ListQueriesResponse struct { + Queries []*QueryDescriptor `protobuf:"bytes,1,rep,name=queries,proto3" json:"queries,omitempty"` +} + +func (m *ListQueriesResponse) Reset() { *m = ListQueriesResponse{} } +func (m *ListQueriesResponse) String() string { return proto.CompactTextString(m) } +func (*ListQueriesResponse) ProtoMessage() {} +func (*ListQueriesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d48c054165687f5c, []int{8} +} +func (m *ListQueriesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListQueriesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListQueriesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return dAtA[:n], nil +} +func (m *ListQueriesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListQueriesResponse.Merge(m, src) +} +func (m *ListQueriesResponse) XXX_Size() int { + return m.Size() +} +func (m *ListQueriesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListQueriesResponse.DiscardUnknown(m) } -func (m *ListAllInterfacesResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +var xxx_messageInfo_ListQueriesResponse proto.InternalMessageInfo + +func (m *ListQueriesResponse) GetQueries() []*QueryDescriptor { + if m != nil { + return m.Queries + } + return nil } -func (m *ListAllInterfacesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.InterfaceNames) > 0 { - for iNdEx := len(m.InterfaceNames) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.InterfaceNames[iNdEx]) - copy(dAtA[i:], m.InterfaceNames[iNdEx]) - i = encodeVarintReflection(dAtA, i, uint64(len(m.InterfaceNames[iNdEx]))) - i-- - dAtA[i] = 0xa +type QueryDescriptor struct { + ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` + ProtoFile string `protobuf:"bytes,2,opt,name=proto_file,json=protoFile,proto3" json:"proto_file,omitempty"` +} + +func (m *QueryDescriptor) Reset() { *m = QueryDescriptor{} } +func (m *QueryDescriptor) String() string { return proto.CompactTextString(m) } +func (*QueryDescriptor) ProtoMessage() {} +func (*QueryDescriptor) Descriptor() ([]byte, []int) { + return fileDescriptor_d48c054165687f5c, []int{9} +} +func (m *QueryDescriptor) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryDescriptor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryDescriptor.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err } + return b[:n], nil } - return len(dAtA) - i, nil +} +func (m *QueryDescriptor) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryDescriptor.Merge(m, src) +} +func (m *QueryDescriptor) XXX_Size() int { + return m.Size() +} +func (m *QueryDescriptor) XXX_DiscardUnknown() { + xxx_messageInfo_QueryDescriptor.DiscardUnknown(m) } -func (m *ListImplementationsRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err +var xxx_messageInfo_QueryDescriptor proto.InternalMessageInfo + +func (m *QueryDescriptor) GetServiceName() string { + if m != nil { + return m.ServiceName } - return dAtA[:n], nil + return "" } -func (m *ListImplementationsRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +func (m *QueryDescriptor) GetProtoFile() string { + if m != nil { + return m.ProtoFile + } + return "" } -func (m *ListImplementationsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.InterfaceName) > 0 { - i -= len(m.InterfaceName) - copy(dAtA[i:], m.InterfaceName) - i = encodeVarintReflection(dAtA, i, uint64(len(m.InterfaceName))) - i-- - dAtA[i] = 0xa +// ListAllInterfacesRequest is the request type of the ListAllInterfaces RPC. +type ListAllInterfacesRequest struct { +} + +func (m *ListAllInterfacesRequest) Reset() { *m = ListAllInterfacesRequest{} } +func (m *ListAllInterfacesRequest) String() string { return proto.CompactTextString(m) } +func (*ListAllInterfacesRequest) ProtoMessage() {} +func (*ListAllInterfacesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d48c054165687f5c, []int{10} +} +func (m *ListAllInterfacesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListAllInterfacesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListAllInterfacesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return len(dAtA) - i, nil +} +func (m *ListAllInterfacesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListAllInterfacesRequest.Merge(m, src) +} +func (m *ListAllInterfacesRequest) XXX_Size() int { + return m.Size() +} +func (m *ListAllInterfacesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListAllInterfacesRequest.DiscardUnknown(m) } -func (m *ListImplementationsResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err +var xxx_messageInfo_ListAllInterfacesRequest proto.InternalMessageInfo + +// ListAllInterfacesResponse is the response type of the ListAllInterfaces RPC. +type ListAllInterfacesResponse struct { + // interface_names is an array of all the registered interfaces. + InterfaceNames []string `protobuf:"bytes,1,rep,name=interface_names,json=interfaceNames,proto3" json:"interface_names,omitempty"` +} + +func (m *ListAllInterfacesResponse) Reset() { *m = ListAllInterfacesResponse{} } +func (m *ListAllInterfacesResponse) String() string { return proto.CompactTextString(m) } +func (*ListAllInterfacesResponse) ProtoMessage() {} +func (*ListAllInterfacesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d48c054165687f5c, []int{11} +} +func (m *ListAllInterfacesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListAllInterfacesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListAllInterfacesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil } - return dAtA[:n], nil +} +func (m *ListAllInterfacesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListAllInterfacesResponse.Merge(m, src) +} +func (m *ListAllInterfacesResponse) XXX_Size() int { + return m.Size() +} +func (m *ListAllInterfacesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListAllInterfacesResponse.DiscardUnknown(m) } -func (m *ListImplementationsResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) +var xxx_messageInfo_ListAllInterfacesResponse proto.InternalMessageInfo + +func (m *ListAllInterfacesResponse) GetInterfaceNames() []string { + if m != nil { + return m.InterfaceNames + } + return nil } -func (m *ListImplementationsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ImplementationMessageNames) > 0 { - for iNdEx := len(m.ImplementationMessageNames) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.ImplementationMessageNames[iNdEx]) - copy(dAtA[i:], m.ImplementationMessageNames[iNdEx]) - i = encodeVarintReflection(dAtA, i, uint64(len(m.ImplementationMessageNames[iNdEx]))) - i-- - dAtA[i] = 0xa +// ListImplementationsRequest is the request type of the ListImplementations +// RPC. +type ListImplementationsRequest struct { + // interface_name defines the interface to query the implementations for. + InterfaceName string `protobuf:"bytes,1,opt,name=interface_name,json=interfaceName,proto3" json:"interface_name,omitempty"` +} + +func (m *ListImplementationsRequest) Reset() { *m = ListImplementationsRequest{} } +func (m *ListImplementationsRequest) String() string { return proto.CompactTextString(m) } +func (*ListImplementationsRequest) ProtoMessage() {} +func (*ListImplementationsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d48c054165687f5c, []int{12} +} +func (m *ListImplementationsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListImplementationsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListImplementationsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err } + return b[:n], nil } - return len(dAtA) - i, nil +} +func (m *ListImplementationsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListImplementationsRequest.Merge(m, src) +} +func (m *ListImplementationsRequest) XXX_Size() int { + return m.Size() +} +func (m *ListImplementationsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ListImplementationsRequest.DiscardUnknown(m) } -func encodeVarintReflection(dAtA []byte, offset int, v uint64) int { - offset -= sovReflection(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +var xxx_messageInfo_ListImplementationsRequest proto.InternalMessageInfo + +func (m *ListImplementationsRequest) GetInterfaceName() string { + if m != nil { + return m.InterfaceName } - dAtA[offset] = uint8(v) - return base + return "" } -func (m *ListAllInterfacesRequest) Size() (n int) { - if m == nil { - return 0 + +// ListImplementationsResponse is the response type of the ListImplementations +// RPC. +type ListImplementationsResponse struct { + // implementation_message_names returns the names as saved in the codec + ImplementationMessageNames []string `protobuf:"bytes,1,rep,name=implementation_message_names,json=implementationMessageNames,proto3" json:"implementation_message_names,omitempty"` + // implementation_message_proto_names returns the protobuf names of the implementers + ImplementationMessageProtoNames []string `protobuf:"bytes,2,rep,name=implementation_message_proto_names,json=implementationMessageProtoNames,proto3" json:"implementation_message_proto_names,omitempty"` +} + +func (m *ListImplementationsResponse) Reset() { *m = ListImplementationsResponse{} } +func (m *ListImplementationsResponse) String() string { return proto.CompactTextString(m) } +func (*ListImplementationsResponse) ProtoMessage() {} +func (*ListImplementationsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d48c054165687f5c, []int{13} +} +func (m *ListImplementationsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ListImplementationsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ListImplementationsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ListImplementationsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListImplementationsResponse.Merge(m, src) +} +func (m *ListImplementationsResponse) XXX_Size() int { + return m.Size() +} +func (m *ListImplementationsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ListImplementationsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ListImplementationsResponse proto.InternalMessageInfo + +func (m *ListImplementationsResponse) GetImplementationMessageNames() []string { + if m != nil { + return m.ImplementationMessageNames + } + return nil +} + +func (m *ListImplementationsResponse) GetImplementationMessageProtoNames() []string { + if m != nil { + return m.ImplementationMessageProtoNames + } + return nil +} + +func init() { + proto.RegisterType((*ResolveProtoTypeRequest)(nil), "cosmos.base.reflection.v1beta1.ResolveProtoTypeRequest") + proto.RegisterType((*ResolveProtoTypeResponse)(nil), "cosmos.base.reflection.v1beta1.ResolveProtoTypeResponse") + proto.RegisterType((*ResolveServiceRequest)(nil), "cosmos.base.reflection.v1beta1.ResolveServiceRequest") + proto.RegisterType((*ResolveServiceResponse)(nil), "cosmos.base.reflection.v1beta1.ResolveServiceResponse") + proto.RegisterType((*ListDeliverablesRequest)(nil), "cosmos.base.reflection.v1beta1.ListDeliverablesRequest") + proto.RegisterType((*ListDeliverablesResponse)(nil), "cosmos.base.reflection.v1beta1.ListDeliverablesResponse") + proto.RegisterType((*DeliverableDescriptor)(nil), "cosmos.base.reflection.v1beta1.DeliverableDescriptor") + proto.RegisterType((*ListQueriesRequest)(nil), "cosmos.base.reflection.v1beta1.ListQueriesRequest") + proto.RegisterType((*ListQueriesResponse)(nil), "cosmos.base.reflection.v1beta1.ListQueriesResponse") + proto.RegisterType((*QueryDescriptor)(nil), "cosmos.base.reflection.v1beta1.QueryDescriptor") + proto.RegisterType((*ListAllInterfacesRequest)(nil), "cosmos.base.reflection.v1beta1.ListAllInterfacesRequest") + proto.RegisterType((*ListAllInterfacesResponse)(nil), "cosmos.base.reflection.v1beta1.ListAllInterfacesResponse") + proto.RegisterType((*ListImplementationsRequest)(nil), "cosmos.base.reflection.v1beta1.ListImplementationsRequest") + proto.RegisterType((*ListImplementationsResponse)(nil), "cosmos.base.reflection.v1beta1.ListImplementationsResponse") +} + +func init() { + proto.RegisterFile("cosmos/base/reflection/v1beta1/reflection.proto", fileDescriptor_d48c054165687f5c) +} + +var fileDescriptor_d48c054165687f5c = []byte{ + // 739 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xdf, 0x4e, 0x13, 0x4f, + 0x14, 0xee, 0xc2, 0x2f, 0xf0, 0xeb, 0x01, 0x8a, 0x8c, 0x02, 0x65, 0xc1, 0x15, 0x37, 0x21, 0x12, + 0x23, 0xdd, 0x50, 0x44, 0x51, 0x2f, 0xfc, 0x47, 0x4c, 0x08, 0x42, 0x70, 0xf1, 0x46, 0xbd, 0xc0, + 0xed, 0xf6, 0x50, 0x26, 0xee, 0x3f, 0x76, 0xb6, 0x45, 0x62, 0x34, 0xd1, 0x1b, 0x6f, 0x4d, 0x7c, + 0x0d, 0x1f, 0xc1, 0x07, 0xf0, 0x92, 0xc4, 0x1b, 0x2f, 0x0d, 0xf5, 0x41, 0xcc, 0xee, 0xcc, 0xb6, + 0xbb, 0xa5, 0xb5, 0x2d, 0x57, 0xed, 0x9e, 0x33, 0xdf, 0x37, 0xdf, 0x77, 0xce, 0x99, 0x19, 0xd0, + 0x4c, 0x97, 0xd9, 0x2e, 0xd3, 0x4a, 0x06, 0x43, 0xcd, 0xc7, 0x7d, 0x0b, 0xcd, 0x80, 0xba, 0x8e, + 0x56, 0x5b, 0x2e, 0x61, 0x60, 0x2c, 0x27, 0x42, 0x05, 0xcf, 0x77, 0x03, 0x97, 0x28, 0x1c, 0x50, + 0x08, 0x01, 0x85, 0x44, 0x56, 0x00, 0xe4, 0xb9, 0x8a, 0xeb, 0x56, 0x2c, 0xd4, 0x0c, 0x8f, 0x6a, + 0x86, 0xe3, 0xb8, 0x81, 0x11, 0xa6, 0x19, 0x47, 0xab, 0x4b, 0x30, 0xad, 0x23, 0x73, 0xad, 0x1a, + 0xee, 0x84, 0xdf, 0xcf, 0x8f, 0x3d, 0xd4, 0xf1, 0xb0, 0x8a, 0x2c, 0x20, 0x04, 0xfe, 0x73, 0x0c, + 0x1b, 0xf3, 0xd2, 0xbc, 0xb4, 0x98, 0xd5, 0xa3, 0xff, 0xea, 0x2b, 0xc8, 0x9f, 0x5d, 0xce, 0x3c, + 0xd7, 0x61, 0x48, 0x16, 0x20, 0xe7, 0x1b, 0x47, 0x7b, 0x65, 0x64, 0xa6, 0x4f, 0xbd, 0xc0, 0xf5, + 0x23, 0xe4, 0xa8, 0x3e, 0xe6, 0x1b, 0x47, 0xeb, 0x8d, 0x20, 0xc9, 0xc3, 0x30, 0x75, 0xca, 0xf8, + 0x16, 0x59, 0x7e, 0x60, 0x7e, 0x70, 0x71, 0x50, 0x8f, 0x3f, 0xd5, 0x9b, 0x30, 0x29, 0xc8, 0x77, + 0xd1, 0xaf, 0x51, 0xb3, 0xa1, 0x64, 0x16, 0xb2, 0xfb, 0xd4, 0xc2, 0xbd, 0x84, 0x9c, 0xff, 0xc3, + 0xc0, 0x76, 0x28, 0xe9, 0x3e, 0x4c, 0xb5, 0xa2, 0xfa, 0x12, 0xa4, 0xce, 0xc0, 0xf4, 0x53, 0xca, + 0x82, 0x75, 0xb4, 0x68, 0x0d, 0x7d, 0xa3, 0x64, 0x21, 0x13, 0x1b, 0xab, 0x55, 0xc8, 0x9f, 0x4d, + 0x09, 0xf6, 0x17, 0x30, 0x5a, 0x4e, 0xc4, 0xf3, 0xd2, 0xfc, 0xe0, 0xe2, 0x48, 0x71, 0xb5, 0xf0, + 0xef, 0x76, 0x14, 0x12, 0x5c, 0x4d, 0x0d, 0x7a, 0x8a, 0x4a, 0xdd, 0x86, 0xc9, 0xb6, 0xcb, 0xc8, + 0x14, 0x0c, 0xd9, 0x18, 0x1c, 0xb8, 0x65, 0x51, 0x05, 0xf1, 0x45, 0x2e, 0x03, 0x44, 0xed, 0xe4, + 0x15, 0x1a, 0x88, 0x72, 0xd9, 0x28, 0x12, 0x95, 0xe8, 0x12, 0x90, 0xd0, 0xc6, 0xb3, 0x2a, 0xfa, + 0xb4, 0x69, 0xee, 0x35, 0x5c, 0x4c, 0x45, 0x85, 0xaf, 0x0d, 0x18, 0x3e, 0xe4, 0x21, 0x61, 0x49, + 0xeb, 0x66, 0x29, 0x64, 0x38, 0x4e, 0x98, 0x89, 0xf1, 0xea, 0x2e, 0x8c, 0xb7, 0xe4, 0xc8, 0x55, + 0x18, 0x65, 0xbc, 0x4d, 0xc9, 0x6e, 0x8e, 0x88, 0x58, 0xa8, 0xb6, 0x69, 0x26, 0x6c, 0x71, 0xca, + 0xcc, 0x13, 0x6a, 0xa1, 0x2a, 0xf3, 0x9e, 0x3c, 0xb4, 0xac, 0x0d, 0x27, 0x40, 0x7f, 0xdf, 0x30, + 0x9b, 0x96, 0xd6, 0x61, 0xa6, 0x4d, 0x4e, 0x18, 0xbb, 0x06, 0xe3, 0x34, 0x8e, 0x46, 0x9b, 0x73, + 0x83, 0x59, 0x3d, 0xd7, 0x08, 0x87, 0xfb, 0x33, 0xf5, 0x31, 0xc8, 0x21, 0xcb, 0x86, 0xed, 0x59, + 0x68, 0xa3, 0x23, 0x0e, 0x4c, 0x3c, 0x8c, 0x0b, 0x90, 0x4b, 0xd3, 0x08, 0x0f, 0x63, 0x29, 0x16, + 0xf5, 0x9b, 0x04, 0xb3, 0x6d, 0x59, 0x84, 0x9a, 0x07, 0x30, 0x47, 0x53, 0xa9, 0x3d, 0x1b, 0x19, + 0x33, 0x2a, 0x69, 0x69, 0x72, 0x7a, 0xcd, 0x16, 0x5f, 0x12, 0xc9, 0x24, 0x9b, 0xa0, 0x76, 0x60, + 0x68, 0xce, 0x02, 0x3f, 0x63, 0x59, 0xfd, 0x4a, 0x5b, 0x9e, 0x9d, 0x78, 0x42, 0x58, 0xf1, 0x64, + 0x18, 0x26, 0xf4, 0x46, 0x6b, 0xc5, 0x49, 0x22, 0xdf, 0x25, 0x98, 0x38, 0x53, 0x50, 0xb2, 0xd6, + 0x6d, 0x20, 0x3a, 0xf5, 0x47, 0xbe, 0x73, 0x0e, 0x24, 0xaf, 0x97, 0x5a, 0xfc, 0xf4, 0xf3, 0xcf, + 0xd7, 0x81, 0x1b, 0xe4, 0x7a, 0xb7, 0x0b, 0x92, 0x36, 0x85, 0xd6, 0x25, 0x3e, 0xe2, 0x2d, 0x3d, + 0x20, 0x77, 0x7b, 0x91, 0xd1, 0xbe, 0xfd, 0xf2, 0xbd, 0x73, 0x61, 0x85, 0x89, 0xdd, 0xc8, 0xc4, + 0x16, 0xd9, 0xec, 0xdd, 0x84, 0xf6, 0x2e, 0x3d, 0x6d, 0xef, 0x35, 0xda, 0xe2, 0xe6, 0xb3, 0x04, + 0x17, 0x5a, 0x6f, 0x29, 0x72, 0xbb, 0x17, 0x99, 0x6d, 0xae, 0x3c, 0x79, 0xad, 0x7f, 0xa0, 0x30, + 0x97, 0x21, 0x1f, 0xf8, 0xb4, 0x44, 0x67, 0x5e, 0x8c, 0x10, 0x23, 0xc5, 0x5e, 0x08, 0xd3, 0x57, + 0x93, 0xbc, 0xd2, 0x17, 0xa6, 0xb1, 0x7f, 0x58, 0x89, 0xd6, 0xe7, 0xa9, 0x7b, 0x25, 0x3a, 0xbc, + 0x7f, 0xdd, 0x2b, 0xd1, 0xe9, 0x25, 0x54, 0x33, 0xe4, 0xa3, 0x04, 0xb9, 0xf4, 0xab, 0x44, 0x56, + 0x7b, 0xa4, 0x4b, 0xbf, 0x7d, 0xf2, 0xad, 0x7e, 0x61, 0xb1, 0x86, 0x47, 0x5b, 0x3f, 0x4e, 0x15, + 0xe9, 0xe4, 0x54, 0x91, 0x7e, 0x9f, 0x2a, 0xd2, 0x97, 0xba, 0x92, 0x39, 0xa9, 0x2b, 0x99, 0x5f, + 0x75, 0x25, 0xf3, 0x72, 0xa5, 0x42, 0x83, 0x83, 0x6a, 0xa9, 0x60, 0xba, 0x76, 0x3c, 0x88, 0xfc, + 0x67, 0x89, 0x95, 0xdf, 0x68, 0xa6, 0x45, 0xd1, 0x09, 0xb4, 0x8a, 0xef, 0x99, 0x89, 0xd1, 0x2c, + 0x0d, 0x45, 0xb7, 0xca, 0xca, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x48, 0xfe, 0x99, 0x9f, 0xa1, + 0x08, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// ReflectionServiceClient is the client API for ReflectionService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type ReflectionServiceClient interface { + // ListAllInterfaces lists all the interfaces registered in the interface + // registry. + ListAllInterfaces(ctx context.Context, in *ListAllInterfacesRequest, opts ...grpc.CallOption) (*ListAllInterfacesResponse, error) + // ListImplementations list all the concrete types that implement a given + // interface. + ListImplementations(ctx context.Context, in *ListImplementationsRequest, opts ...grpc.CallOption) (*ListImplementationsResponse, error) + // ListDeliverables provides a list of all the messages that can be passed to the + // deliver tx endpoint of the tendermint node for the application + ListDeliverables(ctx context.Context, in *ListDeliverablesRequest, opts ...grpc.CallOption) (*ListDeliverablesResponse, error) + // ListQueries lists the queries that the application supports + ListQueryServices(ctx context.Context, in *ListQueriesRequest, opts ...grpc.CallOption) (*ListQueriesResponse, error) + // ResolveProtoType returns the raw descriptor of the given type + ResolveProtoType(ctx context.Context, in *ResolveProtoTypeRequest, opts ...grpc.CallOption) (*ResolveProtoTypeResponse, error) + ResolveService(ctx context.Context, in *ResolveServiceRequest, opts ...grpc.CallOption) (*ResolveServiceResponse, error) +} + +type reflectionServiceClient struct { + cc grpc1.ClientConn +} + +func NewReflectionServiceClient(cc grpc1.ClientConn) ReflectionServiceClient { + return &reflectionServiceClient{cc} +} + +func (c *reflectionServiceClient) ListAllInterfaces(ctx context.Context, in *ListAllInterfacesRequest, opts ...grpc.CallOption) (*ListAllInterfacesResponse, error) { + out := new(ListAllInterfacesResponse) + err := c.cc.Invoke(ctx, "/cosmos.base.reflection.v1beta1.ReflectionService/ListAllInterfaces", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *reflectionServiceClient) ListImplementations(ctx context.Context, in *ListImplementationsRequest, opts ...grpc.CallOption) (*ListImplementationsResponse, error) { + out := new(ListImplementationsResponse) + err := c.cc.Invoke(ctx, "/cosmos.base.reflection.v1beta1.ReflectionService/ListImplementations", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *reflectionServiceClient) ListDeliverables(ctx context.Context, in *ListDeliverablesRequest, opts ...grpc.CallOption) (*ListDeliverablesResponse, error) { + out := new(ListDeliverablesResponse) + err := c.cc.Invoke(ctx, "/cosmos.base.reflection.v1beta1.ReflectionService/ListDeliverables", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *reflectionServiceClient) ListQueryServices(ctx context.Context, in *ListQueriesRequest, opts ...grpc.CallOption) (*ListQueriesResponse, error) { + out := new(ListQueriesResponse) + err := c.cc.Invoke(ctx, "/cosmos.base.reflection.v1beta1.ReflectionService/ListQueryServices", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *reflectionServiceClient) ResolveProtoType(ctx context.Context, in *ResolveProtoTypeRequest, opts ...grpc.CallOption) (*ResolveProtoTypeResponse, error) { + out := new(ResolveProtoTypeResponse) + err := c.cc.Invoke(ctx, "/cosmos.base.reflection.v1beta1.ReflectionService/ResolveProtoType", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *reflectionServiceClient) ResolveService(ctx context.Context, in *ResolveServiceRequest, opts ...grpc.CallOption) (*ResolveServiceResponse, error) { + out := new(ResolveServiceResponse) + err := c.cc.Invoke(ctx, "/cosmos.base.reflection.v1beta1.ReflectionService/ResolveService", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ReflectionServiceServer is the server API for ReflectionService service. +type ReflectionServiceServer interface { + // ListAllInterfaces lists all the interfaces registered in the interface + // registry. + ListAllInterfaces(context.Context, *ListAllInterfacesRequest) (*ListAllInterfacesResponse, error) + // ListImplementations list all the concrete types that implement a given + // interface. + ListImplementations(context.Context, *ListImplementationsRequest) (*ListImplementationsResponse, error) + // ListDeliverables provides a list of all the messages that can be passed to the + // deliver tx endpoint of the tendermint node for the application + ListDeliverables(context.Context, *ListDeliverablesRequest) (*ListDeliverablesResponse, error) + // ListQueries lists the queries that the application supports + ListQueryServices(context.Context, *ListQueriesRequest) (*ListQueriesResponse, error) + // ResolveProtoType returns the raw descriptor of the given type + ResolveProtoType(context.Context, *ResolveProtoTypeRequest) (*ResolveProtoTypeResponse, error) + ResolveService(context.Context, *ResolveServiceRequest) (*ResolveServiceResponse, error) +} + +// UnimplementedReflectionServiceServer can be embedded to have forward compatible implementations. +type UnimplementedReflectionServiceServer struct { +} + +func (*UnimplementedReflectionServiceServer) ListAllInterfaces(ctx context.Context, req *ListAllInterfacesRequest) (*ListAllInterfacesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListAllInterfaces not implemented") +} +func (*UnimplementedReflectionServiceServer) ListImplementations(ctx context.Context, req *ListImplementationsRequest) (*ListImplementationsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListImplementations not implemented") +} +func (*UnimplementedReflectionServiceServer) ListDeliverables(ctx context.Context, req *ListDeliverablesRequest) (*ListDeliverablesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListDeliverables not implemented") +} +func (*UnimplementedReflectionServiceServer) ListQueryServices(ctx context.Context, req *ListQueriesRequest) (*ListQueriesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListQueryServices not implemented") +} +func (*UnimplementedReflectionServiceServer) ResolveProtoType(ctx context.Context, req *ResolveProtoTypeRequest) (*ResolveProtoTypeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ResolveProtoType not implemented") +} +func (*UnimplementedReflectionServiceServer) ResolveService(ctx context.Context, req *ResolveServiceRequest) (*ResolveServiceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ResolveService not implemented") +} + +func RegisterReflectionServiceServer(s grpc1.Server, srv ReflectionServiceServer) { + s.RegisterService(&_ReflectionService_serviceDesc, srv) +} + +func _ReflectionService_ListAllInterfaces_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListAllInterfacesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).ListAllInterfaces(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.base.reflection.v1beta1.ReflectionService/ListAllInterfaces", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).ListAllInterfaces(ctx, req.(*ListAllInterfacesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReflectionService_ListImplementations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListImplementationsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).ListImplementations(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.base.reflection.v1beta1.ReflectionService/ListImplementations", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).ListImplementations(ctx, req.(*ListImplementationsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReflectionService_ListDeliverables_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListDeliverablesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).ListDeliverables(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.base.reflection.v1beta1.ReflectionService/ListDeliverables", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).ListDeliverables(ctx, req.(*ListDeliverablesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReflectionService_ListQueryServices_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListQueriesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).ListQueryServices(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.base.reflection.v1beta1.ReflectionService/ListQueryServices", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).ListQueryServices(ctx, req.(*ListQueriesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReflectionService_ResolveProtoType_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResolveProtoTypeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).ResolveProtoType(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.base.reflection.v1beta1.ReflectionService/ResolveProtoType", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).ResolveProtoType(ctx, req.(*ResolveProtoTypeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReflectionService_ResolveService_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResolveServiceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReflectionServiceServer).ResolveService(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.base.reflection.v1beta1.ReflectionService/ResolveService", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReflectionServiceServer).ResolveService(ctx, req.(*ResolveServiceRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _ReflectionService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cosmos.base.reflection.v1beta1.ReflectionService", + HandlerType: (*ReflectionServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ListAllInterfaces", + Handler: _ReflectionService_ListAllInterfaces_Handler, + }, + { + MethodName: "ListImplementations", + Handler: _ReflectionService_ListImplementations_Handler, + }, + { + MethodName: "ListDeliverables", + Handler: _ReflectionService_ListDeliverables_Handler, + }, + { + MethodName: "ListQueryServices", + Handler: _ReflectionService_ListQueryServices_Handler, + }, + { + MethodName: "ResolveProtoType", + Handler: _ReflectionService_ResolveProtoType_Handler, + }, + { + MethodName: "ResolveService", + Handler: _ReflectionService_ResolveService_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "cosmos/base/reflection/v1beta1/reflection.proto", +} + +func (m *ResolveProtoTypeRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResolveProtoTypeRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResolveProtoTypeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintReflection(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ResolveProtoTypeResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResolveProtoTypeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResolveProtoTypeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Indexes) > 0 { + dAtA2 := make([]byte, len(m.Indexes)*10) + var j1 int + for _, num1 := range m.Indexes { + num := uint64(num1) + for num >= 1<<7 { + dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA2[j1] = uint8(num) + j1++ + } + i -= j1 + copy(dAtA[i:], dAtA2[:j1]) + i = encodeVarintReflection(dAtA, i, uint64(j1)) + i-- + dAtA[i] = 0x12 + } + if len(m.RawDescriptor) > 0 { + i -= len(m.RawDescriptor) + copy(dAtA[i:], m.RawDescriptor) + i = encodeVarintReflection(dAtA, i, uint64(len(m.RawDescriptor))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ResolveServiceRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResolveServiceRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResolveServiceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.FileName) > 0 { + i -= len(m.FileName) + copy(dAtA[i:], m.FileName) + i = encodeVarintReflection(dAtA, i, uint64(len(m.FileName))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ResolveServiceResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResolveServiceResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResolveServiceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RawDescriptor) > 0 { + i -= len(m.RawDescriptor) + copy(dAtA[i:], m.RawDescriptor) + i = encodeVarintReflection(dAtA, i, uint64(len(m.RawDescriptor))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ListDeliverablesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListDeliverablesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListDeliverablesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *ListDeliverablesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListDeliverablesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListDeliverablesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Deliverables) > 0 { + for iNdEx := len(m.Deliverables) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Deliverables[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *DeliverableDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DeliverableDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DeliverableDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ProtoName) > 0 { + i -= len(m.ProtoName) + copy(dAtA[i:], m.ProtoName) + i = encodeVarintReflection(dAtA, i, uint64(len(m.ProtoName))) + i-- + dAtA[i] = 0x12 + } + if len(m.Method) > 0 { + i -= len(m.Method) + copy(dAtA[i:], m.Method) + i = encodeVarintReflection(dAtA, i, uint64(len(m.Method))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ListQueriesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListQueriesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListQueriesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *ListQueriesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListQueriesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListQueriesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Queries) > 0 { + for iNdEx := len(m.Queries) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Queries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReflection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryDescriptor) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryDescriptor) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryDescriptor) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ProtoFile) > 0 { + i -= len(m.ProtoFile) + copy(dAtA[i:], m.ProtoFile) + i = encodeVarintReflection(dAtA, i, uint64(len(m.ProtoFile))) + i-- + dAtA[i] = 0x12 + } + if len(m.ServiceName) > 0 { + i -= len(m.ServiceName) + copy(dAtA[i:], m.ServiceName) + i = encodeVarintReflection(dAtA, i, uint64(len(m.ServiceName))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ListAllInterfacesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListAllInterfacesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListAllInterfacesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *ListAllInterfacesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListAllInterfacesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListAllInterfacesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.InterfaceNames) > 0 { + for iNdEx := len(m.InterfaceNames) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.InterfaceNames[iNdEx]) + copy(dAtA[i:], m.InterfaceNames[iNdEx]) + i = encodeVarintReflection(dAtA, i, uint64(len(m.InterfaceNames[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ListImplementationsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListImplementationsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListImplementationsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.InterfaceName) > 0 { + i -= len(m.InterfaceName) + copy(dAtA[i:], m.InterfaceName) + i = encodeVarintReflection(dAtA, i, uint64(len(m.InterfaceName))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ListImplementationsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ListImplementationsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ListImplementationsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ImplementationMessageProtoNames) > 0 { + for iNdEx := len(m.ImplementationMessageProtoNames) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ImplementationMessageProtoNames[iNdEx]) + copy(dAtA[i:], m.ImplementationMessageProtoNames[iNdEx]) + i = encodeVarintReflection(dAtA, i, uint64(len(m.ImplementationMessageProtoNames[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.ImplementationMessageNames) > 0 { + for iNdEx := len(m.ImplementationMessageNames) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ImplementationMessageNames[iNdEx]) + copy(dAtA[i:], m.ImplementationMessageNames[iNdEx]) + i = encodeVarintReflection(dAtA, i, uint64(len(m.ImplementationMessageNames[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintReflection(dAtA []byte, offset int, v uint64) int { + offset -= sovReflection(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ResolveProtoTypeRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *ResolveProtoTypeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RawDescriptor) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + if len(m.Indexes) > 0 { + l = 0 + for _, e := range m.Indexes { + l += sovReflection(uint64(e)) + } + n += 1 + sovReflection(uint64(l)) + l + } + return n +} + +func (m *ResolveServiceRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.FileName) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *ResolveServiceResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RawDescriptor) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *ListDeliverablesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *ListDeliverablesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Deliverables) > 0 { + for _, e := range m.Deliverables { + l = e.Size() + n += 1 + l + sovReflection(uint64(l)) + } + } + return n +} + +func (m *DeliverableDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Method) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + l = len(m.ProtoName) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *ListQueriesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *ListQueriesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Queries) > 0 { + for _, e := range m.Queries { + l = e.Size() + n += 1 + l + sovReflection(uint64(l)) + } + } + return n +} + +func (m *QueryDescriptor) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ServiceName) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + l = len(m.ProtoFile) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *ListAllInterfacesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *ListAllInterfacesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.InterfaceNames) > 0 { + for _, s := range m.InterfaceNames { + l = len(s) + n += 1 + l + sovReflection(uint64(l)) + } + } + return n +} + +func (m *ListImplementationsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.InterfaceName) + if l > 0 { + n += 1 + l + sovReflection(uint64(l)) + } + return n +} + +func (m *ListImplementationsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ImplementationMessageNames) > 0 { + for _, s := range m.ImplementationMessageNames { + l = len(s) + n += 1 + l + sovReflection(uint64(l)) + } + } + if len(m.ImplementationMessageProtoNames) > 0 { + for _, s := range m.ImplementationMessageProtoNames { + l = len(s) + n += 1 + l + sovReflection(uint64(l)) + } + } + return n +} + +func sovReflection(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozReflection(x uint64) (n int) { + return sovReflection(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ResolveProtoTypeRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResolveProtoTypeRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResolveProtoTypeRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + 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 ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ResolveProtoTypeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResolveProtoTypeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResolveProtoTypeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RawDescriptor", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RawDescriptor = append(m.RawDescriptor[:0], dAtA[iNdEx:postIndex]...) + if m.RawDescriptor == nil { + m.RawDescriptor = []byte{} + } + iNdEx = postIndex + case 2: + if wireType == 0 { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Indexes = append(m.Indexes, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.Indexes) == 0 { + m.Indexes = make([]int64, 0, elementCount) + } + for iNdEx < postIndex { + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Indexes = append(m.Indexes, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Indexes", wireType) + } + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ResolveServiceRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResolveServiceRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResolveServiceRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FileName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + 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 ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FileName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ResolveServiceResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResolveServiceResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResolveServiceResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RawDescriptor", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RawDescriptor = append(m.RawDescriptor[:0], dAtA[iNdEx:postIndex]...) + if m.RawDescriptor == nil { + m.RawDescriptor = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ListDeliverablesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListDeliverablesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListDeliverablesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ListDeliverablesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListDeliverablesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListDeliverablesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Deliverables", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Deliverables = append(m.Deliverables, &DeliverableDescriptor{}) + if err := m.Deliverables[len(m.Deliverables)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DeliverableDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DeliverableDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DeliverableDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Method", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + 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 ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Method = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProtoName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + 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 ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProtoName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ListQueriesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListQueriesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListQueriesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } } - var l int - _ = l - return n -} -func (m *ListAllInterfacesResponse) Size() (n int) { - if m == nil { - return 0 + if iNdEx > l { + return io.ErrUnexpectedEOF } - var l int - _ = l - if len(m.InterfaceNames) > 0 { - for _, s := range m.InterfaceNames { - l = len(s) - n += 1 + l + sovReflection(uint64(l)) + return nil +} +func (m *ListQueriesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListQueriesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListQueriesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Queries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReflection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Queries = append(m.Queries, &QueryDescriptor{}) + if err := m.Queries[len(m.Queries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy } } - return n -} -func (m *ListImplementationsRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.InterfaceName) - if l > 0 { - n += 1 + l + sovReflection(uint64(l)) + if iNdEx > l { + return io.ErrUnexpectedEOF } - return n + return nil } - -func (m *ListImplementationsResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.ImplementationMessageNames) > 0 { - for _, s := range m.ImplementationMessageNames { - l = len(s) - n += 1 + l + sovReflection(uint64(l)) +func (m *QueryDescriptor) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryDescriptor: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryDescriptor: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServiceName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + 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 ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServiceName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProtoFile", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + 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 ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProtoFile = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReflection(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReflection + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy } } - return n -} -func sovReflection(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozReflection(x uint64) (n int) { - return sovReflection(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil } func (m *ListAllInterfacesRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) @@ -829,6 +2864,38 @@ func (m *ListImplementationsResponse) Unmarshal(dAtA []byte) error { } m.ImplementationMessageNames = append(m.ImplementationMessageNames, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ImplementationMessageProtoNames", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReflection + } + 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 ErrInvalidLengthReflection + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReflection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ImplementationMessageProtoNames = append(m.ImplementationMessageProtoNames, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipReflection(dAtA[iNdEx:]) diff --git a/client/reflection/client/builder.go b/client/reflection/client/builder.go new file mode 100644 index 000000000000..b895818eea5e --- /dev/null +++ b/client/reflection/client/builder.go @@ -0,0 +1,231 @@ +package client + +import ( + "context" + "errors" + "fmt" + + tmrpc "github.com/tendermint/tendermint/rpc/client" + + "github.com/cosmos/cosmos-sdk/client/grpc/reflection" + "github.com/cosmos/cosmos-sdk/client/reflection/codec" + "github.com/cosmos/cosmos-sdk/client/reflection/descriptor" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// BuilderConfig defines the required *Builder configurations +type BuilderConfig struct { + // ProtoImporter is used to import proto files dynamically + ProtoImporter codec.ProtoImportsDownloader + // SDKReflectionClient is the client used to build the codec + // in a dynamic way, based on the chain the client is connected to. + SDKReflectionClient reflection.ReflectionServiceClient + // TMClient is the client used to interact with the tendermint endpoint + // for queries and transaction posting + TMClient tmrpc.Client + // AuthInfoProvider takes care of providing authentication information + // such as account sequence, number, address and signing capabilities. + AuthInfoProvider AccountInfoProvider +} + +// Builder is used to generate a *Client, it wraps all the logic +// required to build the *codec.Codec and the descriptor.Chain +type Builder struct { + tm tmrpc.Client + sdk reflection.ReflectionServiceClient + chainDesc *descriptor.Builder + cdc *codec.Codec + authInfoProvider AccountInfoProvider +} + +// NewBuilder instantiates a new *Client *Builder +func NewBuilder(opts BuilderConfig) *Builder { + return &Builder{ + tm: opts.TMClient, + sdk: opts.SDKReflectionClient, + chainDesc: descriptor.NewBuilder(), + cdc: codec.NewCodec(opts.ProtoImporter), + authInfoProvider: opts.AuthInfoProvider, + } +} + +func (b *Builder) Build(ctx context.Context) (*Client, error) { + err := b.queries(ctx) + if err != nil { + return nil, fmt.Errorf("unable to generate queries: %w", err) + } + + err = b.deliverables(ctx) + if err != nil { + return nil, fmt.Errorf("unable to generate deliverables: %w", err) + } + + err = b.resolveAnys(ctx) + if err != nil { + return nil, fmt.Errorf("unable to generate interfaces: %w", err) + } + + chainDesc, err := b.chainDesc.Build() + if err != nil { + return nil, fmt.Errorf("unable to generate chain descriptor: %w", err) + } + return &Client{ + tm: b.tm, + cdc: b.cdc, + accountInfoProvider: b.authInfoProvider, + chainDesc: chainDesc, + }, nil +} + +// queries attempts to build all the available query service +func (b *Builder) queries(ctx context.Context) error { + resp, err := b.sdk.ListQueryServices(ctx, nil) + if err != nil { + return err + } + + // iterate over files to parse the descriptors + for _, q := range resp.Queries { + // get raw descriptor + rawDesc, err := b.sdk.ResolveService(ctx, &reflection.ResolveServiceRequest{FileName: q.ProtoFile}) + if err != nil { + return fmt.Errorf("unable to get file descriptor for %s: %w", q.ProtoFile, err) + } + // register proto file + fd, err := b.cdc.RegisterRawFileDescriptor(ctx, rawDesc.RawDescriptor) + // we ignore file already registered errors + if err != nil && !errors.Is(err, codec.ErrFileRegistered) { + return fmt.Errorf("unable to register descriptor for %s: %w", q.ProtoFile, err) + } + // register query services in chain descriptor Builder + sds := fd.Services() + for i := 0; i < sds.Len(); i++ { + sd := sds.Get(i) + err = b.chainDesc.RegisterQueryService(sd) + if err != nil { + return fmt.Errorf("unable to compute chain query descriptor for %s: %w", q.ProtoFile, err) + } + } + } + + return nil +} + +func (b *Builder) deliverables(ctx context.Context) error { + // list sdk.Msg implementers + msgImplsResp, err := b.sdk.ListImplementations(ctx, &reflection.ListImplementationsRequest{ + InterfaceName: sdk.MsgInterfaceName, + }) + if err != nil { + return fmt.Errorf("unable to list sdk.Msg implementations: %w", err) + } + + // list sdk.ServiceMsg implementers + svcMsgImplsResp, err := b.sdk.ListImplementations(ctx, &reflection.ListImplementationsRequest{ + InterfaceName: sdk.ServiceMsgInterfaceName, + }) + if err != nil { + return fmt.Errorf("unable to list sdk.ServiceMsg implementations: %w", err) + } + // join the implementations as deliverables + deliverablesProtoNames := make( + []string, + 0, + len(msgImplsResp.ImplementationMessageProtoNames)+len(svcMsgImplsResp.ImplementationMessageProtoNames), + ) + + deliverablesProtoNames = append(deliverablesProtoNames, msgImplsResp.ImplementationMessageProtoNames...) + deliverablesProtoNames = append(deliverablesProtoNames, svcMsgImplsResp.ImplementationMessageProtoNames...) + + // we create a map which contains the message names that we expect to process + // so in case one file contains multiple messages we need then we won't need + // to resolve the same proto file multiple times :) + expectedMsgs := make(map[string]struct{}, len(deliverablesProtoNames)) + foundMsgs := make(map[string]struct{}, len(deliverablesProtoNames)) + for _, name := range deliverablesProtoNames { + expectedMsgs[name] = struct{}{} + } + + // now resolve types + for name := range expectedMsgs { + // check if we already processed it + if _, exists := foundMsgs[name]; exists { + continue + } + rptResp, err := b.sdk.ResolveProtoType(ctx, &reflection.ResolveProtoTypeRequest{Name: name}) + if err != nil { + return fmt.Errorf("unable to resolve proto type %s: %w", name, err) + } + desc, err := b.cdc.RegisterRawFileDescriptor(ctx, rptResp.RawDescriptor) + // TODO: we should most likely check if error is file already registered and if it is + // skip it as some people might define a module into a single proto file which we might have imported already + if err != nil { + return fmt.Errorf("unable to resolve proto type %s: %w", name, err) + } + // iterate over msgs + found := false // we assume to always find our message in the file descriptor... but still + for i := 0; i < desc.Messages().Len(); i++ { + msgDesc := desc.Messages().Get(i) + msgName := (string)(msgDesc.FullName()) + // check if msg is required + if _, required := expectedMsgs[msgName]; !required { + continue + } + // ok msg is required, so insert it in found list + foundMsgs[msgName] = struct{}{} + if msgName == name { + found = true + } + // save in msgs + err = b.chainDesc.RegisterDeliverable(msgDesc) + if err != nil { + return err + } + } + if !found { + return fmt.Errorf("unable to find message %s in resolved descriptor", name) + } + } + return nil +} + +// resolveAnys is gonna resolve all the concrete types we can have in *anypb.Any +// proto messages, we could do it in a different way by querying for the type registry +// but we do it in this way as in the future the sdk will provide interface identification +// for *anypb.Any field types which will allow this library to offer concrete type safety +// during marshalling, as now any proto.Message can be used to fill the type +func (b *Builder) resolveAnys(ctx context.Context) error { + ifaces, err := b.sdk.ListAllInterfaces(ctx, nil) + if err != nil { + return fmt.Errorf("unable to get interfaces list: %s", err) + } + // we list all applications available interfaces + for _, implementation := range ifaces.InterfaceNames { + implementers, err := b.sdk.ListImplementations(ctx, &reflection.ListImplementationsRequest{ + InterfaceName: implementation, + }) + if err != nil { + return fmt.Errorf("unable to list implementations for %s: %w", implementation, err) + } + + // register all implementers + for _, implementer := range implementers.ImplementationMessageProtoNames { + // if the type is known then we can skip + if b.cdc.KnownMessage(implementer) { + continue + } + // if unknown then solve + rawDesc, err := b.sdk.ResolveProtoType(ctx, &reflection.ResolveProtoTypeRequest{Name: implementer}) + if err != nil { + return fmt.Errorf("unable to resolve interface implemenenter %s concrete type %s: %w", implementation, implementer, err) + } + + _, err = b.cdc.RegisterRawFileDescriptor(ctx, rawDesc.RawDescriptor) + if err != nil { + return fmt.Errorf("unable to register descriptor for implementer %s concrete type %s: %w", implementation, implementer, err) + } + } + } + + return nil +} diff --git a/client/reflection/client/client.go b/client/reflection/client/client.go new file mode 100644 index 000000000000..2b634bd9d108 --- /dev/null +++ b/client/reflection/client/client.go @@ -0,0 +1,178 @@ +package client + +import ( + "context" + "fmt" + "log" + + tmrpc "github.com/tendermint/tendermint/rpc/client" + tmhttp "github.com/tendermint/tendermint/rpc/client/http" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + "google.golang.org/grpc" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/dynamicpb" + + "github.com/cosmos/cosmos-sdk/client/grpc/reflection" + "github.com/cosmos/cosmos-sdk/client/reflection/codec" + "github.com/cosmos/cosmos-sdk/client/reflection/descriptor" + "github.com/cosmos/cosmos-sdk/client/reflection/tx" + "github.com/cosmos/cosmos-sdk/client/reflection/unstructured" + "github.com/cosmos/cosmos-sdk/types" +) + +// Client defines a dynamic cosmos-sdk client, that can be used to query +// different cosmos sdk versions with different messages and available +// queries. +type Client struct { + tm tmrpc.Client + cdc *codec.Codec // chain specific codec generated at run time + accountInfoProvider AccountInfoProvider + chainDesc descriptor.Chain // chain specific descriptor generated at runtime +} + +// Dial is going to create a new client by dialing to the tendermint and gRPC endpoints of the provided application. +func Dial(ctx context.Context, grpcEndpoint, tmEndpoint string, accountInfoProvider AccountInfoProvider) (*Client, error) { + conn, err := grpc.Dial(grpcEndpoint, grpc.WithInsecure()) + if err != nil { + return nil, err + } + + sdkReflect := reflection.NewReflectionServiceClient(conn) + fetcher := protoDownloader{client: sdkReflect} + + tmRPC, err := tmhttp.New(tmEndpoint, "") + if err != nil { + return nil, err + } + + builder := NewBuilder(BuilderConfig{ + ProtoImporter: fetcher, + SDKReflectionClient: sdkReflect, + TMClient: tmRPC, + AuthInfoProvider: accountInfoProvider, + }) + c, err := builder.Build(ctx) + if err != nil { + return nil, err + } + + return c, nil +} + +// Codec exposes the client specific codec +func (c *Client) Codec() *codec.Codec { + return c.cdc +} + +func (c *Client) ChainDescriptor() descriptor.Chain { + return c.chainDesc +} + +// QueryTM routes the query via tendermint abci.Query, given the tendermint full query name +func (c *Client) QueryTM(ctx context.Context, method string, request proto.Message) (resp proto.Message, err error) { + desc := c.chainDesc.Queriers().ByTMName(method) + if desc == nil { + return nil, fmt.Errorf("unknown method: %s", method) + } + + reqBytes, err := c.cdc.Marshal(request) + if err != nil { + return nil, err + } + + tmResp, err := c.tm.ABCIQuery(ctx, method, reqBytes) + if err != nil { + return nil, err + } + + resp = dynamicpb.NewMessage(desc.Descriptor().Output()) + return resp, c.cdc.Unmarshal(tmResp.Response.Value, resp) +} + +func (c *Client) Query(ctx context.Context, request proto.Message) (resp proto.Message, err error) { + desc := c.chainDesc.Queriers().ByInput(request) + if desc == nil { + return nil, fmt.Errorf("unknown input: %s", request.ProtoReflect().Descriptor().FullName()) + } + return c.QueryTM(ctx, desc.TMQueryPath(), request) +} + +func (c *Client) QueryUnstructured(ctx context.Context, method string, request unstructured.Map) (resp proto.Message, err error) { + desc := c.chainDesc.Queriers().ByTMName(method) + if desc == nil { + return nil, fmt.Errorf("unknown method: %s", method) + } + + reqProto, err := request.Marshal(desc.Descriptor().Input()) + if err != nil { + return nil, fmt.Errorf("unable to marshal request to proto message: %w", err) + } + + b, err := c.cdc.Marshal(reqProto) + if err != nil { + return nil, err + } + + tmResp, err := c.tm.ABCIQuery(ctx, method, b) + if err != nil { + return nil, err + } + + resp = dynamicpb.NewMessage(desc.Descriptor().Output()) + return resp, c.cdc.Unmarshal(tmResp.Response.Value, resp) +} + +func (c *Client) Tx() *Tx { + return NewTx() +} + +func (c *Client) TxBeta(ctx context.Context, method string, request unstructured.Map, signerInfo tx.SignerInfo) (resp *ctypes.ResultBroadcastTxCommit, err error) { + msgDesc := c.chainDesc.Deliverables().ByName(method) + if msgDesc == nil { + return nil, fmt.Errorf("deliverable not found: %s", method) + } + // marshal unstructured to proto.Message type + pb, err := request.Marshal(msgDesc.Descriptor()) + if err != nil { + return nil, err + } + + pbJs, err := protojson.Marshal(pb) + if err != nil { + panic(err) + } + log.Printf("%s", pbJs) + uBuilder := tx.NewUnsignedTxBuilder() + uBuilder.AddMsg(pb) + uBuilder.AddSigner(signerInfo) + uBuilder.SetChainID("testing") + uBuilder.SetFeePayer("cosmos1ujtnemf6jmfm995j000qdry064n5lq854gfe3j") + uBuilder.SetFees(types.NewCoins(types.NewInt64Coin("stake", 10))) + uBuilder.SetGasLimit(2500000) + + sBuilder, err := uBuilder.SignedBuilder() + if err != nil { + return nil, err + } + + bytesToSign, err := sBuilder.BytesToSign(signerInfo.PubKey) + if err != nil { + return nil, err + } + + signedBytes, err := c.accountInfoProvider.Sign(ctx, signerInfo.PubKey, bytesToSign) + + err = sBuilder.SetSignature(signerInfo.PubKey, signedBytes) + if err != nil { + return nil, err + } + + txBytes, err := sBuilder.Bytes() + if err != nil { + return nil, err + } + + tmResp, err := c.tm.BroadcastTxCommit(ctx, txBytes) + return tmResp, err +} diff --git a/client/reflection/client/client_test.go b/client/reflection/client/client_test.go new file mode 100644 index 000000000000..6f71fe327ff4 --- /dev/null +++ b/client/reflection/client/client_test.go @@ -0,0 +1,140 @@ +package client + +import ( + "context" + "encoding/hex" + "testing" + + "google.golang.org/protobuf/encoding/protojson" + + "github.com/cosmos/cosmos-sdk/client/reflection/tx" + "github.com/cosmos/cosmos-sdk/client/reflection/unstructured" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" +) + +func TestClientListQueries(t *testing.T) { + +} + +func TestClient_ListDeliverables(t *testing.T) { + +} + +func TestClient_Query(t *testing.T) { + c, err := Dial(context.TODO(), "localhost:9090", "tcp://localhost:26657", nil) + if err != nil { + t.Fatal(err) + } + + t.Run("account test", func(t *testing.T) { + resp, err := c.QueryUnstructured(context.TODO(), "/cosmos.auth.v1beta1.Query/Account", unstructured.Map{ + "address": "cosmos1ujtnemf6jmfm995j000qdry064n5lq854gfe3j", + }) + if err != nil { + t.Fatal(err) + } + + b, err := c.cdc.MarshalJSON(resp) + if err != nil { + t.Fatal(err) + } + t.Logf("%s", b) + }) + + t.Run("bank test", func(t *testing.T) { + resp, err := c.QueryUnstructured(context.TODO(), "/cosmos.bank.v1beta1.Query/Balance", unstructured.Map{ + "address": "cosmos1ujtnemf6jmfm995j000qdry064n5lq854gfe3j", + "denom": "stake", + }) + + if err != nil { + t.Fatal(err) + } + + t.Log(resp) + + b, err := protojson.Marshal(resp) + if err != nil { + t.Fatal(err) + } + t.Logf("%s", b) + }) + + t.Run("params", func(t *testing.T) { + resp, err := c.QueryUnstructured(context.TODO(), "/cosmos.bank.v1beta1.Query/Params", unstructured.Map{}) + if err != nil { + t.Fatal(err) + } + t.Log(resp) + }) + +} + +type testInfoProvider struct { + pk cryptotypes.PrivKey + sequence uint64 + accountNumber uint64 +} + +func newInfoProvider(hexKey string, sequence, accountNumber uint64) testInfoProvider { + b, err := hex.DecodeString(hexKey) + if err != nil { + panic(err) + } + + pk := &secp256k1.PrivKey{Key: b} + return testInfoProvider{ + pk: pk, + sequence: sequence, + accountNumber: accountNumber, + } +} + +func (t testInfoProvider) SigningInfo(ctx context.Context, pubKey cryptotypes.PubKey) (accountNumber, sequence uint64, err error) { + panic("implement me") +} + +func (t testInfoProvider) Sign(ctx context.Context, pubKey cryptotypes.PubKey, b []byte) (signedBytes []byte, err error) { + return t.pk.Sign(b) +} + +func (t testInfoProvider) Address(ctx context.Context, pubKey cryptotypes.PubKey) (address string, err error) { + panic("implement mwe") +} + +func TestClient_Tx(t *testing.T) { + const keyHex = "8c7e006440ac5e358739bdc3d10a8b2d229e23d27660f6d3a8306cee4379594c" + const sequence uint64 = 3 + const accNum uint64 = 0 + infoProvider := newInfoProvider(keyHex, 0, 0) + c, err := Dial(context.TODO(), "localhost:9090", "tcp://localhost:26657", infoProvider) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TxBeta(context.TODO(), "cosmos.bank.v1beta1.MsgSend", + unstructured.Map{ + "from_address": "cosmos1ujtnemf6jmfm995j000qdry064n5lq854gfe3j", + "to_address": "cosmos1caa3es6q3mv8t4gksn9wjcwyzw7cnf5gn5cx7j", + "amount": []unstructured.Map{ + { + "denom": "stake", + "amount": "10", + }, + }, + }, + tx.SignerInfo{ + PubKey: infoProvider.pk.PubKey(), + SignMode: signing.SignMode_SIGN_MODE_DIRECT, + AccountNumber: accNum, + Sequence: sequence, + }) + + if err != nil { + t.Fatal(err) + } + + t.Logf("%#v", resp) +} diff --git a/client/reflection/client/export.go b/client/reflection/client/export.go new file mode 100644 index 000000000000..63046d291720 --- /dev/null +++ b/client/reflection/client/export.go @@ -0,0 +1,27 @@ +package client + +import ( + "io" + + "github.com/cosmos/cosmos-sdk/client/grpc/reflection" +) + +type exporter struct { + FileRegistry map[string][]byte `json:"file_registry" yaml:"file_registry"` + Services []*reflection.QueryDescriptor `json:"services" yaml:"services"` + ServiceDescriptors map[string][]byte `json:"service_descriptors" yaml:"service_descriptors"` + MsgImplementers map[string][]string `json:"mgs_implementers" yaml:"msg_implementers"` + ServiceMsgImplementers map[string][]string `json:"service_msg_implementers" yaml:"service_msg_implementers"` + TypeDescriptors map[string][]byte `json:"type_descriptors" yaml:"type_descriptors"` + InterfaceImplementers map[string][]string `json:"interface_implementers" yaml:"interface_implementers"` +} + +// Export allows to export client configuration to the given reader +func Export(c *Client, w io.Writer) error { + return nil +} + +// Import instantiates a new *Client from an import +func Import(desc io.Reader) (*Client, error) { + return nil, nil +} diff --git a/client/reflection/client/fetcher.go b/client/reflection/client/fetcher.go new file mode 100644 index 000000000000..4c08f23f7d9c --- /dev/null +++ b/client/reflection/client/fetcher.go @@ -0,0 +1,21 @@ +package client + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/client/grpc/reflection" +) + +// protoDownloader implements codec.ProtoImportsDownloader +type protoDownloader struct { + client reflection.ReflectionServiceClient +} + +func (c protoDownloader) DownloadDescriptorByPath(ctx context.Context, path string) (desc []byte, err error) { + resp, err := c.client.ResolveService(ctx, &reflection.ResolveServiceRequest{FileName: path}) + if err != nil { + return nil, err + } + + return resp.RawDescriptor, nil +} diff --git a/client/reflection/client/tx.go b/client/reflection/client/tx.go new file mode 100644 index 000000000000..3d4db7b44ffa --- /dev/null +++ b/client/reflection/client/tx.go @@ -0,0 +1,27 @@ +package client + +import ( + tmrpc "github.com/tendermint/tendermint/rpc/client" + "google.golang.org/protobuf/proto" + + "github.com/cosmos/cosmos-sdk/client/reflection/tx" + sdktypes "github.com/cosmos/cosmos-sdk/types" +) + +type TxBuilder interface { + // AddMsg adds a message to the builder + AddMsg(msg proto.Message) + // SetFees sets the fees + SetFees(fees sdktypes.Coins) + // SetMemo sets the memo + SetMemo(memo string) +} + +type Tx struct { + rpc tmrpc.Client + tx.UnsignedBuilder +} + +func NewTx() *Tx { + return &Tx{} +} diff --git a/client/reflection/client/types.go b/client/reflection/client/types.go new file mode 100644 index 000000000000..d6959f25278a --- /dev/null +++ b/client/reflection/client/types.go @@ -0,0 +1,13 @@ +package client + +import ( + "context" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +type AccountInfoProvider interface { + Address(ctx context.Context, pubKey cryptotypes.PubKey) (string, error) + SigningInfo(ctx context.Context, pubKey cryptotypes.PubKey) (accountNumber, sequence uint64, err error) + Sign(ctx context.Context, pubKey cryptotypes.PubKey, b []byte) (signedBytes []byte, err error) +} diff --git a/client/reflection/codec/codec.go b/client/reflection/codec/codec.go new file mode 100644 index 000000000000..28a3bf217aa6 --- /dev/null +++ b/client/reflection/codec/codec.go @@ -0,0 +1,275 @@ +package codec + +import ( + "bytes" + "compress/gzip" + "context" + "errors" + "fmt" + "io/ioutil" + "strings" + + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/runtime/protoimpl" + "google.golang.org/protobuf/types/dynamicpb" +) + +var ( + ErrFileRegistered = errors.New("file is already registered") + ErrNoDependencyFetcher = errors.New("no dependency fetcher was set") + ErrBuild = errors.New("unable to build the file descriptor") +) + +// Codec is a protobuf registry builder. It is capable of building +// entire protobuf registries starting from one file and resolving +// its imports dynamically. It's meant to be used in a contextualized +// way in order to avoid namespace issues caused by identical filenames +// package names and message names. +// It has support for *anypb.Any type resolving, as long as the types +// were correctly registered. +type Codec struct { + files *protoregistry.Files + types *protoregistry.Types + + jsonMarshaler protojson.MarshalOptions + jsonUnmarshaler protojson.UnmarshalOptions + + protoMarshaler proto.MarshalOptions + protoUnmarshaler proto.UnmarshalOptions + + dependencyFetcher ProtoImportsDownloader +} + +// NewCodec builds a codec which resolves dependencies for unknown protobuf types +func NewCodec(f ProtoImportsDownloader) *Codec { + filesReg := new(protoregistry.Files) + typesReg := new(protoregistry.Types) + + typeResolver := newTypeResolver(typesReg) + return &Codec{ + files: filesReg, + types: typesReg, + jsonMarshaler: protojson.MarshalOptions{ + Resolver: typeResolver, + }, + jsonUnmarshaler: protojson.UnmarshalOptions{ + Resolver: typesReg, + }, + protoMarshaler: proto.MarshalOptions{}, + protoUnmarshaler: proto.UnmarshalOptions{ + Resolver: typeResolver, + }, + dependencyFetcher: f, + } +} + +func (c *Codec) KnownMessage(name string) bool { + if _, err := c.types.FindMessageByName(protoreflect.FullName(name)); err != nil { + return false + } + + return true +} + +func (c *Codec) MarshalJSON(o proto.Message) (b []byte, err error) { + return c.jsonMarshaler.Marshal(o) +} + +func (c *Codec) UnmarshalJSON(b []byte, o proto.Message) error { + return c.jsonUnmarshaler.Unmarshal(b, o) +} + +func (c *Codec) Marshal(o proto.Message) ([]byte, error) { + return c.protoMarshaler.Marshal(o) +} + +func (c *Codec) Unmarshal(b []byte, o proto.Message) error { + return c.protoUnmarshaler.Unmarshal(b, o) +} + +// FilesRegistry returns the codec proto file registry with read only access +func (c *Codec) FilesRegistry() ReadonlyProtoFileRegistry { + return c.files +} + +// TypesRegistry returns the codec proto type registry with read only access +func (c *Codec) TypesRegistry() ReadonlyTypeRegistry { + return c.types +} + +// RegisterRawFileDescriptor is going to parse the given descriptor and also attempt to resolve its import dependencies +func (c *Codec) RegisterRawFileDescriptor(ctx context.Context, rawDesc []byte) (fileDesc protoreflect.FileDescriptor, err error) { + + rawDesc, err = tryUnzip(rawDesc) + if err != nil { + return nil, err + } + // we build a temporary descriptor whose purpose is to check for dependencies + // after the proto dependencies are resolved and registered we can build + // and register the file descriptor + tmpDesc, err := buildDescriptor(new(protoregistry.Files), new(protoregistry.Types), rawDesc) + if err != nil { + return nil, err + } + + // get dependencies + fileImports := tmpDesc.Imports() + for i := 0; i < fileImports.Len(); i++ { + // process missing imports + imp := fileImports.Get(i) + _, err := c.files.FindFileByPath(imp.Path()) + // if the file exist then skip the import + if err == nil { + continue + } + // if the error is not a not found one then fail + if !errors.Is(err, protoregistry.NotFound) { + return nil, fmt.Errorf("unrecognized error while processing imports: %s", err) + } + + // check if we have set up a dependency fetcher + if c.dependencyFetcher == nil { + return nil, fmt.Errorf("file %s requires missing dependency %s: %w", tmpDesc.Path(), imp.Path(), ErrNoDependencyFetcher) + } + // get the missing import from the fetcher + // TODO: files such as gogoproto and co are empty :\ + importDesc, err := c.dependencyFetcher.DownloadDescriptorByPath(ctx, imp.Path()) + if err != nil { + return nil, fmt.Errorf("unable to fetch missing dependency for %s: %s: %w", tmpDesc.Path(), imp.Path(), err) + } + _, err = c.RegisterRawFileDescriptor(ctx, importDesc) + if err != nil && !errors.Is(err, ErrFileRegistered) { + return nil, fmt.Errorf("unable to parse missing dependency for %s: %s: %w", tmpDesc.Path(), imp.Path(), err) + } + } + // after we have registered the dependencies + // we rebuild the descriptor with the registry + // that contains the resolved dependencies + fileDesc, err = buildDescriptor(c.files, c.types, rawDesc) + if err != nil { + return fileDesc, err + } + return fileDesc, err +} + +// tryUnzip is going to attempt to unzip the provided descriptor +func tryUnzip(rawDesc []byte) ([]byte, error) { + buf := bytes.NewBuffer(rawDesc) + r, err := gzip.NewReader(buf) + if err != nil { + return rawDesc, nil + } + + unzipped, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return unzipped, nil +} + +// buildDescriptor builds a proto file descriptor given the decoded bytes +func buildDescriptor(fileRegistry *protoregistry.Files, typesRegistry *protoregistry.Types, rawDesc []byte) (fileDesc protoreflect.FileDescriptor, err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("%w: %#v", ErrBuild, r) + } + }() + + tmpBuilder := (&protoimpl.DescBuilder{ + GoPackagePath: "", + RawDescriptor: rawDesc, + TypeResolver: new(protoregistry.Types), + FileRegistry: new(protoregistry.Files), + }).Build() + + filePath := tmpBuilder.File.Path() + + // check if it exists + existingFd, err := fileRegistry.FindFileByPath(filePath) + if err != nil && errors.Is(err, protoregistry.NotFound) { + // does not exist, build file desc + fd := (&protoimpl.DescBuilder{ + RawDescriptor: rawDesc, + TypeResolver: typesRegistry, + FileRegistry: fileRegistry, + }).Build().File + // add fd types to registry + err = regTypes(typesRegistry, fd) + if err != nil { + return nil, err + } + return fd, err + } + // check if err + if err != nil { + return nil, err + } + // already registered + return existingFd, fmt.Errorf("%s: %w", existingFd.Path(), ErrFileRegistered) +} + +func regTypes(reg *protoregistry.Types, fd protoreflect.FileDescriptor) error { + msgs := fd.Messages() + for i := 0; i < msgs.Len(); i++ { + md := msgs.Get(i) + typ := dynamicpb.NewMessageType(md) + err := reg.RegisterMessage(typ) + if err != nil { + return err + } + } + + enums := fd.Enums() + for i := 0; i < enums.Len(); i++ { + ed := enums.Get(i) + typ := dynamicpb.NewEnumType(ed) + err := reg.RegisterEnum(typ) + if err != nil { + return err + } + } + + extensions := fd.Extensions() + for i := 0; i < extensions.Len(); i++ { + xd := extensions.Get(i) + typ := dynamicpb.NewExtensionType(xd) + err := reg.RegisterExtension(typ) + if err != nil { + return err + } + } + + return nil +} + +type typeResolver struct { + reg *protoregistry.Types +} + +func (t typeResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) { + return t.reg.FindExtensionByName(field) +} + +func (t typeResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) { + return t.reg.FindExtensionByNumber(message, field) +} + +func (t typeResolver) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) { + return t.reg.FindMessageByName(message) +} + +func (t typeResolver) FindMessageByURL(url string) (protoreflect.MessageType, error) { + u := url + if strings.HasPrefix(u, "/") { + u = u[1:] + } + return t.reg.FindMessageByURL(u) +} + +func newTypeResolver(reg *protoregistry.Types) *typeResolver { + return &typeResolver{reg: reg} +} diff --git a/client/reflection/codec/types.go b/client/reflection/codec/types.go new file mode 100644 index 000000000000..c9f8bc138c99 --- /dev/null +++ b/client/reflection/codec/types.go @@ -0,0 +1,31 @@ +package codec + +import ( + "context" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" +) + +// ReadonlyTypeRegistry defines an immutable protobuf type registry +type ReadonlyTypeRegistry interface { + protoregistry.ExtensionTypeResolver + protoregistry.MessageTypeResolver +} + +// ReadonlyProtoFileRegistry defines an immutable protobuf file registry +type ReadonlyProtoFileRegistry interface { + // FindFileByPath returns a protoreflect.FileDescriptor given the file + // path, ex: proto/cosmos/base/v1beta1/coin.proto + FindFileByPath(path string) (protoreflect.FileDescriptor, error) + // FindDescriptorByName returns protoreflect.FileDescriptor given + // its protoreflect.FullName + FindDescriptorByName(name protoreflect.FullName) (protoreflect.Descriptor, error) +} + +// ProtoImportsDownloader defines the behaviour of an object that can +// download the raw descriptors of protobuf files. It is used to resolve +// protobuf dependencies in a dynamic way. +type ProtoImportsDownloader interface { + // DownloadDescriptorByPath returns the protobuf descriptor raw bytes given the file path + DownloadDescriptorByPath(ctx context.Context, path string) (rawDescriptor []byte, err error) +} diff --git a/client/reflection/codec/util.go b/client/reflection/codec/util.go new file mode 100644 index 000000000000..75fa38a5a772 --- /dev/null +++ b/client/reflection/codec/util.go @@ -0,0 +1,13 @@ +package codec + +import "google.golang.org/protobuf/proto" + +// MessageName is a utility function to return the message name +// similar to the deprecated proto.MessageName function. +// If proto.Message is nil then an empty string is returned. +func MessageName(pb proto.Message) string { + if pb == nil { + return "" + } + return (string)(pb.ProtoReflect().Descriptor().FullName()) +} diff --git a/client/reflection/descriptor/builder.go b/client/reflection/descriptor/builder.go new file mode 100644 index 000000000000..d8101619cc53 --- /dev/null +++ b/client/reflection/descriptor/builder.go @@ -0,0 +1,221 @@ +package descriptor + +import ( + "errors" + "fmt" + + "google.golang.org/protobuf/proto" + + "google.golang.org/protobuf/reflect/protoreflect" +) + +var ( + ErrAlreadyExists = errors.New("descriptor: already exists") +) + +func NewBuilder() *Builder { + return &Builder{ + queriers: newQueriers(), + deliverables: newDeliverables(), + } +} + +// Builder builds a Chain descriptor +type Builder struct { + queriers queriers + deliverables deliverables +} + +func (b *Builder) Build() (Chain, error) { + return newChain(b.queriers, b.deliverables), nil +} + +func (b *Builder) RegisterDeliverable(desc protoreflect.MessageDescriptor) error { + err := b.deliverables.insert(desc) + if err != nil { + return nil + } + return nil +} + +func (b *Builder) RegisterQueryService(desc protoreflect.ServiceDescriptor) error { + md := desc.Methods() + for i := 0; i < md.Len(); i++ { + method := md.Get(i) + err := b.queriers.insert(desc, method) + if err != nil { + return err + } + } + + return nil +} + +func newQueriers() queriers { + return queriers{ + byName: make(map[string]querier), + byTMName: make(map[string]querier), + byInputName: make(map[string]querier), + byIndex: nil, + } +} + +type queriers struct { + byName map[string]querier + byTMName map[string]querier + byInputName map[string]querier + byIndex []querier +} + +func (q *queriers) insert(sd protoreflect.ServiceDescriptor, md protoreflect.MethodDescriptor) error { + name := (string)(md.FullName()) + if _, exists := q.byName[name]; exists { + return fmt.Errorf("%s: %w", name, ErrAlreadyExists) + } + qr := newQuerier(sd, md) + if _, exists := q.byTMName[qr.tmQueryPath]; exists { + return fmt.Errorf("%s: %w", name, ErrAlreadyExists) + } + q.byName[name] = qr + q.byTMName[qr.tmQueryPath] = qr + reqName := (string)(qr.desc.Input().FullName()) + if _, exists := q.byInputName[reqName]; exists { + return fmt.Errorf("message name to query descriptor override %s: %w", reqName, ErrAlreadyExists) + } + q.byInputName[reqName] = qr + q.byIndex = append(q.byIndex, qr) + + return nil +} + +func (q queriers) Len() int { + return len(q.byName) +} + +func (q queriers) Get(i int) Querier { + if i >= len(q.byIndex) { + return nil + } + return q.byIndex[i] +} + +func (q queriers) ByName(name string) Querier { + if o, exists := q.byName[name]; exists { + return o + } + return nil +} + +func (q queriers) ByTMName(tmName string) Querier { + if o, exists := q.byTMName[tmName]; exists { + return o + } + return nil +} + +func (q queriers) ByInput(input proto.Message) Querier { + if o, exists := q.byInputName[(string)(input.ProtoReflect().Descriptor().FullName())]; exists { + return o + } + return nil +} + +func newQuerier(sd protoreflect.ServiceDescriptor, md protoreflect.MethodDescriptor) querier { + return querier{ + desc: md, + tmQueryPath: fmt.Sprintf("/%s/%s", sd.FullName(), md.Name()), // TODO: why in the sdk we broke standard grpc query method invocation naming? + } +} + +type querier struct { + desc protoreflect.MethodDescriptor + tmQueryPath string +} + +func (q querier) Descriptor() protoreflect.MethodDescriptor { + return q.desc +} + +func (q querier) TMQueryPath() string { + return q.tmQueryPath +} + +func newDeliverables() deliverables { + return deliverables{ + byName: make(map[string]deliverable), + byIndex: nil, + } +} + +type deliverables struct { + byName map[string]deliverable + byIndex []deliverable +} + +func (d *deliverables) insert(md protoreflect.MessageDescriptor) error { + name := (string)(md.FullName()) + if _, exists := d.byName[name]; exists { + return fmt.Errorf("%w: %s", ErrAlreadyExists, name) + } + + deliverable := newDeliverable(md) + d.byName[name] = deliverable + d.byIndex = append(d.byIndex, deliverable) + + return nil +} + +func (d deliverables) Len() int { + return len(d.byName) +} + +func (d deliverables) Get(i int) Deliverable { + if i >= len(d.byIndex) { + return nil + } + return d.byIndex[i] +} + +func (d deliverables) ByName(name string) Deliverable { + desc, exists := d.byName[name] + if !exists { + return nil + } + return desc +} + +func newDeliverable(desc protoreflect.MessageDescriptor) deliverable { + return deliverable{desc: desc} +} + +type deliverable struct { + desc protoreflect.MessageDescriptor +} + +func (d deliverable) Descriptor() protoreflect.MessageDescriptor { + return d.desc +} + +func newChain(q queriers, d deliverables) chain { + return chain{ + q: q, + d: d, + } +} + +type chain struct { + q queriers + d deliverables +} + +func (c chain) Config() Config { + panic("implement me") +} + +func (c chain) Deliverables() Deliverables { + return c.d +} + +func (c chain) Queriers() Queriers { + return c.q +} diff --git a/client/reflection/descriptor/descriptor.go b/client/reflection/descriptor/descriptor.go new file mode 100644 index 000000000000..9a3383747948 --- /dev/null +++ b/client/reflection/descriptor/descriptor.go @@ -0,0 +1,80 @@ +package descriptor + +import ( + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" +) + +// Chain exposes the descriptor for the chain +type Chain interface { + // Config returns the sdk.Config specific + Config() Config + // Deliverables returns the list of deliverable messages + Deliverables() Deliverables + // Queriers returns the list of available queriers + Queriers() Queriers +} + +// Deliverables allows to interact with a list of deliverables +type Deliverables interface { + // Len returns the number of deliverables + Len() int + // Get returns the deliverable by index + Get(i int) Deliverable + // ByName returns the deliverable given its name + // if not found nil will be returned + ByName(string) Deliverable +} + +// Deliverable defines the descriptor for the given message +type Deliverable interface { + // Descriptor returns the protoreflect.MessageDescriptor + Descriptor() protoreflect.MessageDescriptor + // ExpectedSigners // TODO +} + +// Queriers exposes the queriers descriptor interface +type Queriers interface { + // Len returns the number of queriers + Len() int + // Get returns the querier by index + Get(i int) Querier + // ByInput returns the querier given its input proto.Message + ByInput(input proto.Message) Querier + // ByName gets the Querier descriptor + // given its service method name + ByName(name string) Querier + // ByTMName gets the Querier descriptor + // given the tendermint query path + ByTMName(path string) Querier +} + +// Querier exposes the query descriptor interface +type Querier interface { + // TMQueryPath returns the path that needs to be used in tendermint to execute the query + TMQueryPath() string + // Descriptor returns the protoreflect.MethodDescriptor + Descriptor() protoreflect.MethodDescriptor +} + +// Config provides reflection capabilities for sdk.Config type +type Config interface { + // Bech32Prefix returns the chain bech32 prefix + Bech32Prefix() string + // Bech32AccAddressPrefix returns the account address prefix + Bech32AccAddressPrefix() string + // Bech32AccPubPrefix returns the bech32 prefix of an account's public key + Bech32AccPubPrefix() string + // Bech32ValAddrPrefix returns the bech32 prefix of a validator's operator address + Bech32ValAddrPrefix() string + // Bech32ValPubPrefix returns the bech32 prefix of validator's operator public key + Bech32ValPubPrefix() string + // Bech32ConsAddrPrefix returns the bech32 prefix of a consensus node address + Bech32ConsAddrPrefix() string + // Bech32ConsPubPrefix returns the bech32 prefix of a consensus node public key + Bech32ConsPubPrefix() string + // Purpose returns the purpose as defined in SLIP44 + Purpose() uint + // CoinType returns the coin type as defined in SLIP44 + CoinType() uint +} diff --git a/client/reflection/descriptor/doc.go b/client/reflection/descriptor/doc.go new file mode 100644 index 000000000000..82a9b165161c --- /dev/null +++ b/client/reflection/descriptor/doc.go @@ -0,0 +1,3 @@ +// Package descriptor provides cosmos-sdk specific chain descriptors +// NOTE: the API is unstable +package descriptor diff --git a/client/reflection/examples/cli/cli.go b/client/reflection/examples/cli/cli.go new file mode 100644 index 000000000000..82e6d774b7b9 --- /dev/null +++ b/client/reflection/examples/cli/cli.go @@ -0,0 +1,134 @@ +package cli + +import ( + "context" + "fmt" + "os" + "sort" + + "github.com/manifoldco/promptui" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/dynamicpb" + + "github.com/cosmos/cosmos-sdk/client/reflection/client" +) + +const ( + actionTx = "tx" + actionQuery = "query" +) + +func NewCLI(c *client.Client) *CLI { + return &CLI{c: c} +} + +type CLI struct { + c *client.Client +} + +func (p *CLI) Run() error { + prompt := promptui.Select{ + Label: "Select action", + Items: []string{actionTx, actionQuery}, + } + + _, res, err := prompt.Run() + if err != nil { + return err + } + + switch res { + case actionTx: + return fmt.Errorf("not supported") + case actionQuery: + return p.query() + default: + return fmt.Errorf("unknown action: %s", res) + } +} + +func (p *CLI) query() error { + qd := p.c.ChainDescriptor().Queriers() + + selections := make([]string, 0, qd.Len()) + + for i := 0; i < qd.Len(); i++ { + q := qd.Get(i) + selections = append(selections, q.TMQueryPath()) + } + + sort.Slice(selections, func(i, j int) bool { + return selections[i] < selections[j] + }) + + prompt := promptui.Select{ + Label: "method to query", + Items: selections, + } + + _, res, err := prompt.Run() + if err != nil { + return err + } + + queryDesc := qd.ByTMName(res) + if queryDesc == nil { + return fmt.Errorf("not found: %s", res) + } + + dpb, err := fillDynamicMessagePrompt(queryDesc.Descriptor().Input()) + if err != nil { + return err + } + + resp, err := p.c.Query(context.TODO(), dpb) + if err != nil { + return err + } + + b, err := p.c.Codec().MarshalJSON(resp) + if err != nil { + return err + } + + _, err = fmt.Fprintln(os.Stderr, fmt.Sprintf("%s", b)) + if err != nil { + return err + } + + return nil +} + +func fillDynamicMessagePrompt(md protoreflect.MessageDescriptor) (*dynamicpb.Message, error) { + dyn := dynamicpb.NewMessage(md) + fields := md.Fields() + for i := 0; i < fields.Len(); i++ { + field := fields.Get(i) + v, err := valueFromFieldDescriptor(dyn, field) + if err != nil { + return nil, err + } + + dyn.Set(field, v) + } + return dyn, nil +} + +func valueFromFieldDescriptor(dyn *dynamicpb.Message, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) { + label := fmt.Sprintf("fill field %s", fd.Name()) + switch fd.Kind() { + case protoreflect.StringKind: + prompt := promptui.Prompt{ + Label: label, + Default: fd.Default().String(), + } + + res, err := prompt.Run() + if err != nil { + return protoreflect.Value{}, err + } + return protoreflect.ValueOfString(res), nil + default: + return protoreflect.Value{}, fmt.Errorf("unsupported kind: %s", fd.Kind()) + } +} diff --git a/client/reflection/examples/cli/main/main.go b/client/reflection/examples/cli/main/main.go new file mode 100644 index 000000000000..98163e67f718 --- /dev/null +++ b/client/reflection/examples/cli/main/main.go @@ -0,0 +1,22 @@ +package main + +import ( + "context" + "log" + + "github.com/cosmos/cosmos-sdk/client/reflection/client" + "github.com/cosmos/cosmos-sdk/client/reflection/examples/cli" +) + +func main() { + c, err := client.Dial(context.TODO(), "localhost:9090", "tcp://localhost:26657", nil) + if err != nil { + panic(err) + } + + prompt := cli.NewCLI(c) + err = prompt.Run() + if err != nil { + log.Fatal(err) + } +} diff --git a/client/reflection/tx/builder_signed.go b/client/reflection/tx/builder_signed.go new file mode 100644 index 000000000000..2be09a0a65fd --- /dev/null +++ b/client/reflection/tx/builder_signed.go @@ -0,0 +1,60 @@ +package tx + +import ( + "fmt" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/types/tx" +) + +type SignedBuilder struct { + tx *tx.Tx + signatureBytesProvider SignatureBytesProvider + expectedSigners map[string]SignerInfo + signatures map[string]struct{} + chainID string +} + +func NewSignedBuilder(rawTx *tx.Tx, chainID string, expectedSigners map[string]SignerInfo) (*SignedBuilder, error) { + // do raw tx verification for correctness + return &SignedBuilder{ + tx: rawTx, + signatureBytesProvider: defaultSigBytesProvider{}, + expectedSigners: expectedSigners, + signatures: make(map[string]struct{}), + chainID: chainID, + }, nil +} + +func (s *SignedBuilder) SetSignature(signer cryptotypes.PubKey, signature []byte) error { + if _, exists := s.expectedSigners[signer.String()]; !exists { + return fmt.Errorf("unexpected signer provided") + } + + if _, exists := s.signatures[signer.String()]; exists { + return fmt.Errorf("signer already set") + } + + s.tx.Signatures = append(s.tx.Signatures, signature) + s.signatures[signer.String()] = struct{}{} + + return nil +} + +func (s *SignedBuilder) BytesToSign(signer cryptotypes.PubKey) ([]byte, error) { + sigInfo, exists := s.expectedSigners[signer.String()] + if !exists { + return nil, fmt.Errorf("unexpected signer provided") + } + + bytesToSign, err := s.signatureBytesProvider.GetSignBytes(sigInfo.SignMode, s.tx, sigInfo.AccountNumber, sigInfo.Sequence, s.chainID) + if err != nil { + return nil, err + } + + return bytesToSign, nil +} + +func (s *SignedBuilder) Bytes() ([]byte, error) { + return s.tx.Marshal() +} diff --git a/client/reflection/tx/builder_test.go b/client/reflection/tx/builder_test.go new file mode 100644 index 000000000000..e6eb66c50e8a --- /dev/null +++ b/client/reflection/tx/builder_test.go @@ -0,0 +1,65 @@ +package tx + +/* +func TestBuilders(t *testing.T) { + const keyHex = "8c7e006440ac5e358739bdc3d10a8b2d229e23d27660f6d3a8306cee4379594c" + pkBytes, err := hex.DecodeString(keyHex) + if err != nil { + t.Fatal(err) + } + pk := secp256k1.PrivKey{Key: pkBytes} + tmRPC, err := tmrpc.New("tcp://localhost:26657", "") + if err != nil { + t.Fatal(err) + } + + builder := NewUnsignedTxBuilder() + builder.SetMemo("") + builder.SetChainID("testing") + builder.AddMsg(&bank.MsgSend{ + FromAddress: "cosmos1ujtnemf6jmfm995j000qdry064n5lq854gfe3j", + ToAddress: "cosmos1caa3es6q3mv8t4gksn9wjcwyzw7cnf5gn5cx7j", + Amount: sdk.NewCoins(sdk.NewInt64Coin("stake", 10)), + }) + builder.SetFeePayer("cosmos1ujtnemf6jmfm995j000qdry064n5lq854gfe3j") + builder.SetFees(sdk.NewCoins(sdk.NewInt64Coin("stake", 10))) + builder.SetGasLimit(2500000) + builder.AddSigner(SignerInfo{ + PubKey: pk.PubKey(), + SignMode: signing.SignMode_SIGN_MODE_DIRECT, + AccountNumber: 0, + Sequence: 2, + }) + + signedbldr, err := builder.SignedBuilder() + if err != nil { + t.Fatal(err) + } + + expectedSig, err := signedbldr.BytesToSign(pk.PubKey()) + if err != nil { + t.Fatal(err) + } + signedSig, err := pk.Sign(expectedSig) + if err != nil { + t.Fatal(err) + } + err = signedbldr.SetSignature(pk.PubKey(), signedSig) + if err != nil { + t.Fatal(err) + } + + txB, err := signedbldr.Bytes() + if err != nil { + t.Fatal(err) + } + + resp, err := tmRPC.BroadcastTxCommit(context.TODO(),txB ) + if err != nil { + t.Fatal(err) + } + + t.Logf("%#v", resp) +} + +*/ diff --git a/client/reflection/tx/builder_unsigned.go b/client/reflection/tx/builder_unsigned.go new file mode 100644 index 000000000000..17e3bca9a222 --- /dev/null +++ b/client/reflection/tx/builder_unsigned.go @@ -0,0 +1,141 @@ +package tx + +import ( + "fmt" + + "google.golang.org/protobuf/proto" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx" +) + +// UnsignedBuilder implements a raw unsigned transaction builder +// it of course cannot offer the full set of functionalities +// of the standard sdk tx builder as it cannot deduct if a +// given message is valid and who are the expected signers. +type UnsignedBuilder struct { + msgs []proto.Message + gasLimit uint64 + fees sdktypes.Coins + chainID string + memo string + accountsInfo map[string]SignerInfo + feePayer string + timeoutHeight uint64 +} + +func NewUnsignedTxBuilder() *UnsignedBuilder { + return &UnsignedBuilder{ + msgs: nil, + gasLimit: 0, + fees: nil, + chainID: "", + accountsInfo: make(map[string]SignerInfo), + } +} + +func (t *UnsignedBuilder) SetMemo(memo string) { + t.memo = memo +} + +func (t *UnsignedBuilder) SetFees(fees sdktypes.Coins) { + t.fees = fees +} + +func (t *UnsignedBuilder) SetGasLimit(limit uint64) { + t.gasLimit = limit +} + +func (t *UnsignedBuilder) AddMsg(msg proto.Message) { + t.msgs = append(t.msgs, msg) +} + +// AddSigner is going to add a signer +func (t *UnsignedBuilder) AddSigner(signer SignerInfo) { + if signer.PubKey == nil { + panic("nil signer pub key") + } + t.accountsInfo[signer.PubKey.String()] = signer +} + +func (t *UnsignedBuilder) SignedBuilder() (*SignedBuilder, error) { + // add prereq checks + // get fee payer + if t.feePayer == "" { + return nil, fmt.Errorf("fee payer not specified") + } + // pack msgs as any + anyMsgs := make([]*codectypes.Any, len(t.msgs)) + + for i, msg := range t.msgs { + msgBytes, err := proto.Marshal(msg) + if err != nil { + return nil, err + } + typeURL := fmt.Sprintf("/%s", msg.ProtoReflect().Descriptor().FullName()) + anyMsg := &codectypes.Any{ + TypeUrl: typeURL, + Value: msgBytes, + } + anyMsgs[i] = anyMsg + } + + signersInfo := make([]*tx.SignerInfo, 0, len(t.accountsInfo)) + + for _, signer := range t.accountsInfo { + signerInfo, err := getSignerInfo(signer) + if err != nil { + return nil, err + } + signersInfo = append(signersInfo, signerInfo) + } + + rawTx := &tx.Tx{ + Body: &tx.TxBody{ + Messages: anyMsgs, + Memo: t.memo, + TimeoutHeight: 0, + ExtensionOptions: nil, + NonCriticalExtensionOptions: nil, + }, + AuthInfo: &tx.AuthInfo{ + SignerInfos: signersInfo, + Fee: &tx.Fee{ + Amount: t.fees, + GasLimit: t.gasLimit, + Payer: t.feePayer, + Granter: "", + }, + }, + Signatures: nil, + } + + return NewSignedBuilder(rawTx, t.chainID, t.accountsInfo) +} + +func (t *UnsignedBuilder) SetFeePayer(payer string) { + t.feePayer = payer +} + +func (t *UnsignedBuilder) SetChainID(chainID string) { + t.chainID = chainID +} + +func getSignerInfo(signer SignerInfo) (*tx.SignerInfo, error) { + anyPubKey, err := codectypes.NewAnyWithValue(signer.PubKey) + if err != nil { + return nil, err + } + sig := &tx.SignerInfo{ + PublicKey: anyPubKey, + ModeInfo: &tx.ModeInfo{ + Sum: &tx.ModeInfo_Single_{ + Single: &tx.ModeInfo_Single{Mode: signer.SignMode}, + }, + }, + Sequence: signer.Sequence, + } + + return sig, nil +} diff --git a/client/reflection/tx/types.go b/client/reflection/tx/types.go new file mode 100644 index 000000000000..9b549ba193aa --- /dev/null +++ b/client/reflection/tx/types.go @@ -0,0 +1,50 @@ +package tx + +import ( + "fmt" + + "github.com/golang/protobuf/proto" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/types/tx" + "github.com/cosmos/cosmos-sdk/types/tx/signing" +) + +type SignatureBytesProvider interface { + GetSignBytes(mode signing.SignMode, rawTx *tx.Tx, accountNumber, sequence uint64, chainID string) ([]byte, error) +} + +type SignerInfo struct { + PubKey cryptotypes.PubKey + SignMode signing.SignMode + AccountNumber uint64 + Sequence uint64 +} + +// defaultSigBytesProvider aliases the direct mode signing spec, it is repeated here in order not to create +// import dependencies on the auth module. The reflection library should not depend on any module but it +// should be able to interact with any of them. +type defaultSigBytesProvider struct{} + +// GetSignBytes returns the expected bytes that need to be signed in order for a transaction to be valid +func (s defaultSigBytesProvider) GetSignBytes(mode signing.SignMode, rawTx *tx.Tx, accountNumber, _ uint64, chainID string) ([]byte, error) { + if mode != signing.SignMode_SIGN_MODE_DIRECT { + return nil, fmt.Errorf("unsupported mode") + } + + authInfoBytes, err := proto.Marshal(rawTx.AuthInfo) + if err != nil { + return nil, err + } + + bodyBytes, err := proto.Marshal(rawTx.Body) + + signDoc := tx.SignDoc{ + BodyBytes: bodyBytes, + AuthInfoBytes: authInfoBytes, + ChainId: chainID, + AccountNumber: accountNumber, + } + + return signDoc.Marshal() +} diff --git a/client/reflection/unstructured/object.go b/client/reflection/unstructured/object.go new file mode 100644 index 000000000000..6575fcd7da21 --- /dev/null +++ b/client/reflection/unstructured/object.go @@ -0,0 +1,212 @@ +package unstructured + +import ( + "fmt" + "reflect" + + "github.com/spf13/cast" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/dynamicpb" +) + +// Object represents the behaviour of a raw object that can marshal itself +// to a proto dynamic message given its file descriptor +type Object interface { + Marshal(desc protoreflect.MessageDescriptor) (*dynamicpb.Message, error) +} + +// Map defines an unstructured map object that can be used to fill protobuf objects recursively +// types should be either pointers or golang primitive types, as of now, using type aliases +// is not supported. +type Map map[string]interface{} + +func (o Map) Marshal(md protoreflect.MessageDescriptor) (*dynamicpb.Message, error) { + dyn := dynamicpb.NewMessage(md) + for fieldName, interfaceValue := range o { + fd := md.Fields().ByName(protoreflect.Name(fieldName)) + if fd == nil { + return nil, fmt.Errorf("descriptor %s does not contain field named %s", md.FullName(), fieldName) + } + pv, err := interfaceToProtoValue(dyn, interfaceValue, fd, md, false) + if err != nil { + return nil, err + } + // set the field + dyn.Set(fd, pv) + } + + return dyn, nil +} + +// TODO: indirect +func fillMap(dyn *dynamicpb.Message, v interface{}, pMap protoreflect.Map, fd protoreflect.FieldDescriptor, md protoreflect.MessageDescriptor) error { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Map { + return errTypeMismatch(md, fd, v) + } + + keyDesc := fd.MapKey() + valueDesc := fd.MapValue() + + mapIter := rv.MapRange() + + for mapIter.Next() { + k := mapIter.Key().Interface() + v := mapIter.Value().Interface() + + // cast k and v to kDesc and vDesc + kValue, err := interfaceToProtoValue(dyn, k, keyDesc, md, false) + if err != nil { + return fmt.Errorf("unable to set map key for map field descriptor %s: %w", fd, err) + } + vValue, err := interfaceToProtoValue(dyn, v, valueDesc, md, false) + if err != nil { + return fmt.Errorf("unable to set map value for map field descriptor %s: %w", fd, err) + } + // set in map + pMap.Set(kValue.MapKey(), vValue) + } + + return nil +} + +// TODO: indirect +func fillList(dyn *dynamicpb.Message, v interface{}, list protoreflect.List, fd protoreflect.FieldDescriptor, md protoreflect.MessageDescriptor) error { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Slice { + return errTypeMismatch(md, fd, v) + } + for i := 0; i < rv.Len(); i++ { + iv := rv.Index(i).Interface() + v, err := interfaceToProtoValue(dyn, iv, fd, md, true) + if err != nil { + return err + } + list.Append(v) + } + return nil +} + +// interfaceToProtoValue converts the given interface value to the protoreflect.Value expected +// isListElement tells if the interfaceValue we are processing is part of a list or not +// as its protoreflect.FieldDescriptor would return that this is a list instead of returning +// the descriptor for the list element. This can be done in this way as protobuf does not allow +// rectangular (or more) arrays. So if we're dealing with a list it's gonna be of a singular dimension. +func interfaceToProtoValue(dyn *dynamicpb.Message, interfaceValue interface{}, fd protoreflect.FieldDescriptor, md protoreflect.MessageDescriptor, isListElement bool) (protoreflect.Value, error) { + // handle list or map + if fd.IsList() && !isListElement { + value := dyn.NewField(fd) + listValue := value.List() + err := fillList(dyn, interfaceValue, listValue, fd, md) + if err != nil { + return protoreflect.Value{}, err + } + return value, nil + } else if fd.IsMap() { + value := dyn.NewField(fd) + mapValue := value.Map() + err := fillMap(dyn, interfaceValue, mapValue, fd, md) + if err != nil { + return protoreflect.Value{}, err + } + return value, nil + } else { // handle normal + switch fd.Kind() { + // bool + case protoreflect.BoolKind: + v, err := cast.ToBoolE(interfaceValue) + if err != nil { + return protoreflect.Value{}, errTypeMismatch(md, fd, interfaceValue) + } + return protoreflect.ValueOfBool(v), nil + // enum + case protoreflect.EnumKind: + v, err := cast.ToInt32E(interfaceValue) + if err != nil { + return protoreflect.Value{}, errTypeMismatch(md, fd, interfaceValue) + } + return protoreflect.ValueOfEnum((protoreflect.EnumNumber)(v)), nil + // int32 + case protoreflect.Int32Kind: + v, err := cast.ToInt32E(interfaceValue) + if err != nil { + return protoreflect.Value{}, errTypeMismatch(md, fd, interfaceValue) + } + return protoreflect.ValueOfInt32(v), nil + // uint32 + case protoreflect.Uint32Kind: + v, err := cast.ToUint32E(interfaceValue) + if err != nil { + return protoreflect.Value{}, errTypeMismatch(md, fd, interfaceValue) + } + return protoreflect.ValueOfUint32(v), nil + // int64 + case protoreflect.Int64Kind: + v, err := cast.ToInt64E(interfaceValue) + if err != nil { + return protoreflect.Value{}, errTypeMismatch(md, fd, interfaceValue) + } + return protoreflect.ValueOfInt64(v), nil + // uint64 + case protoreflect.Uint64Kind: + v, err := cast.ToUint64E(interfaceValue) + if err != nil { + return protoreflect.Value{}, errTypeMismatch(md, fd, interfaceValue) + } + return protoreflect.ValueOfUint64(v), nil + // float + case protoreflect.FloatKind: + v, err := cast.ToFloat32E(interfaceValue) + if err != nil { + return protoreflect.Value{}, errTypeMismatch(md, fd, interfaceValue) + } + return protoreflect.ValueOfFloat32(v), nil + // handle double + case protoreflect.DoubleKind: + v, err := cast.ToFloat64E(interfaceValue) + if err != nil { + return protoreflect.Value{}, errTypeMismatch(md, fd, interfaceValue) + } + return protoreflect.ValueOfFloat64(v), nil + // string + case protoreflect.StringKind: + v, err := cast.ToStringE(interfaceValue) + if err != nil { + return protoreflect.Value{}, errTypeMismatch(md, fd, interfaceValue) + } + return protoreflect.ValueOfString(v), nil + // bytes + case protoreflect.BytesKind: + v, err := castToBytes(interfaceValue) + if err != nil { + return protoreflect.Value{}, errTypeMismatch(md, fd, interfaceValue) + } + return protoreflect.ValueOfBytes(v), nil + // handle message kind + case protoreflect.MessageKind: + ob, ok := interfaceValue.(Object) + if !ok { + return protoreflect.Value{}, fmt.Errorf("descriptor %s expected %s kind at %s which should be castable to unstructured.Object, got: %T", md, protoreflect.MessageKind, fd, interfaceValue) + } + dpb, err := ob.Marshal(fd.Message()) + if err != nil { + return protoreflect.Value{}, fmt.Errorf("descriptor %s failed to marshal Message for field descriptor %s: %w", md, fd, err) + } + return protoreflect.ValueOfMessage(dpb), nil + default: + return protoreflect.Value{}, fmt.Errorf("descriptor %s field %s unsupported type: %s", md.FullName(), fd.FullName(), fd.Kind().String()) + } + } +} + +func castToBytes(value interface{}) ([]byte, error) { + switch casted := value.(type) { + case []byte: + return casted, nil + } + return nil, fmt.Errorf("unable to cast %#v of type %T to string", value, value) +} + +func errTypeMismatch(desc protoreflect.MessageDescriptor, field protoreflect.FieldDescriptor, v interface{}) error { + return fmt.Errorf("descriptor %s field %s expects %s, got: %T", desc.FullName(), field.FullName(), field.Kind(), v) +} diff --git a/client/reflection/unstructured/object_bench_test.go b/client/reflection/unstructured/object_bench_test.go new file mode 100644 index 000000000000..784ddc1d20c9 --- /dev/null +++ b/client/reflection/unstructured/object_bench_test.go @@ -0,0 +1,36 @@ +package unstructured + +import ( + "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/runtime/protoimpl" + "google.golang.org/protobuf/types/dynamicpb" + "testing" +) + +var pb *dynamicpb.Message + +func BenchmarkMap_Marshal_Map(b *testing.B) { + fdBuilder := protoimpl.DescBuilder{ + RawDescriptor: fileDescriptor, + TypeResolver: new(protoregistry.Types), + FileRegistry: new(protoregistry.Files), + } + + md := fdBuilder.Build().File.Messages().ByName("WithMap") + + msg := Map{ + "a_map": map[int64]string{ + 1: "hi", + }, + } + var err error + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err = msg.Marshal(md) + if err != nil { + b.Fatal(err) + } + } + +} diff --git a/client/reflection/unstructured/object_test.go b/client/reflection/unstructured/object_test.go new file mode 100644 index 000000000000..d7c3829869e3 --- /dev/null +++ b/client/reflection/unstructured/object_test.go @@ -0,0 +1,100 @@ +package unstructured + +import ( + "testing" + + "github.com/stretchr/testify/suite" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/runtime/protoimpl" +) + +// this is a protobuf file descriptor which contains the required types to run unstructured tests +/* unstructured_test.proto +syntax="proto3"; + +package unstructured.test; + +message Flat { + string hi = 1; +} + +message Nested { + string test = 1; + Flat nested = 2; +} + +message WithMap { + string test = 1; + map a_map = 2; +} + +message WithList { + string test = 1; + repeated string rep = 2; +} +*/ +var fileDescriptor = []byte{ + 0x0a, 0x24, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x63, 0x6f, 0x72, + 0x65, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x75, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, + 0x75, 0x72, 0x65, 0x64, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x22, 0x16, 0x0a, 0x04, 0x46, 0x6c, 0x61, + 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x68, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x68, + 0x69, 0x22, 0x4d, 0x0a, 0x06, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, + 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x73, 0x74, 0x12, + 0x2f, 0x0a, 0x06, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x75, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x64, 0x2e, 0x74, + 0x65, 0x73, 0x74, 0x2e, 0x46, 0x6c, 0x61, 0x74, 0x52, 0x06, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, + 0x22, 0x91, 0x01, 0x0a, 0x07, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x12, 0x12, 0x0a, 0x04, + 0x74, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x73, 0x74, + 0x12, 0x39, 0x0a, 0x05, 0x61, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x75, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x64, 0x2e, 0x74, + 0x65, 0x73, 0x74, 0x2e, 0x57, 0x69, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x2e, 0x41, 0x4d, 0x61, 0x70, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x61, 0x4d, 0x61, 0x70, 0x1a, 0x37, 0x0a, 0x09, 0x41, + 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x30, 0x0a, 0x08, 0x57, 0x69, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x74, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x70, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x03, 0x72, 0x65, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +type MapSuite struct { + suite.Suite + fd protoreflect.FileDescriptor + + mapMD protoreflect.MessageDescriptor +} + +func (m *MapSuite) SetupTest() { + m.Require().NotPanics(func() { + b := protoimpl.DescBuilder{ + RawDescriptor: fileDescriptor, + TypeResolver: new(protoregistry.Types), + FileRegistry: new(protoregistry.Files), + } + + m.fd = b.Build().File + }) + + m.mapMD = m.fd.Messages().ByName("WithMap") + m.Require().NotNil(m.mapMD) +} + +func (m *MapSuite) TestMessageWithMap() { + msg := Map{ + "a_map": map[int64]string{ + 1: "hi", + }, + } + + pb, err := msg.Marshal(m.mapMD) + m.Require().NoError(err) + + m.T().Logf("%s", pb) +} + +func TestMap(t *testing.T) { + suite.Run(t, new(MapSuite)) +} diff --git a/contrib/rosetta/configuration/bootstrap.json b/contrib/rosetta/configuration/bootstrap.json index 1793988f37e5..f75c7ec145bb 100644 --- a/contrib/rosetta/configuration/bootstrap.json +++ b/contrib/rosetta/configuration/bootstrap.json @@ -1,7 +1,7 @@ [ { "account_identifier": { - "address":"cosmos158nkd0l9tyemv2crp579rmj8dg37qty8lzff88" + "address":"cosmos1ujtnemf6jmfm995j000qdry064n5lq854gfe3j" }, "currency":{ "symbol":"stake", diff --git a/contrib/rosetta/configuration/data.sh b/contrib/rosetta/configuration/data.sh index 45297d5a21bf..4d7d5ff0b056 100644 --- a/contrib/rosetta/configuration/data.sh +++ b/contrib/rosetta/configuration/data.sh @@ -45,7 +45,7 @@ sleep 10 # send transaction to deterministic address echo sending transaction with addr $addr -simd tx bank send "$addr" cosmos1wjmt63j4fv9nqda92nsrp2jp2vsukcke4va3pt 100stake --yes --keyring-backend=test --broadcast-mode=block --chain-id=testing +simd tx bank send "$addr" cosmos19g9cm8ymzchq2qkcdv3zgqtwayj9asv3hjv5u5 100stake --yes --keyring-backend=test --broadcast-mode=block --chain-id=testing sleep 10 diff --git a/contrib/rosetta/configuration/rosetta.json b/contrib/rosetta/configuration/rosetta.json index 39a0bb3811dd..b4adc6a756f1 100644 --- a/contrib/rosetta/configuration/rosetta.json +++ b/contrib/rosetta/configuration/rosetta.json @@ -25,7 +25,7 @@ "constructor_dsl_file": "transfer.ros", "end_conditions": { "create_account": 1, - "transfer": 3 + "transfer": 1 } }, "data": { diff --git a/contrib/rosetta/configuration/run_tests.sh b/contrib/rosetta/configuration/run_tests.sh index cd7af92acda2..c53f89ff88a4 100755 --- a/contrib/rosetta/configuration/run_tests.sh +++ b/contrib/rosetta/configuration/run_tests.sh @@ -2,16 +2,6 @@ set -e -addr="abcd" - -send_tx() { - echo '12345678' | simd tx bank send $addr "$1" "$2" -} - -detect_account() { - line=$1 -} - wait_for_rosetta() { timeout 30 sh -c 'until nc -z $0 $1; do sleep 1; done' rosetta 8080 } @@ -25,5 +15,3 @@ rosetta-cli check:data --configuration-file ./config/rosetta.json echo "checking construction API" rosetta-cli check:construction --configuration-file ./config/rosetta.json -echo "checking staking API" -rosetta-cli check:construction --configuration-file ./config/staking.json diff --git a/contrib/rosetta/configuration/staking.json b/contrib/rosetta/configuration/staking.json deleted file mode 100644 index 9c5e5da3ba46..000000000000 --- a/contrib/rosetta/configuration/staking.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "network": { - "blockchain": "app", - "network": "network" - }, - "online_url": "http://rosetta:8080", - "data_directory": "", - "http_timeout": 300, - "max_retries": 5, - "retry_elapsed_time": 0, - "max_online_connections": 0, - "max_sync_concurrency": 0, - "tip_delay": 60, - "log_configuration": true, - "construction": { - "offline_url": "http://rosetta:8080", - "max_offline_connections": 0, - "stale_depth": 0, - "broadcast_limit": 0, - "ignore_broadcast_failures": false, - "clear_broadcasts": false, - "broadcast_behind_tip": false, - "block_broadcast_limit": 0, - "rebroadcast_all": false, - "constructor_dsl_file": "staking.ros", - "end_conditions": { - "staking": 3 - } - } -} \ No newline at end of file diff --git a/contrib/rosetta/configuration/staking.ros b/contrib/rosetta/configuration/staking.ros deleted file mode 100644 index 4f89a43b9893..000000000000 --- a/contrib/rosetta/configuration/staking.ros +++ /dev/null @@ -1,147 +0,0 @@ -request_funds(1){ - find_account{ - currency = {"symbol":"stake", "decimals":0}; - random_account = find_balance({ - "minimum_balance":{ - "value": "0", - "currency": {{currency}} - }, - "create_limit":1 - }); - }, - send_funds{ - account_identifier = {{random_account.account_identifier}}; - address = {{account_identifier.address}}; - idk = http_request({ - "method": "POST", - "url": "http:\/\/faucet:8000", - "timeout": 10, - "body": {{random_account.account_identifier.address}} - }); - }, - // Create a separate scenario to request funds so that - // the address we are using to request funds does not - // get rolled back if funds do not yet exist. - request{ - loaded_account = find_balance({ - "account_identifier": {{random_account.account_identifier}}, - "minimum_balance":{ - "value": "100", - "currency": {{currency}} - } - }); - } -} -create_account(1){ - create{ - network = {"network":"network", "blockchain":"app"}; - key = generate_key({"curve_type": "secp256k1"}); - account = derive({ - "network_identifier": {{network}}, - "public_key": {{key.public_key}} - }); - // If the account is not saved, the key will be lost! - save_account({ - "account_identifier": {{account.account_identifier}}, - "keypair": {{key}} - }); - } -} - -staking(1){ - stake{ - stake.network = {"network":"network", "blockchain":"app"}; - currency = {"symbol":"stake", "decimals":0}; - sender = find_balance({ - "minimum_balance":{ - "value": "100", - "currency": {{currency}} - } - }); - // Set the recipient_amount as some value <= sender.balance-max_fee - max_fee = "0"; - fee_amount = "1"; - fee_value = 0 - {{fee_amount}}; - available_amount = {{sender.balance.value}} - {{max_fee}}; - recipient_amount = "1"; - print_message({"recipient_amount":{{recipient_amount}}}); - // Find recipient and construct operations - recipient = {{sender.account_identifier}}; - sender_amount = 0 - {{recipient_amount}}; - stake.confirmation_depth = "1"; - stake.operations = [ - { - "operation_identifier":{"index":0}, - "type":"fee", - "account":{{sender.account_identifier}}, - "amount":{ - "value":{{fee_value}}, - "currency":{{currency}} - } - }, - { - "operation_identifier":{"index":1}, - "type":"cosmos.staking.v1beta1.MsgDelegate", - "account":{{sender.account_identifier}}, - "amount":{ - "value":{{sender_amount}}, - "currency":{{currency}} - } - }, - { - "operation_identifier":{"index":2}, - "type":"cosmos.staking.v1beta1.MsgDelegate", - "account": { - "address": "staking_account", - "sub_account": { - "address" : "cosmosvaloper158nkd0l9tyemv2crp579rmj8dg37qty86kaut5" - } - }, - "amount":{ - "value":{{recipient_amount}}, - "currency":{{currency}} - } - } - ]; - }, - undelegate{ - print_message({"undelegate":{{sender}}}); - - undelegate.network = {"network":"network", "blockchain":"app"}; - undelegate.confirmation_depth = "1"; - undelegate.operations = [ - { - "operation_identifier":{"index":0}, - "type":"fee", - "account":{{sender.account_identifier}}, - "amount":{ - "value":{{fee_value}}, - "currency":{{currency}} - } - }, - { - "operation_identifier":{"index":1}, - "type":"cosmos.staking.v1beta1.MsgUndelegate", - "account":{{sender.account_identifier}}, - "amount":{ - "value":{{recipient_amount}}, - "currency":{{currency}} - } - }, - { - "operation_identifier":{"index":2}, - "type":"cosmos.staking.v1beta1.MsgUndelegate", - "account": { - "address": "staking_account", - "sub_account": { - "address" : "cosmosvaloper158nkd0l9tyemv2crp579rmj8dg37qty86kaut5" - } - }, - "amount":{ - "value":{{sender_amount}}, - "currency":{{currency}} - } - } - ]; - } -} diff --git a/contrib/rosetta/configuration/transfer.ros b/contrib/rosetta/configuration/transfer.ros index a1cb3f8caf89..74ebd2ddf50c 100644 --- a/contrib/rosetta/configuration/transfer.ros +++ b/contrib/rosetta/configuration/transfer.ros @@ -26,7 +26,7 @@ request_funds(1){ loaded_account = find_balance({ "account_identifier": {{random_account.account_identifier}}, "minimum_balance":{ - "value": "100", + "value": "50", "currency": {{currency}} } }); @@ -57,6 +57,8 @@ transfer(3){ "currency": {{currency}} } }); + acc_identifier = {{sender.account_identifier}}; + sender_address = {{acc_identifier.address}}; // Set the recipient_amount as some value <= sender.balance-max_fee max_fee = "0"; fee_amount = "1"; @@ -76,34 +78,28 @@ transfer(3){ "create_probability": 50 }); transfer.confirmation_depth = "1"; + recipient_account_identifier = {{recipient.account_identifier}}; + recipient_address = {{recipient_account_identifier.address}}; transfer.operations = [ { "operation_identifier":{"index":0}, - "type":"fee", - "account":{{sender.account_identifier}}, - "amount":{ - "value":{{fee_value}}, - "currency":{{currency}} - } - }, - { - "operation_identifier":{"index":1}, "type":"cosmos.bank.v1beta1.MsgSend", "account":{{sender.account_identifier}}, - "amount":{ - "value":{{sender_amount}}, - "currency":{{currency}} - } - }, - { - "operation_identifier":{"index":2}, - "type":"cosmos.bank.v1beta1.MsgSend", - "account":{{recipient.account_identifier}}, - "amount":{ - "value":{{recipient_amount}}, - "currency":{{currency}} + "metadata": { + "amount": [ + { + "amount": {{recipient_amount}}, + "denom": {{currency.symbol}} + } + ], + "from_address": {{sender_address}}, + "to_address": {{recipient_address}} } } ]; + transfer.preprocess_metadata = { + "gas_price": "1stake", + "gas_limit": 250000 + }; } } diff --git a/contrib/rosetta/docker-compose.yaml b/contrib/rosetta/docker-compose.yaml index 0a9e82de8a9e..930fb83b6ddf 100644 --- a/contrib/rosetta/docker-compose.yaml +++ b/contrib/rosetta/docker-compose.yaml @@ -7,8 +7,8 @@ services: ports: - 9090:9090 - 26657:26657 - logging: - driver: "none" + #logging: + # driver: "none" rosetta: image: rosetta-ci:latest diff --git a/contrib/rosetta/node/data.tar.gz b/contrib/rosetta/node/data.tar.gz index ad285ac62e75..987bb88b33ac 100644 Binary files a/contrib/rosetta/node/data.tar.gz and b/contrib/rosetta/node/data.tar.gz differ diff --git a/docs/core/baseapp.md b/docs/core/baseapp.md index 5d0fd115f3ef..a0021e88648c 100644 --- a/docs/core/baseapp.md +++ b/docs/core/baseapp.md @@ -104,7 +104,7 @@ Finally, a few more important parameterd: ```go func NewBaseApp( - name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecoder, options ...func(*BaseApp), + name string, logger log.Logger, db dbm.DB, txDecode sdk.TxDecoder, options ...func(*BaseApp), ) *BaseApp { // ... diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 9e985a6a6a1b..814dfaeb27fb 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -117,10 +117,20 @@ - [Pairs](#cosmos.base.kv.v1beta1.Pairs) - [cosmos/base/reflection/v1beta1/reflection.proto](#cosmos/base/reflection/v1beta1/reflection.proto) + - [DeliverableDescriptor](#cosmos.base.reflection.v1beta1.DeliverableDescriptor) - [ListAllInterfacesRequest](#cosmos.base.reflection.v1beta1.ListAllInterfacesRequest) - [ListAllInterfacesResponse](#cosmos.base.reflection.v1beta1.ListAllInterfacesResponse) + - [ListDeliverablesRequest](#cosmos.base.reflection.v1beta1.ListDeliverablesRequest) + - [ListDeliverablesResponse](#cosmos.base.reflection.v1beta1.ListDeliverablesResponse) - [ListImplementationsRequest](#cosmos.base.reflection.v1beta1.ListImplementationsRequest) - [ListImplementationsResponse](#cosmos.base.reflection.v1beta1.ListImplementationsResponse) + - [ListQueriesRequest](#cosmos.base.reflection.v1beta1.ListQueriesRequest) + - [ListQueriesResponse](#cosmos.base.reflection.v1beta1.ListQueriesResponse) + - [QueryDescriptor](#cosmos.base.reflection.v1beta1.QueryDescriptor) + - [ResolveProtoTypeRequest](#cosmos.base.reflection.v1beta1.ResolveProtoTypeRequest) + - [ResolveProtoTypeResponse](#cosmos.base.reflection.v1beta1.ResolveProtoTypeResponse) + - [ResolveServiceRequest](#cosmos.base.reflection.v1beta1.ResolveServiceRequest) + - [ResolveServiceResponse](#cosmos.base.reflection.v1beta1.ResolveServiceResponse) - [ReflectionService](#cosmos.base.reflection.v1beta1.ReflectionService) @@ -2014,6 +2024,22 @@ Pairs defines a repeated slice of Pair objects. + + +### DeliverableDescriptor + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `method` | [string](#string) | | | +| `proto_name` | [string](#string) | | | + + + + + + ### ListAllInterfacesRequest @@ -2039,6 +2065,31 @@ ListAllInterfacesResponse is the response type of the ListAllInterfaces RPC. + + +### ListDeliverablesRequest + + + + + + + + + +### ListDeliverablesResponse + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `deliverables` | [DeliverableDescriptor](#cosmos.base.reflection.v1beta1.DeliverableDescriptor) | repeated | | + + + + + + ### ListImplementationsRequest @@ -2064,7 +2115,110 @@ RPC. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `implementation_message_names` | [string](#string) | repeated | | +| `implementation_message_names` | [string](#string) | repeated | implementation_message_names returns the names as saved in the codec | +| `implementation_message_proto_names` | [string](#string) | repeated | implementation_message_proto_names returns the protobuf names of the implementers | + + + + + + + + +### ListQueriesRequest + + + + + + + + + +### ListQueriesResponse + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `queries` | [QueryDescriptor](#cosmos.base.reflection.v1beta1.QueryDescriptor) | repeated | | + + + + + + + + +### QueryDescriptor + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `service_name` | [string](#string) | | | +| `proto_file` | [string](#string) | | | + + + + + + + + +### ResolveProtoTypeRequest + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `name` | [string](#string) | | | + + + + + + + + +### ResolveProtoTypeResponse + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `raw_descriptor` | [bytes](#bytes) | | | +| `indexes` | [int64](#int64) | repeated | | + + + + + + + + +### ResolveServiceRequest + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `file_name` | [string](#string) | | | + + + + + + + + +### ResolveServiceResponse + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `raw_descriptor` | [bytes](#bytes) | | | @@ -2086,6 +2240,10 @@ ReflectionService defines a service for interface reflection. | ----------- | ------------ | ------------- | ------------| ------- | -------- | | `ListAllInterfaces` | [ListAllInterfacesRequest](#cosmos.base.reflection.v1beta1.ListAllInterfacesRequest) | [ListAllInterfacesResponse](#cosmos.base.reflection.v1beta1.ListAllInterfacesResponse) | ListAllInterfaces lists all the interfaces registered in the interface registry. | GET|/cosmos/base/reflection/v1beta1/interfaces| | `ListImplementations` | [ListImplementationsRequest](#cosmos.base.reflection.v1beta1.ListImplementationsRequest) | [ListImplementationsResponse](#cosmos.base.reflection.v1beta1.ListImplementationsResponse) | ListImplementations list all the concrete types that implement a given interface. | GET|/cosmos/base/reflection/v1beta1/interfaces/{interface_name}/implementations| +| `ListDeliverables` | [ListDeliverablesRequest](#cosmos.base.reflection.v1beta1.ListDeliverablesRequest) | [ListDeliverablesResponse](#cosmos.base.reflection.v1beta1.ListDeliverablesResponse) | ListDeliverables provides a list of all the messages that can be passed to the deliver tx endpoint of the tendermint node for the application | | +| `ListQueryServices` | [ListQueriesRequest](#cosmos.base.reflection.v1beta1.ListQueriesRequest) | [ListQueriesResponse](#cosmos.base.reflection.v1beta1.ListQueriesResponse) | ListQueries lists the queries that the application supports | | +| `ResolveProtoType` | [ResolveProtoTypeRequest](#cosmos.base.reflection.v1beta1.ResolveProtoTypeRequest) | [ResolveProtoTypeResponse](#cosmos.base.reflection.v1beta1.ResolveProtoTypeResponse) | ResolveProtoType returns the raw descriptor of the given type | | +| `ResolveService` | [ResolveServiceRequest](#cosmos.base.reflection.v1beta1.ResolveServiceRequest) | [ResolveServiceResponse](#cosmos.base.reflection.v1beta1.ResolveServiceResponse) | | | diff --git a/go.mod b/go.mod index d409d401313f..5250e1ad322c 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 github.com/improbable-eng/grpc-web v0.14.0 github.com/magiconair/properties v1.8.4 + github.com/manifoldco/promptui v0.8.0 github.com/mattn/go-isatty v0.0.12 github.com/otiai10/copy v1.5.0 github.com/pelletier/go-toml v1.8.1 // indirect @@ -45,7 +46,7 @@ require ( github.com/spf13/viper v1.7.1 github.com/stretchr/testify v1.7.0 github.com/tendermint/btcd v0.1.1 - github.com/tendermint/cosmos-rosetta-gateway v0.3.0-rc2 + github.com/tendermint/cosmos-rosetta-gateway v0.3.0-rc2.0.20210304154332-87d6ca4410df github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.16.0 github.com/tendermint/tendermint v0.34.8 diff --git a/go.sum b/go.sum index a2c9cd63ed57..97aad04b491a 100644 --- a/go.sum +++ b/go.sum @@ -101,6 +101,12 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= @@ -383,6 +389,8 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -412,13 +420,18 @@ github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoR github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4= +github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw= +github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo= +github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= @@ -660,8 +673,8 @@ github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzH github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= -github.com/tendermint/cosmos-rosetta-gateway v0.3.0-rc2 h1:crekJuQ57yIBDuKd3/dMJ00ZvOHURuv9RGJSi2hWTW4= -github.com/tendermint/cosmos-rosetta-gateway v0.3.0-rc2/go.mod h1:gBPw8WV2Erm4UGHlBRiM3zaEBst4bsuihmMCNQdgP/s= +github.com/tendermint/cosmos-rosetta-gateway v0.3.0-rc2.0.20210304154332-87d6ca4410df h1:hoMLrOS4WyyMM+Y+iWdGu94o0zzp6Q43y7v89Q1/OIw= +github.com/tendermint/cosmos-rosetta-gateway v0.3.0-rc2.0.20210304154332-87d6ca4410df/go.mod h1:gBPw8WV2Erm4UGHlBRiM3zaEBst4bsuihmMCNQdgP/s= github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI= github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= diff --git a/proto/cosmos/base/reflection/v1beta1/reflection.proto b/proto/cosmos/base/reflection/v1beta1/reflection.proto index 22670e72b883..be02949504cc 100644 --- a/proto/cosmos/base/reflection/v1beta1/reflection.proto +++ b/proto/cosmos/base/reflection/v1beta1/reflection.proto @@ -19,6 +19,56 @@ service ReflectionService { option (google.api.http).get = "/cosmos/base/reflection/v1beta1/interfaces/" "{interface_name}/implementations"; }; + + // ListDeliverables provides a list of all the messages that can be passed to the + // deliver tx endpoint of the tendermint node for the application + rpc ListDeliverables(ListDeliverablesRequest) returns (ListDeliverablesResponse) {} + + // ListQueries lists the queries that the application supports + rpc ListQueryServices(ListQueriesRequest) returns (ListQueriesResponse) {} + + // ResolveProtoType returns the raw descriptor of the given type + rpc ResolveProtoType(ResolveProtoTypeRequest) returns (ResolveProtoTypeResponse) {} + + rpc ResolveService(ResolveServiceRequest) returns (ResolveServiceResponse) {} +} + +message ResolveProtoTypeRequest { + string name = 1; +} + +message ResolveProtoTypeResponse { + bytes raw_descriptor = 1; + repeated int64 indexes = 2; +} + +message ResolveServiceRequest { + string file_name = 1; +} + +message ResolveServiceResponse { + bytes raw_descriptor = 1; +} + +message ListDeliverablesRequest {} +message ListDeliverablesResponse { + repeated DeliverableDescriptor deliverables = 1; +} + +message DeliverableDescriptor { + string method = 1; + string proto_name = 2; +} + +message ListQueriesRequest {} + +message ListQueriesResponse { + repeated QueryDescriptor queries = 1; +} + +message QueryDescriptor { + string service_name = 1; + string proto_file = 2; } // ListAllInterfacesRequest is the request type of the ListAllInterfaces RPC. @@ -40,5 +90,8 @@ message ListImplementationsRequest { // ListImplementationsResponse is the response type of the ListImplementations // RPC. message ListImplementationsResponse { + // implementation_message_names returns the names as saved in the codec repeated string implementation_message_names = 1; + // implementation_message_proto_names returns the protobuf names of the implementers + repeated string implementation_message_proto_names = 2; } diff --git a/server/rosetta/client_offline.go b/server/rosetta/client_offline.go index f619bfc6d2cf..fb193d0aa584 100644 --- a/server/rosetta/client_offline.go +++ b/server/rosetta/client_offline.go @@ -3,28 +3,21 @@ package rosetta import ( "context" "encoding/hex" - "strings" - "github.com/btcsuite/btcd/btcec" "github.com/coinbase/rosetta-sdk-go/types" crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors" - "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" ) func (c *Client) OperationStatuses() []*types.OperationStatus { return []*types.OperationStatus{ { - Status: StatusSuccess, + Status: StatusTxSuccess, Successful: true, }, { - Status: StatusReverted, + Status: StatusTxReverted, Successful: false, }, } @@ -35,76 +28,11 @@ func (c *Client) Version() string { } func (c *Client) SupportedOperations() []string { - var supportedOperations []string - for _, ii := range c.ir.ListImplementations("cosmos.base.v1beta1.Msg") { - resolve, err := c.ir.Resolve(ii) - if err != nil { - continue - } - - if _, ok := resolve.(Msg); ok { - supportedOperations = append(supportedOperations, strings.TrimLeft(ii, "/")) - } - } - - supportedOperations = append(supportedOperations, OperationFee) - - return supportedOperations + return c.supportedOperations } -func (c *Client) SignedTx(ctx context.Context, txBytes []byte, signatures []*types.Signature) (signedTxBytes []byte, err error) { - TxConfig := c.getTxConfig() - rawTx, err := TxConfig.TxDecoder()(txBytes) - if err != nil { - return nil, err - } - - txBldr, err := TxConfig.WrapTxBuilder(rawTx) - if err != nil { - return nil, err - } - - var sigs = make([]signing.SignatureV2, len(signatures)) - for i, signature := range signatures { - if signature.PublicKey.CurveType != types.Secp256k1 { - return nil, crgerrs.ErrUnsupportedCurve - } - - cmp, err := btcec.ParsePubKey(signature.PublicKey.Bytes, btcec.S256()) - if err != nil { - return nil, err - } - - compressedPublicKey := make([]byte, secp256k1.PubKeySize) - copy(compressedPublicKey, cmp.SerializeCompressed()) - pubKey := &secp256k1.PubKey{Key: compressedPublicKey} - - accountInfo, err := c.accountInfo(ctx, sdk.AccAddress(pubKey.Address()).String(), nil) - if err != nil { - return nil, err - } - - sig := signing.SignatureV2{ - PubKey: pubKey, - Data: &signing.SingleSignatureData{ - SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, - Signature: signature.Bytes, - }, - Sequence: accountInfo.GetSequence(), - } - sigs[i] = sig - } - - if err = txBldr.SetSignatures(sigs...); err != nil { - return nil, err - } - - txBytes, err = c.getTxConfig().TxEncoder()(txBldr.GetTx()) - if err != nil { - return nil, err - } - - return txBytes, nil +func (c *Client) SignedTx(_ context.Context, txBytes []byte, signatures []*types.Signature) (signedTxBytes []byte, err error) { + return c.converter.ToSDK().SignedTx(txBytes, signatures) } func (c *Client) ConstructionPayload(_ context.Context, request *types.ConstructionPayloadsRequest) (resp *types.ConstructionPayloadsResponse, err error) { @@ -113,109 +41,90 @@ func (c *Client) ConstructionPayload(_ context.Context, request *types.Construct return nil, crgerrs.WrapError(crgerrs.ErrInvalidOperation, "expected at least one operation") } - // convert rosetta operations to sdk msgs and fees (if present) - msgs, fee, err := opsToMsgsAndFees(c.ir, request.Operations) + tx, err := c.converter.ToSDK().UnsignedTx(request.Operations) if err != nil { return nil, crgerrs.WrapError(crgerrs.ErrInvalidOperation, err.Error()) } - metadata, err := getMetadataFromPayloadReq(request) - if err != nil { - return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) + metadata := new(ConstructionMetadata) + if err = metadata.FromMetadata(request.Metadata); err != nil { + return nil, err } - txFactory := tx.Factory{}.WithAccountNumber(metadata.AccountNumber).WithChainID(metadata.ChainID). - WithGas(metadata.Gas).WithSequence(metadata.Sequence).WithMemo(metadata.Memo).WithFees(fee.String()) - - TxConfig := c.getTxConfig() - txFactory = txFactory.WithTxConfig(TxConfig) - - txBldr, err := tx.BuildUnsignedTx(txFactory, msgs...) + txBytes, payloads, err := c.converter.ToRosetta().SigningComponents(tx, metadata, request.PublicKeys) if err != nil { return nil, err } - // Sign_mode_legacy_amino is being used as default here, as sign_mode_direct - // needs the signer infos to be set before hand but rosetta doesn't have a way - // to do this yet. To be revisited in future versions of sdk and rosetta - if txFactory.SignMode() == signing.SignMode_SIGN_MODE_UNSPECIFIED { - txFactory = txFactory.WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) - } - - signerData := authsigning.SignerData{ - ChainID: txFactory.ChainID(), - AccountNumber: txFactory.AccountNumber(), - Sequence: txFactory.Sequence(), - } + return &types.ConstructionPayloadsResponse{ + UnsignedTransaction: hex.EncodeToString(txBytes), + Payloads: payloads, + }, nil +} - signBytes, err := TxConfig.SignModeHandler().GetSignBytes(txFactory.SignMode(), signerData, txBldr.GetTx()) - if err != nil { - return nil, err +func (c *Client) PreprocessOperationsToOptions(_ context.Context, req *types.ConstructionPreprocessRequest) (response *types.ConstructionPreprocessResponse, err error) { + if len(req.Operations) == 0 { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "no operations") } - txBytes, err := TxConfig.TxEncoder()(txBldr.GetTx()) + // now we need to parse the operations to cosmos sdk messages + tx, err := c.converter.ToSDK().UnsignedTx(req.Operations) if err != nil { return nil, err } - accIdentifiers := getAccountIdentifiersByMsgs(msgs) + // get the signers + signers := tx.GetSigners() + signersStr := make([]string, len(signers)) + accountIdentifiers := make([]*types.AccountIdentifier, len(signers)) - payloads := make([]*types.SigningPayload, len(accIdentifiers)) - for i, accID := range accIdentifiers { - payloads[i] = &types.SigningPayload{ - AccountIdentifier: accID, - Bytes: crypto.Sha256(signBytes), - SignatureType: types.Ecdsa, + for i, sig := range signers { + addr := sig.String() + signersStr[i] = addr + accountIdentifiers[i] = &types.AccountIdentifier{ + Address: addr, } } - - return &types.ConstructionPayloadsResponse{ - UnsignedTransaction: hex.EncodeToString(txBytes), - Payloads: payloads, - }, nil -} - -func getAccountIdentifiersByMsgs(msgs []sdk.Msg) []*types.AccountIdentifier { - var accIdentifiers []*types.AccountIdentifier - for _, msg := range msgs { - for _, signer := range msg.GetSigners() { - accIdentifiers = append(accIdentifiers, &types.AccountIdentifier{Address: signer.String()}) - } + // get the metadata request information + meta := new(ConstructionPreprocessMetadata) + err = meta.FromMetadata(req.Metadata) + if err != nil { + return nil, err } - return accIdentifiers -} - -func (c *Client) PreprocessOperationsToOptions(_ context.Context, req *types.ConstructionPreprocessRequest) (options map[string]interface{}, err error) { - operations := req.Operations - if len(operations) < 1 { - return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "invalid number of operations") + if meta.GasPrice == "" { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "no gas prices") } - msgs, err := opsToMsgs(c.ir, operations) - if err != nil { - return nil, crgerrs.WrapError(crgerrs.ErrInvalidOperation, err.Error()) + if meta.GasLimit == 0 { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "no gas limit") } - if len(msgs) < 1 || len(msgs[0].GetSigners()) < 1 { - return nil, crgerrs.WrapError(crgerrs.ErrInvalidOperation, "operation produced no msg or signers") + // prepare the options to return + options := &PreprocessOperationsOptionsResponse{ + ExpectedSigners: signersStr, + Memo: meta.Memo, + GasLimit: meta.GasLimit, + GasPrice: meta.GasPrice, } - memo, ok := req.Metadata["memo"] - if !ok { - memo = "" + metaOptions, err := options.ToMetadata() + if err != nil { + return nil, err } + return &types.ConstructionPreprocessResponse{ + Options: metaOptions, + RequiredPublicKeys: accountIdentifiers, + }, nil +} - defaultGas := float64(200000) - - gas := req.SuggestedFeeMultiplier - if gas == nil { - gas = &defaultGas +func (c *Client) AccountIdentifierFromPublicKey(pubKey *types.PublicKey) (*types.AccountIdentifier, error) { + pk, err := c.converter.ToSDK().PubKey(pubKey) + if err != nil { + return nil, err } - return map[string]interface{}{ - OptionAddress: msgs[0].GetSigners()[0], - OptionMemo: memo, - OptionGas: gas, + return &types.AccountIdentifier{ + Address: sdk.AccAddress(pk.Address()).String(), }, nil } diff --git a/server/rosetta/client_online.go b/server/rosetta/client_online.go index f5e5cfafeebf..9e18cdeb6182 100644 --- a/server/rosetta/client_online.go +++ b/server/rosetta/client_online.go @@ -6,34 +6,29 @@ import ( "encoding/hex" "fmt" "strconv" + "strings" "time" "github.com/cosmos/cosmos-sdk/version" abcitypes "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/btcd/btcec" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - - "github.com/coinbase/rosetta-sdk-go/types" + rosettatypes "github.com/coinbase/rosetta-sdk-go/types" "google.golang.org/grpc/metadata" "github.com/tendermint/tendermint/rpc/client/http" - tmtypes "github.com/tendermint/tendermint/rpc/core/types" "google.golang.org/grpc" crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors" crgtypes "github.com/tendermint/cosmos-rosetta-gateway/types" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" auth "github.com/cosmos/cosmos-sdk/x/auth/types" bank "github.com/cosmos/cosmos-sdk/x/bank/types" + + tmrpc "github.com/tendermint/tendermint/rpc/client" ) // interface assertion @@ -44,36 +39,17 @@ const defaultNodeTimeout = 15 * time.Second // Client implements a single network client to interact with cosmos based chains type Client struct { - config *Config - - auth auth.QueryClient - bank bank.QueryClient + supportedOperations []string - ir codectypes.InterfaceRegistry + config *Config - clientCtx client.Context + auth auth.QueryClient + bank bank.QueryClient + tmRPC tmrpc.Client version string -} - -func (c *Client) AccountIdentifierFromPublicKey(pubKey *types.PublicKey) (*types.AccountIdentifier, error) { - if pubKey.CurveType != "secp256k1" { - return nil, crgerrs.WrapError(crgerrs.ErrUnsupportedCurve, "only secp256k1 supported") - } - cmp, err := btcec.ParsePubKey(pubKey.Bytes, btcec.S256()) - if err != nil { - return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) - } - - compressedPublicKey := make([]byte, secp256k1.PubKeySize) - copy(compressedPublicKey, cmp.SerializeCompressed()) - - pk := secp256k1.PubKey{Key: compressedPublicKey} - - return &types.AccountIdentifier{ - Address: sdk.AccAddress(pk.Address()).String(), - }, nil + converter Converter } // NewClient instantiates a new online servicer @@ -85,14 +61,74 @@ func NewClient(cfg *Config) (*Client, error) { v = "unknown" } + txConfig := authtx.NewTxConfig(cfg.Codec, authtx.DefaultSignModes) + + var supportedOperations []string + for _, ii := range cfg.InterfaceRegistry.ListImplementations("cosmos.base.v1beta1.Msg") { + resolvedMsg, err := cfg.InterfaceRegistry.Resolve(ii) + if err != nil { + continue + } + + if _, ok := resolvedMsg.(sdk.Msg); ok { + supportedOperations = append(supportedOperations, strings.TrimLeft(ii, "/")) + } + } + + supportedOperations = append( + supportedOperations, + bank.EventTypeCoinSpent, bank.EventTypeCoinReceived, + ) + return &Client{ - config: cfg, - ir: cfg.InterfaceRegistry, - version: fmt.Sprintf("%s/%s", info.AppName, v), + supportedOperations: supportedOperations, + config: cfg, + auth: nil, + bank: nil, + tmRPC: nil, + version: fmt.Sprintf("%s/%s", info.AppName, v), + converter: NewConverter(cfg.Codec, cfg.InterfaceRegistry, txConfig), }, nil } -func (c *Client) accountInfo(ctx context.Context, addr string, height *int64) (auth.AccountI, error) { +// Bootstrap is gonna connect the client to the endpoints +func (c *Client) Bootstrap() error { + grpcConn, err := grpc.Dial(c.config.GRPCEndpoint, grpc.WithInsecure()) + if err != nil { + return err + } + + tmRPC, err := http.New(c.config.TendermintRPC, tmWebsocketPath) + if err != nil { + return err + } + + authClient := auth.NewQueryClient(grpcConn) + bankClient := bank.NewQueryClient(grpcConn) + + c.auth = authClient + c.bank = bankClient + c.tmRPC = tmRPC + + return nil +} + +// Ready asserts if the client is ready or not +func (c *Client) Ready() error { + ctx, cancel := context.WithTimeout(context.Background(), defaultNodeTimeout) + defer cancel() + _, err := c.tmRPC.Health(ctx) + if err != nil { + return err + } + _, err = c.bank.TotalSupply(ctx, &bank.QueryTotalSupplyRequest{}) + if err != nil { + return err + } + return nil +} + +func (c *Client) accountInfo(ctx context.Context, addr string, height *int64) (*SignerData, error) { if height != nil { strHeight := strconv.FormatInt(*height, 10) ctx = metadata.AppendToOutgoingContext(ctx, grpctypes.GRPCBlockHeightHeader, strHeight) @@ -105,16 +141,14 @@ func (c *Client) accountInfo(ctx context.Context, addr string, height *int64) (a return nil, crgerrs.FromGRPCToRosettaError(err) } - var account auth.AccountI - err = c.ir.UnpackAny(accountInfo.Account, &account) + signerData, err := c.converter.ToRosetta().SignerData(accountInfo.Account) if err != nil { - return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + return nil, err } - - return account, nil + return signerData, nil } -func (c *Client) Balances(ctx context.Context, addr string, height *int64) ([]*types.Amount, error) { +func (c *Client) Balances(ctx context.Context, addr string, height *int64) ([]*rosettatypes.Amount, error) { if height != nil { strHeight := strconv.FormatInt(*height, 10) ctx = metadata.AppendToOutgoingContext(ctx, grpctypes.GRPCBlockHeightHeader, strHeight) @@ -132,7 +166,7 @@ func (c *Client) Balances(ctx context.Context, addr string, height *int64) ([]*t return nil, err } - return sdkCoinsToRosettaAmounts(balance.Balances, availableCoins), nil + return c.converter.ToRosetta().Amounts(balance.Balances, availableCoins), nil } func (c *Client) BlockByHash(ctx context.Context, hash string) (crgtypes.BlockResponse, error) { @@ -141,64 +175,39 @@ func (c *Client) BlockByHash(ctx context.Context, hash string) (crgtypes.BlockRe return crgtypes.BlockResponse{}, fmt.Errorf("invalid block hash: %s", err) } - block, err := c.clientCtx.Client.BlockByHash(ctx, bHash) + block, err := c.tmRPC.BlockByHash(ctx, bHash) if err != nil { - return crgtypes.BlockResponse{}, err + return crgtypes.BlockResponse{}, crgerrs.WrapError(crgerrs.ErrBadGateway, err.Error()) } - return buildBlockResponse(block), nil + return c.converter.ToRosetta().BlockResponse(block), nil } func (c *Client) BlockByHeight(ctx context.Context, height *int64) (crgtypes.BlockResponse, error) { - block, err := c.clientCtx.Client.Block(ctx, height) + block, err := c.tmRPC.Block(ctx, height) if err != nil { - return crgtypes.BlockResponse{}, err + return crgtypes.BlockResponse{}, crgerrs.WrapError(crgerrs.ErrBadGateway, err.Error()) } - return buildBlockResponse(block), nil -} - -func buildBlockResponse(block *tmtypes.ResultBlock) crgtypes.BlockResponse { - return crgtypes.BlockResponse{ - Block: TMBlockToRosettaBlockIdentifier(block), - ParentBlock: TMBlockToRosettaParentBlockIdentifier(block), - MillisecondTimestamp: timeToMilliseconds(block.Block.Time), - TxCount: int64(len(block.Block.Txs)), - } + return c.converter.ToRosetta().BlockResponse(block), nil } func (c *Client) BlockTransactionsByHash(ctx context.Context, hash string) (crgtypes.BlockTransactionsResponse, error) { + // TODO(fdymylja): use a faster path, by searching the block by hash, instead of doing a double query operation blockResp, err := c.BlockByHash(ctx, hash) if err != nil { return crgtypes.BlockTransactionsResponse{}, err } - txs, err := c.listTransactionsInBlock(ctx, blockResp.Block.Index) - if err != nil { - return crgtypes.BlockTransactionsResponse{}, err - } - - return crgtypes.BlockTransactionsResponse{ - BlockResponse: blockResp, - Transactions: sdkTxsWithHashToRosettaTxs(txs), - }, nil + return c.blockTxs(ctx, &blockResp.Block.Index) } func (c *Client) BlockTransactionsByHeight(ctx context.Context, height *int64) (crgtypes.BlockTransactionsResponse, error) { - blockResp, err := c.BlockByHeight(ctx, height) - if err != nil { - return crgtypes.BlockTransactionsResponse{}, err - } - - txs, err := c.listTransactionsInBlock(ctx, blockResp.Block.Index) + blockTxResp, err := c.blockTxs(ctx, height) if err != nil { return crgtypes.BlockTransactionsResponse{}, err } - - return crgtypes.BlockTransactionsResponse{ - BlockResponse: blockResp, - Transactions: sdkTxsWithHashToRosettaTxs(txs), - }, nil + return blockTxResp, nil } // Coins fetches the existing coins in the application @@ -210,69 +219,80 @@ func (c *Client) coins(ctx context.Context) (sdk.Coins, error) { return supply.Supply, nil } -// listTransactionsInBlock returns the list of the transactions in a block given its height -func (c *Client) listTransactionsInBlock(ctx context.Context, height int64) ([]*sdkTxWithHash, error) { - txQuery := fmt.Sprintf(`tx.height=%d`, height) - txList, err := c.clientCtx.Client.TxSearch(ctx, txQuery, true, nil, nil, "") - if err != nil { - return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) - } - - sdkTxs, err := tmResultTxsToSdkTxsWithHash(c.clientCtx.TxConfig.TxDecoder(), txList.Txs) - if err != nil { - return nil, err +func (c *Client) TxOperationsAndSignersAccountIdentifiers(signed bool, txBytes []byte) (ops []*rosettatypes.Operation, signers []*rosettatypes.AccountIdentifier, err error) { + switch signed { + case false: + rosTx, err := c.converter.ToRosetta().Tx(txBytes, nil) + if err != nil { + return nil, nil, err + } + return rosTx.Operations, nil, err + default: + ops, signers, err = c.converter.ToRosetta().OpsAndSigners(txBytes) + return } - return sdkTxs, nil } -func (c *Client) TxOperationsAndSignersAccountIdentifiers(signed bool, txBytes []byte) (ops []*types.Operation, signers []*types.AccountIdentifier, err error) { - txConfig := c.getTxConfig() - rawTx, err := txConfig.TxDecoder()(txBytes) +// GetTx returns a transaction given its hash, in rosetta begin block and end block are mocked +// as transaction hashes in order to adhere to balance tracking rules +func (c *Client) GetTx(ctx context.Context, hash string) (*rosettatypes.Transaction, error) { + hashBytes, err := hex.DecodeString(hash) if err != nil { - return nil, nil, err + return nil, crgerrs.WrapError(crgerrs.ErrCodec, fmt.Sprintf("bad tx hash: %s", err)) } - txBldr, err := txConfig.WrapTxBuilder(rawTx) - if err != nil { - return nil, nil, err - } + // get tx type and hash + txType, hashBytes := c.converter.ToSDK().HashToTxType(hashBytes) - var accountIdentifierSigners []*types.AccountIdentifier - if signed { - addrs := txBldr.GetTx().GetSigners() - for _, addr := range addrs { - signer := &types.AccountIdentifier{ - Address: addr.String(), - } - accountIdentifierSigners = append(accountIdentifierSigners, signer) + // construct rosetta tx + switch txType { + // handle begin block hash + case BeginBlockTx: + // get block height by hash + block, err := c.tmRPC.BlockByHash(ctx, hashBytes) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) } - } - return sdkTxToOperations(txBldr.GetTx(), false, false), accountIdentifierSigners, nil -} + // get block txs + fullBlock, err := c.blockTxs(ctx, &block.Block.Height) + if err != nil { + return nil, err + } -// GetTx returns a transaction given its hash -func (c *Client) GetTx(_ context.Context, hash string) (*types.Transaction, error) { - txResp, err := authtx.QueryTx(c.clientCtx, hash) - if err != nil { - return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) + return fullBlock.Transactions[0], nil + // handle deliver tx hash + case DeliverTxTx: + rawTx, err := c.tmRPC.Tx(ctx, hashBytes, true) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) + } + return c.converter.ToRosetta().Tx(rawTx.Tx, &rawTx.TxResult) + // handle end block hash + case EndBlockTx: + // get block height by hash + block, err := c.tmRPC.BlockByHash(ctx, hashBytes) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) + } + + // get block txs + fullBlock, err := c.blockTxs(ctx, &block.Block.Height) + if err != nil { + return nil, err + } + + // get last tx + return fullBlock.Transactions[len(fullBlock.Transactions)-1], nil + // unrecognized tx + default: + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, fmt.Sprintf("invalid tx hash provided: %s", hash)) } - var sdkTx sdk.Tx - err = c.ir.UnpackAny(txResp.Tx, &sdkTx) - if err != nil { - return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) - } - return sdkTxWithHashToOperations(&sdkTxWithHash{ - HexHash: txResp.TxHash, - Code: txResp.Code, - Log: txResp.RawLog, - Tx: sdkTx, - }), nil } // GetUnconfirmedTx gets an unconfirmed transaction given its hash -func (c *Client) GetUnconfirmedTx(ctx context.Context, hash string) (*types.Transaction, error) { - res, err := c.clientCtx.Client.UnconfirmedTxs(ctx, nil) +func (c *Client) GetUnconfirmedTx(ctx context.Context, hash string) (*rosettatypes.Transaction, error) { + res, err := c.tmRPC.UnconfirmedTxs(ctx, nil) if err != nil { return nil, crgerrs.WrapError(crgerrs.ErrNotFound, "unconfirmed tx not found") } @@ -282,165 +302,168 @@ func (c *Client) GetUnconfirmedTx(ctx context.Context, hash string) (*types.Tran return nil, crgerrs.WrapError(crgerrs.ErrInterpreting, "invalid hash") } - for _, tx := range res.Txs { - if bytes.Equal(tx.Hash(), hashAsBytes) { - sdkTx, err := tmTxToSdkTx(c.clientCtx.TxConfig.TxDecoder(), tx) - if err != nil { - return nil, err - } + // assert that correct tx length is provided + switch len(hashAsBytes) { + default: + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, fmt.Sprintf("unrecognized tx size: %d", len(hashAsBytes))) + case BeginEndBlockTxSize: + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "endblock and begin block txs cannot be unconfirmed") + case DeliverTxSize: + break + } - return &types.Transaction{ - TransactionIdentifier: TmTxToRosettaTxsIdentifier(tx), - Operations: sdkTxToOperations(sdkTx, false, false), - Metadata: nil, - }, nil + // iterate over unconfirmed txs to find the one with matching hash + for _, unconfirmedTx := range res.Txs { + if !bytes.Equal(unconfirmedTx.Hash(), hashAsBytes) { + continue } - } - return nil, crgerrs.WrapError(crgerrs.ErrNotFound, "transaction not found in mempool") + return c.converter.ToRosetta().Tx(unconfirmedTx, nil) + } + return nil, crgerrs.WrapError(crgerrs.ErrNotFound, "transaction not found in mempool: "+hash) } // Mempool returns the unconfirmed transactions in the mempool -func (c *Client) Mempool(ctx context.Context) ([]*types.TransactionIdentifier, error) { - txs, err := c.clientCtx.Client.UnconfirmedTxs(ctx, nil) +func (c *Client) Mempool(ctx context.Context) ([]*rosettatypes.TransactionIdentifier, error) { + txs, err := c.tmRPC.UnconfirmedTxs(ctx, nil) if err != nil { return nil, err } - return TMTxsToRosettaTxsIdentifiers(txs.Txs), nil + return c.converter.ToRosetta().TxIdentifiers(txs.Txs), nil } // Peers gets the number of peers -func (c *Client) Peers(ctx context.Context) ([]*types.Peer, error) { - netInfo, err := c.clientCtx.Client.NetInfo(ctx) +func (c *Client) Peers(ctx context.Context) ([]*rosettatypes.Peer, error) { + netInfo, err := c.tmRPC.NetInfo(ctx) if err != nil { return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) } - return TmPeersToRosettaPeers(netInfo.Peers), nil + return c.converter.ToRosetta().Peers(netInfo.Peers), nil } -func (c *Client) Status(ctx context.Context) (*types.SyncStatus, error) { - status, err := c.clientCtx.Client.Status(ctx) +func (c *Client) Status(ctx context.Context) (*rosettatypes.SyncStatus, error) { + status, err := c.tmRPC.Status(ctx) if err != nil { return nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) } - return TMStatusToRosettaSyncStatus(status), err -} - -func (c *Client) getTxConfig() client.TxConfig { - return c.clientCtx.TxConfig + return c.converter.ToRosetta().SyncStatus(status), err } -func (c *Client) PostTx(txBytes []byte) (*types.TransactionIdentifier, map[string]interface{}, error) { +func (c *Client) PostTx(txBytes []byte) (*rosettatypes.TransactionIdentifier, map[string]interface{}, error) { // sync ensures it will go through checkTx - res, err := c.clientCtx.BroadcastTxSync(txBytes) + res, err := c.tmRPC.BroadcastTxSync(context.Background(), txBytes) if err != nil { return nil, nil, crgerrs.WrapError(crgerrs.ErrUnknown, err.Error()) } // check if tx was broadcast successfully if res.Code != abcitypes.CodeTypeOK { - return nil, nil, crgerrs.WrapError(crgerrs.ErrUnknown, fmt.Sprintf("transaction broadcast failure: (%d) %s ", res.Code, res.RawLog)) + return nil, nil, crgerrs.WrapError( + crgerrs.ErrUnknown, + fmt.Sprintf("transaction broadcast failure: (%d) %s ", res.Code, res.Log), + ) } - return &types.TransactionIdentifier{ - Hash: res.TxHash, + return &rosettatypes.TransactionIdentifier{ + Hash: fmt.Sprintf("%X", res.Hash), }, map[string]interface{}{ - Log: res.RawLog, + Log: res.Log, }, nil } +// construction endpoints + +// ConstructionMetadataFromOptions builds the metadata given the options func (c *Client) ConstructionMetadataFromOptions(ctx context.Context, options map[string]interface{}) (meta map[string]interface{}, err error) { if len(options) == 0 { return nil, crgerrs.ErrBadArgument } - addr, ok := options[OptionAddress] - if !ok { - return nil, crgerrs.WrapError(crgerrs.ErrInvalidAddress, "no address provided") - } - - addrString, ok := addr.(string) - if !ok { - return nil, crgerrs.WrapError(crgerrs.ErrInvalidAddress, "address is not a string") - } + constructionOptions := new(PreprocessOperationsOptionsResponse) - accountInfo, err := c.accountInfo(ctx, addrString, nil) + err = constructionOptions.FromMetadata(options) if err != nil { return nil, err } - gas, ok := options[OptionGas] - if !ok { - return nil, crgerrs.WrapError(crgerrs.ErrInvalidAddress, "gas not set") - } + signersData := make([]*SignerData, len(constructionOptions.ExpectedSigners)) + + for i, signer := range constructionOptions.ExpectedSigners { + accountInfo, err := c.accountInfo(ctx, signer, nil) + if err != nil { + return nil, err + } - memo, ok := options[OptionMemo] - if !ok { - return nil, crgerrs.WrapError(crgerrs.ErrInvalidMemo, "memo not set") + signersData[i] = accountInfo } - status, err := c.clientCtx.Client.Status(ctx) + status, err := c.tmRPC.Status(ctx) if err != nil { return nil, err } - return map[string]interface{}{ - OptionAccountNumber: accountInfo.GetAccountNumber(), - OptionSequence: accountInfo.GetSequence(), - OptionChainID: status.NodeInfo.Network, - OptionGas: gas, - OptionMemo: memo, - }, nil + metadataResp := ConstructionMetadata{ + ChainID: status.NodeInfo.Network, + SignersData: signersData, + GasLimit: constructionOptions.GasLimit, + GasPrice: constructionOptions.GasPrice, + Memo: constructionOptions.Memo, + } + + return metadataResp.ToMetadata() } -func (c *Client) Ready() error { - ctx, cancel := context.WithTimeout(context.Background(), defaultNodeTimeout) - defer cancel() - _, err := c.clientCtx.Client.Health(ctx) +func (c *Client) blockTxs(ctx context.Context, height *int64) (crgtypes.BlockTransactionsResponse, error) { + // get block info + blockInfo, err := c.tmRPC.Block(ctx, height) if err != nil { - return err + return crgtypes.BlockTransactionsResponse{}, err } - _, err = c.bank.TotalSupply(ctx, &bank.QueryTotalSupplyRequest{}) + // get block events + blockResults, err := c.tmRPC.BlockResults(ctx, height) if err != nil { - return err + return crgtypes.BlockTransactionsResponse{}, err } - return nil -} -func (c *Client) Bootstrap() error { - grpcConn, err := grpc.Dial(c.config.GRPCEndpoint, grpc.WithInsecure()) - if err != nil { - return err + if len(blockResults.TxsResults) != len(blockInfo.Block.Txs) { + // wtf? + panic("block results transactions do now match block transactions") } - - tmRPC, err := http.New(c.config.TendermintRPC, tmWebsocketPath) - if err != nil { - return err + // process begin and end block txs + beginBlockTx := &rosettatypes.Transaction{ + TransactionIdentifier: &rosettatypes.TransactionIdentifier{Hash: c.converter.ToRosetta().BeginBlockTxHash(blockInfo.BlockID.Hash)}, + Operations: AddOperationIndexes( + nil, + c.converter.ToRosetta().BalanceOps(StatusTxSuccess, blockResults.BeginBlockEvents), + ), } - authClient := auth.NewQueryClient(grpcConn) - bankClient := bank.NewQueryClient(grpcConn) + endBlockTx := &rosettatypes.Transaction{ + TransactionIdentifier: &rosettatypes.TransactionIdentifier{Hash: c.converter.ToRosetta().EndBlockTxHash(blockInfo.BlockID.Hash)}, + Operations: AddOperationIndexes( + nil, + c.converter.ToRosetta().BalanceOps(StatusTxSuccess, blockResults.EndBlockEvents), + ), + } - // NodeURI and Client are set from here otherwise - // WitNodeURI will require to create a new client - // it's done here because WithNodeURI panics if - // connection to tendermint node fails - clientCtx := client.Context{ - Client: tmRPC, - NodeURI: c.config.TendermintRPC, - } - clientCtx = clientCtx. - WithJSONMarshaler(c.config.Codec). - WithInterfaceRegistry(c.config.InterfaceRegistry). - WithTxConfig(authtx.NewTxConfig(c.config.Codec, authtx.DefaultSignModes)). - WithAccountRetriever(auth.AccountRetriever{}). - WithBroadcastMode(flags.BroadcastBlock) + deliverTx := make([]*rosettatypes.Transaction, len(blockInfo.Block.Txs)) + // process normal txs + for i, tx := range blockInfo.Block.Txs { + rosTx, err := c.converter.ToRosetta().Tx(tx, blockResults.TxsResults[i]) + if err != nil { + return crgtypes.BlockTransactionsResponse{}, err + } + deliverTx[i] = rosTx + } - c.auth = authClient - c.bank = bankClient - c.clientCtx = clientCtx - c.ir = c.config.InterfaceRegistry + finalTxs := make([]*rosettatypes.Transaction, 0, 2+len(deliverTx)) + finalTxs = append(finalTxs, beginBlockTx) + finalTxs = append(finalTxs, deliverTx...) + finalTxs = append(finalTxs, endBlockTx) - return nil + return crgtypes.BlockTransactionsResponse{ + BlockResponse: c.converter.ToRosetta().BlockResponse(blockInfo), + Transactions: finalTxs, + }, nil } diff --git a/server/rosetta/conv_from_rosetta.go b/server/rosetta/conv_from_rosetta.go deleted file mode 100644 index da9ea5b2ed6f..000000000000 --- a/server/rosetta/conv_from_rosetta.go +++ /dev/null @@ -1,211 +0,0 @@ -package rosetta - -import ( - "fmt" - "time" - - "github.com/coinbase/rosetta-sdk-go/types" - tmcoretypes "github.com/tendermint/tendermint/rpc/core/types" - tmtypes "github.com/tendermint/tendermint/types" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// timeToMilliseconds converts time to milliseconds timestamp -func timeToMilliseconds(t time.Time) int64 { - return t.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) -} - -// sdkCoinsToRosettaAmounts converts []sdk.Coin to rosetta amounts -// availableCoins keeps track of current available coins vs the coins -// owned by an address. This is required to support historical balances -// as rosetta expects them to be set to 0, if an address does not own them -func sdkCoinsToRosettaAmounts(ownedCoins []sdk.Coin, availableCoins sdk.Coins) []*types.Amount { - amounts := make([]*types.Amount, len(availableCoins)) - ownedCoinsMap := make(map[string]sdk.Int, len(availableCoins)) - - for _, ownedCoin := range ownedCoins { - ownedCoinsMap[ownedCoin.Denom] = ownedCoin.Amount - } - - for i, coin := range availableCoins { - value, owned := ownedCoinsMap[coin.Denom] - if !owned { - amounts[i] = &types.Amount{ - Value: sdk.NewInt(0).String(), - Currency: &types.Currency{ - Symbol: coin.Denom, - }, - } - continue - } - amounts[i] = &types.Amount{ - Value: value.String(), - Currency: &types.Currency{ - Symbol: coin.Denom, - }, - } - } - - return amounts -} - -// sdkTxsWithHashToRosettaTxs converts sdk transactions wrapped with their hash to rosetta transactions -func sdkTxsWithHashToRosettaTxs(txs []*sdkTxWithHash) []*types.Transaction { - converted := make([]*types.Transaction, len(txs)) - for i, tx := range txs { - converted[i] = sdkTxWithHashToOperations(tx) - } - - return converted -} - -func sdkTxWithHashToOperations(tx *sdkTxWithHash) *types.Transaction { - hasError := tx.Code != 0 - return &types.Transaction{ - TransactionIdentifier: &types.TransactionIdentifier{Hash: tx.HexHash}, - Operations: sdkTxToOperations(tx.Tx, true, hasError), - Metadata: map[string]interface{}{ - Log: tx.Log, - }, - } -} - -// sdkTxToOperations converts an sdk.Tx to rosetta operations -func sdkTxToOperations(tx sdk.Tx, withStatus, hasError bool) []*types.Operation { - var operations []*types.Operation - - msgOps := sdkMsgsToRosettaOperations(tx.GetMsgs(), withStatus, hasError) - operations = append(operations, msgOps...) - - feeTx := tx.(sdk.FeeTx) - feeOps := sdkFeeTxToOperations(feeTx, withStatus, len(msgOps)) - operations = append(operations, feeOps...) - - return operations -} - -// sdkFeeTxToOperations converts sdk.FeeTx to rosetta operations -func sdkFeeTxToOperations(feeTx sdk.FeeTx, withStatus bool, previousOps int) []*types.Operation { - feeCoins := feeTx.GetFee() - var ops []*types.Operation - if feeCoins != nil { - var feeOps = rosettaFeeOperationsFromCoins(feeCoins, feeTx.FeePayer().String(), withStatus, previousOps) - ops = append(ops, feeOps...) - } - - return ops -} - -// rosettaFeeOperationsFromCoins returns the list of rosetta fee operations given sdk coins -func rosettaFeeOperationsFromCoins(coins sdk.Coins, account string, withStatus bool, previousOps int) []*types.Operation { - feeOps := make([]*types.Operation, 0) - var status string - if withStatus { - status = StatusSuccess - } - - for i, coin := range coins { - op := &types.Operation{ - OperationIdentifier: &types.OperationIdentifier{ - Index: int64(previousOps + i), - }, - Type: OperationFee, - Status: status, - Account: &types.AccountIdentifier{ - Address: account, - }, - Amount: &types.Amount{ - Value: "-" + coin.Amount.String(), - Currency: &types.Currency{ - Symbol: coin.Denom, - }, - }, - } - - feeOps = append(feeOps, op) - } - - return feeOps -} - -// sdkMsgsToRosettaOperations converts sdk messages to rosetta operations -func sdkMsgsToRosettaOperations(msgs []sdk.Msg, withStatus bool, hasError bool) []*types.Operation { - var operations []*types.Operation - for _, msg := range msgs { - if rosettaMsg, ok := msg.(Msg); ok { - operations = append(operations, rosettaMsg.ToOperations(withStatus, hasError)...) - } - } - - return operations -} - -// TMTxsToRosettaTxsIdentifiers converts a tendermint raw transactions into an array of rosetta tx identifiers -func TMTxsToRosettaTxsIdentifiers(txs []tmtypes.Tx) []*types.TransactionIdentifier { - converted := make([]*types.TransactionIdentifier, len(txs)) - for i, tx := range txs { - converted[i] = TmTxToRosettaTxsIdentifier(tx) - } - - return converted -} - -// TmTxToRosettaTxsIdentifier converts a tendermint raw transaction into a rosetta tx identifier -func TmTxToRosettaTxsIdentifier(tx tmtypes.Tx) *types.TransactionIdentifier { - return &types.TransactionIdentifier{Hash: fmt.Sprintf("%x", tx.Hash())} -} - -// TMBlockToRosettaBlockIdentifier converts a tendermint result block to a rosetta block identifier -func TMBlockToRosettaBlockIdentifier(block *tmcoretypes.ResultBlock) *types.BlockIdentifier { - return &types.BlockIdentifier{ - Index: block.Block.Height, - Hash: block.Block.Hash().String(), - } -} - -// TmPeersToRosettaPeers converts tendermint peers to rosetta ones -func TmPeersToRosettaPeers(peers []tmcoretypes.Peer) []*types.Peer { - converted := make([]*types.Peer, len(peers)) - - for i, peer := range peers { - converted[i] = &types.Peer{ - PeerID: peer.NodeInfo.Moniker, - Metadata: map[string]interface{}{ - "addr": peer.NodeInfo.ListenAddr, - }, - } - } - - return converted -} - -// TMStatusToRosettaSyncStatus converts a tendermint status to rosetta sync status -func TMStatusToRosettaSyncStatus(status *tmcoretypes.ResultStatus) *types.SyncStatus { - // determine sync status - var stage = StageSynced - if status.SyncInfo.CatchingUp { - stage = StageSyncing - } - - return &types.SyncStatus{ - CurrentIndex: status.SyncInfo.LatestBlockHeight, - TargetIndex: nil, // sync info does not allow us to get target height - Stage: &stage, - } -} - -// TMBlockToRosettaParentBlockIdentifier returns the parent block identifier from the last block -func TMBlockToRosettaParentBlockIdentifier(block *tmcoretypes.ResultBlock) *types.BlockIdentifier { - if block.Block.Height == 1 { - return &types.BlockIdentifier{ - Index: 1, - Hash: fmt.Sprintf("%X", block.BlockID.Hash.Bytes()), - } - } - - return &types.BlockIdentifier{ - Index: block.Block.Height - 1, - Hash: fmt.Sprintf("%X", block.Block.LastBlockID.Hash.Bytes()), - } -} diff --git a/server/rosetta/conv_to_rosetta.go b/server/rosetta/conv_to_rosetta.go deleted file mode 100644 index 09146eed4f3e..000000000000 --- a/server/rosetta/conv_to_rosetta.go +++ /dev/null @@ -1,95 +0,0 @@ -package rosetta - -import ( - "fmt" - "strconv" - "strings" - - "github.com/gogo/protobuf/jsonpb" - - "github.com/coinbase/rosetta-sdk-go/types" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// opsToMsgsAndFees converts rosetta operations to sdk.Msg and fees represented as sdk.Coins -func opsToMsgsAndFees(interfaceRegistry jsonpb.AnyResolver, ops []*types.Operation) ([]sdk.Msg, sdk.Coins, error) { - var feeAmnt []*types.Amount - var newOps []*types.Operation - var msgType string - // find the fee operation and put it aside - for _, op := range ops { - switch op.Type { - case OperationFee: - amount := op.Amount - feeAmnt = append(feeAmnt, amount) - default: - // check if operation matches the one already used - // as, at the moment, we only support operations - // that represent a single cosmos-sdk message - switch { - // if msgType was not set then set it - case msgType == "": - msgType = op.Type - // if msgType does not match op.Type then it means we're trying to send multiple messages in a single tx - case msgType != op.Type: - return nil, nil, fmt.Errorf("only single message operations are supported: %s - %s", msgType, op.Type) - } - // append operation to new ops list - newOps = append(newOps, op) - } - } - // convert all operations, except fee op to sdk.Msgs - msgs, err := opsToMsgs(interfaceRegistry, newOps) - if err != nil { - return nil, nil, err - } - - return msgs, amountsToCoins(feeAmnt), nil -} - -// amountsToCoins converts rosetta amounts to sdk coins -func amountsToCoins(amounts []*types.Amount) sdk.Coins { - var feeCoins sdk.Coins - - for _, amount := range amounts { - absValue := strings.Trim(amount.Value, "-") - value, err := strconv.ParseInt(absValue, 10, 64) - if err != nil { - return nil - } - coin := sdk.NewCoin(amount.Currency.Symbol, sdk.NewInt(value)) - feeCoins = append(feeCoins, coin) - } - - return feeCoins -} - -func opsToMsgs(interfaceRegistry jsonpb.AnyResolver, ops []*types.Operation) ([]sdk.Msg, error) { - var msgs []sdk.Msg - var operationsByType = make(map[string][]*types.Operation) - for _, op := range ops { - operationsByType[op.Type] = append(operationsByType[op.Type], op) - } - - for opName, operations := range operationsByType { - if opName == OperationFee { - continue - } - - msgType, err := interfaceRegistry.Resolve("/" + opName) // Types are registered as /proto-name in the interface registry. - if err != nil { - return nil, err - } - - if rosettaMsg, ok := msgType.(Msg); ok { - m, err := rosettaMsg.FromOperations(operations) - if err != nil { - return nil, err - } - msgs = append(msgs, m) - } - } - - return msgs, nil -} diff --git a/server/rosetta/converter.go b/server/rosetta/converter.go new file mode 100644 index 000000000000..43c9460014fc --- /dev/null +++ b/server/rosetta/converter.go @@ -0,0 +1,804 @@ +package rosetta + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + + auth "github.com/cosmos/cosmos-sdk/x/auth/types" + + "github.com/tendermint/tendermint/crypto" + + "github.com/btcsuite/btcd/btcec" + crgtypes "github.com/tendermint/cosmos-rosetta-gateway/types" + tmcoretypes "github.com/tendermint/tendermint/rpc/core/types" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + + rosettatypes "github.com/coinbase/rosetta-sdk-go/types" + "github.com/gogo/protobuf/proto" + crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + sdkclient "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// Converter is a utility that can be used to convert +// back and forth from rosetta to sdk and tendermint types +// IMPORTANT NOTES: +// - IT SHOULD BE USED ONLY TO DEAL WITH THINGS +// IN A STATELESS WAY! IT SHOULD NEVER INTERACT DIRECTLY +// WITH TENDERMINT RPC AND COSMOS GRPC +// +// - IT SHOULD RETURN cosmos rosetta gateway error types! +type Converter interface { + // ToSDK exposes the methods that convert + // rosetta types to cosmos sdk and tendermint types + ToSDK() ToSDKConverter + // ToRosetta exposes the methods that convert + // sdk and tendermint types to rosetta types + ToRosetta() ToRosettaConverter +} + +// ToRosettaConverter is an interface that exposes +// all the functions used to convert sdk and +// tendermint types to rosetta known types +type ToRosettaConverter interface { + // BlockResponse returns a block response given a result block + BlockResponse(block *tmcoretypes.ResultBlock) crgtypes.BlockResponse + // BeginBlockToTx converts the given begin block hash to rosetta transaction hash + BeginBlockTxHash(blockHash []byte) string + // EndBlockTxHash converts the given endblock hash to rosetta transaction hash + EndBlockTxHash(blockHash []byte) string + // Amounts converts sdk.Coins to rosetta.Amounts + Amounts(ownedCoins []sdk.Coin, availableCoins sdk.Coins) []*rosettatypes.Amount + // Ops converts an sdk.Msg to rosetta operations + Ops(status string, msg sdk.Msg) ([]*rosettatypes.Operation, error) + // OpsAndSigners takes raw transaction bytes and returns rosetta operations and the expected signers + OpsAndSigners(txBytes []byte) (ops []*rosettatypes.Operation, signers []*rosettatypes.AccountIdentifier, err error) + // Meta converts an sdk.Msg to rosetta metadata + Meta(msg sdk.Msg) (meta map[string]interface{}, err error) + // SignerData returns account signing data from a queried any account + SignerData(anyAccount *codectypes.Any) (*SignerData, error) + // SigningComponents returns rosetta's components required to build a signable transaction + SigningComponents(tx authsigning.Tx, metadata *ConstructionMetadata, rosPubKeys []*rosettatypes.PublicKey) (txBytes []byte, payloadsToSign []*rosettatypes.SigningPayload, err error) + // Tx converts a tendermint transaction and tx result if provided to a rosetta tx + Tx(rawTx tmtypes.Tx, txResult *abci.ResponseDeliverTx) (*rosettatypes.Transaction, error) + // TxIdentifiers converts a tendermint tx to transaction identifiers + TxIdentifiers(txs []tmtypes.Tx) []*rosettatypes.TransactionIdentifier + // BalanceOps converts events to balance operations + BalanceOps(status string, events []abci.Event) []*rosettatypes.Operation + // SyncStatus converts a tendermint status to sync status + SyncStatus(status *tmcoretypes.ResultStatus) *rosettatypes.SyncStatus + // Peers converts tendermint peers to rosetta + Peers(peers []tmcoretypes.Peer) []*rosettatypes.Peer +} + +// ToSDKConverter is an interface that exposes +// all the functions used to convert rosetta types +// to tendermint and sdk types +type ToSDKConverter interface { + // UnsignedTx converts rosetta operations to an unsigned cosmos sdk transactions + UnsignedTx(ops []*rosettatypes.Operation) (tx authsigning.Tx, err error) + // SignedTx adds the provided signatures after decoding the unsigned transaction raw bytes + // and returns the signed tx bytes + SignedTx(txBytes []byte, signatures []*rosettatypes.Signature) (signedTxBytes []byte, err error) + // Msg converts metadata to an sdk message + Msg(meta map[string]interface{}, msg sdk.Msg) (err error) + // HashToTxType returns the transaction type (end block, begin block or deliver tx) + // and the real hash to query in order to get information + HashToTxType(hashBytes []byte) (txType TransactionType, realHash []byte) + // PubKey attempts to convert a rosetta public key to cosmos sdk one + PubKey(pk *rosettatypes.PublicKey) (cryptotypes.PubKey, error) +} + +type converter struct { + newTxBuilder func() sdkclient.TxBuilder + txBuilderFromTx func(tx sdk.Tx) (sdkclient.TxBuilder, error) + txDecode sdk.TxDecoder + txEncode sdk.TxEncoder + bytesToSign func(tx authsigning.Tx, signerData authsigning.SignerData) (b []byte, err error) + ir codectypes.InterfaceRegistry + cdc *codec.ProtoCodec +} + +func NewConverter(cdc *codec.ProtoCodec, ir codectypes.InterfaceRegistry, cfg sdkclient.TxConfig) Converter { + return converter{ + newTxBuilder: cfg.NewTxBuilder, + txBuilderFromTx: cfg.WrapTxBuilder, + txDecode: cfg.TxDecoder(), + txEncode: cfg.TxEncoder(), + bytesToSign: func(tx authsigning.Tx, signerData authsigning.SignerData) (b []byte, err error) { + bytesToSign, err := cfg.SignModeHandler().GetSignBytes(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, signerData, tx) + if err != nil { + return nil, err + } + + return crypto.Sha256(bytesToSign), nil + }, + ir: ir, + cdc: cdc, + } +} + +func (c converter) ToSDK() ToSDKConverter { + return c +} + +func (c converter) ToRosetta() ToRosettaConverter { + return c +} + +// OpsToUnsignedTx returns all the sdk.Msgs given the operations +func (c converter) UnsignedTx(ops []*rosettatypes.Operation) (tx authsigning.Tx, err error) { + builder := c.newTxBuilder() + + var msgs []sdk.Msg + + for i := 0; i < len(ops); i++ { + op := ops[i] + + protoMessage, err := c.ir.Resolve("/" + op.Type) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "operation not found: "+op.Type) + } + + msg, ok := protoMessage.(sdk.Msg) + if !ok { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "operation is not a valid supported sdk.Msg: "+op.Type) + } + + err = c.Msg(op.Metadata, msg) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + // verify message correctness + if err = msg.ValidateBasic(); err != nil { + return nil, crgerrs.WrapError( + crgerrs.ErrBadArgument, + fmt.Sprintf("validation of operation at index %d failed: %s", op.OperationIdentifier.Index, err), + ) + } + signers := msg.GetSigners() + // check if there are enough signers + if len(signers) == 0 { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, fmt.Sprintf("operation at index %d got no signers", op.OperationIdentifier.Index)) + } + // append the msg + msgs = append(msgs, msg) + // if there's only one signer then simply continue + if len(signers) == 1 { + continue + } + // after we have got the msg, we need to verify if the message has multiple signers + // if it has got multiple signers, then we need to fetch all the related operations + // which involve the other signers of the msg, we expect to find them in order + // so if the msg is named "v1.test.Send" and it expects 3 signers, the next 3 operations + // must be with the same name "v1.test.Send" and contain the other signers + // then we can just skip their processing + for j := 0; j < len(signers)-1; j++ { + skipOp := ops[i+j] // get the next index + // verify that the operation is equal to the new one + if skipOp.Type != op.Type { + return nil, crgerrs.WrapError( + crgerrs.ErrBadArgument, + fmt.Sprintf("operation at index %d should have had type %s got: %s", i+j, op.Type, skipOp.Type), + ) + } + + if !reflect.DeepEqual(op.Metadata, skipOp.Metadata) { + return nil, crgerrs.WrapError( + crgerrs.ErrBadArgument, + fmt.Sprintf("operation at index %d should have had metadata equal to %#v, got: %#v", i+j, op.Metadata, skipOp.Metadata)) + } + + i++ // increase so we skip it + } + } + + if err := builder.SetMsgs(msgs...); err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) + } + + return builder.GetTx(), nil + +} + +// Msg unmarshals the rosetta metadata to the given sdk.Msg +func (c converter) Msg(meta map[string]interface{}, msg sdk.Msg) error { + metaBytes, err := json.Marshal(meta) + if err != nil { + return err + } + return c.cdc.UnmarshalJSON(metaBytes, msg) +} + +func (c converter) Meta(msg sdk.Msg) (meta map[string]interface{}, err error) { + b, err := c.cdc.MarshalJSON(msg) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + err = json.Unmarshal(b, &meta) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + return +} + +// Ops will create an operation for each msg signer +// with the message proto name as type, and the raw fields +// as metadata +func (c converter) Ops(status string, msg sdk.Msg) ([]*rosettatypes.Operation, error) { + opName := proto.MessageName(msg) + // in case proto does not recognize the message name + // then we should try to cast it to service msg, to + // check if it was wrapped or not, in case the cast + // from sdk.ServiceMsg to sdk.Msg fails, then a + // codec error is returned + if opName == "" { + unwrappedMsg, ok := msg.(sdk.ServiceMsg) + if !ok { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, fmt.Sprintf("unrecognized message type: %T", msg)) + } + + msg, ok = unwrappedMsg.Request.(sdk.Msg) + if !ok { + return nil, crgerrs.WrapError( + crgerrs.ErrCodec, + fmt.Sprintf("unable to cast %T to sdk.Msg, method: %s", unwrappedMsg.Request, unwrappedMsg.MethodName), + ) + } + + opName = proto.MessageName(msg) + if opName == "" { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, fmt.Sprintf("unrecognized message type: %T", msg)) + } + } + + meta, err := c.Meta(msg) + if err != nil { + return nil, err + } + + ops := make([]*rosettatypes.Operation, len(msg.GetSigners())) + for i, signer := range msg.GetSigners() { + op := &rosettatypes.Operation{ + Type: opName, + Status: status, + Account: &rosettatypes.AccountIdentifier{Address: signer.String()}, + Metadata: meta, + } + + ops[i] = op + } + + return ops, nil +} + +// Tx converts a tendermint raw transaction and its result (if provided) to a rosetta transaction +func (c converter) Tx(rawTx tmtypes.Tx, txResult *abci.ResponseDeliverTx) (*rosettatypes.Transaction, error) { + // decode tx + tx, err := c.txDecode(rawTx) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + // get initial status, as per sdk design, if one msg fails + // the whole TX will be considered failing, so we can't have + // 1 msg being success and 1 msg being reverted + status := StatusTxSuccess + switch txResult { + // if nil, we're probably checking an unconfirmed tx + // or trying to build a new transaction, so status + // is not put inside + case nil: + status = "" + // set the status + default: + if txResult.Code != abci.CodeTypeOK { + status = StatusTxReverted + } + } + // get operations from msgs + msgs := tx.GetMsgs() + + var rawTxOps []*rosettatypes.Operation + for _, msg := range msgs { + ops, err := c.Ops(status, msg) + if err != nil { + return nil, err + } + rawTxOps = append(rawTxOps, ops...) + } + + // now get balance events from response deliver tx + var balanceOps []*rosettatypes.Operation + // tx result might be nil, in case we're querying an unconfirmed tx from the mempool + if txResult != nil { + balanceOps = c.BalanceOps(status, txResult.Events) + } + + // now normalize indexes + totalOps := AddOperationIndexes(rawTxOps, balanceOps) + + return &rosettatypes.Transaction{ + TransactionIdentifier: &rosettatypes.TransactionIdentifier{Hash: fmt.Sprintf("%X", rawTx.Hash())}, + Operations: totalOps, + }, nil +} + +func (c converter) BalanceOps(status string, events []abci.Event) []*rosettatypes.Operation { + var ops []*rosettatypes.Operation + + for _, e := range events { + balanceOps, ok := sdkEventToBalanceOperations(status, e) + if !ok { + continue + } + ops = append(ops, balanceOps...) + } + + return ops +} + +// sdkEventToBalanceOperations converts an event to a rosetta balance operation +// it will panic if the event is malformed because it might mean the sdk spec +// has changed and rosetta needs to reflect those changes too. +// The balance operations are multiple, one for each denom. +func sdkEventToBalanceOperations(status string, event abci.Event) (operations []*rosettatypes.Operation, isBalanceEvent bool) { + + var ( + accountIdentifier string + coinChange sdk.Coins + isSub bool + ) + + switch event.Type { + default: + return nil, false + case banktypes.EventTypeCoinSpent: + spender, err := sdk.AccAddressFromBech32((string)(event.Attributes[0].Value)) + if err != nil { + panic(err) + } + coins, err := sdk.ParseCoinsNormalized((string)(event.Attributes[1].Value)) + if err != nil { + panic(err) + } + + isSub = true + coinChange = coins + accountIdentifier = spender.String() + + case banktypes.EventTypeCoinReceived: + receiver, err := sdk.AccAddressFromBech32((string)(event.Attributes[0].Value)) + if err != nil { + panic(err) + } + coins, err := sdk.ParseCoinsNormalized((string)(event.Attributes[1].Value)) + if err != nil { + panic(err) + } + + isSub = false + coinChange = coins + accountIdentifier = receiver.String() + + // rosetta does not have the concept of burning coins, so we need to mock + // the burn as a send to an address that cannot be resolved to anything + case banktypes.EventTypeCoinBurn: + coins, err := sdk.ParseCoinsNormalized((string)(event.Attributes[1].Value)) + if err != nil { + panic(err) + } + + coinChange = coins + accountIdentifier = BurnerAddressIdentifier + } + + operations = make([]*rosettatypes.Operation, len(coinChange)) + + for i, coin := range coinChange { + + value := coin.Amount.String() + // in case the event is a subtract balance one the rewrite value with + // the negative coin identifier + if isSub { + value = "-" + value + } + + op := &rosettatypes.Operation{ + Type: event.Type, + Status: status, + Account: &rosettatypes.AccountIdentifier{Address: accountIdentifier}, + Amount: &rosettatypes.Amount{ + Value: value, + Currency: &rosettatypes.Currency{ + Symbol: coin.Denom, + Decimals: 0, + }, + }, + } + + operations[i] = op + } + return operations, true +} + +// Amounts converts []sdk.Coin to rosetta amounts +func (c converter) Amounts(ownedCoins []sdk.Coin, availableCoins sdk.Coins) []*rosettatypes.Amount { + amounts := make([]*rosettatypes.Amount, len(availableCoins)) + ownedCoinsMap := make(map[string]sdk.Int, len(availableCoins)) + + for _, ownedCoin := range ownedCoins { + ownedCoinsMap[ownedCoin.Denom] = ownedCoin.Amount + } + + for i, coin := range availableCoins { + value, owned := ownedCoinsMap[coin.Denom] + if !owned { + amounts[i] = &rosettatypes.Amount{ + Value: sdk.NewInt(0).String(), + Currency: &rosettatypes.Currency{ + Symbol: coin.Denom, + }, + } + continue + } + amounts[i] = &rosettatypes.Amount{ + Value: value.String(), + Currency: &rosettatypes.Currency{ + Symbol: coin.Denom, + }, + } + } + + return amounts +} + +// AddOperationIndexes adds the indexes to operations adhering to specific rules: +// operations related to messages will be always before than the balance ones +func AddOperationIndexes(msgOps []*rosettatypes.Operation, balanceOps []*rosettatypes.Operation) (finalOps []*rosettatypes.Operation) { + lenMsgOps := len(msgOps) + lenBalanceOps := len(balanceOps) + finalOps = make([]*rosettatypes.Operation, 0, lenMsgOps+lenBalanceOps) + + var currentIndex int64 + // add indexes to msg ops + for _, op := range msgOps { + op.OperationIdentifier = &rosettatypes.OperationIdentifier{ + Index: currentIndex, + } + + finalOps = append(finalOps, op) + currentIndex++ + } + + // add indexes to balance ops + for _, op := range balanceOps { + op.OperationIdentifier = &rosettatypes.OperationIdentifier{ + Index: currentIndex, + } + + finalOps = append(finalOps, op) + currentIndex++ + } + + return finalOps +} + +// EndBlockTxHash produces a mock endblock hash that rosetta can query +// for endblock operations, it also serves the purpose of representing +// part of the state changes happening at endblock level (balance ones) +func (c converter) EndBlockTxHash(hash []byte) string { + final := append([]byte{EndBlockHashStart}, hash...) + return fmt.Sprintf("%X", final) +} + +// BeginBlockTxHash produces a mock beginblock hash that rosetta can query +// for beginblock operations, it also serves the purpose of representing +// part of the state changes happening at beginblock level (balance ones) +func (c converter) BeginBlockTxHash(hash []byte) string { + final := append([]byte{BeginBlockHashStart}, hash...) + return fmt.Sprintf("%X", final) +} + +// HashToTxType takes the provided hash bytes from rosetta and discerns if they are +// a deliver tx type or endblock/begin block hash, returning the real hash afterwards +func (c converter) HashToTxType(hashBytes []byte) (txType TransactionType, realHash []byte) { + switch len(hashBytes) { + case DeliverTxSize: + return DeliverTxTx, hashBytes + + case BeginEndBlockTxSize: + switch hashBytes[0] { + case BeginBlockHashStart: + return BeginBlockTx, hashBytes[1:] + case EndBlockHashStart: + return EndBlockTx, hashBytes[1:] + default: + return UnrecognizedTx, nil + } + + default: + return UnrecognizedTx, nil + } +} + +// StatusToSyncStatus converts a tendermint status to rosetta sync status +func (c converter) SyncStatus(status *tmcoretypes.ResultStatus) *rosettatypes.SyncStatus { + // determine sync status + var stage = StatusPeerSynced + if status.SyncInfo.CatchingUp { + stage = StatusPeerSyncing + } + + return &rosettatypes.SyncStatus{ + CurrentIndex: status.SyncInfo.LatestBlockHeight, + TargetIndex: nil, // sync info does not allow us to get target height + Stage: &stage, + } +} + +// TxIdentifiers converts a tendermint raw transactions into an array of rosetta tx identifiers +func (c converter) TxIdentifiers(txs []tmtypes.Tx) []*rosettatypes.TransactionIdentifier { + converted := make([]*rosettatypes.TransactionIdentifier, len(txs)) + for i, tx := range txs { + converted[i] = &rosettatypes.TransactionIdentifier{Hash: fmt.Sprintf("%X", tx.Hash())} + } + + return converted +} + +// tmResultBlockToRosettaBlockResponse converts a tendermint result block to block response +func (c converter) BlockResponse(block *tmcoretypes.ResultBlock) crgtypes.BlockResponse { + var parentBlock *rosettatypes.BlockIdentifier + + switch block.Block.Height { + case 1: + parentBlock = &rosettatypes.BlockIdentifier{ + Index: 1, + Hash: fmt.Sprintf("%X", block.BlockID.Hash.Bytes()), + } + default: + parentBlock = &rosettatypes.BlockIdentifier{ + Index: block.Block.Height - 1, + Hash: fmt.Sprintf("%X", block.Block.LastBlockID.Hash.Bytes()), + } + } + return crgtypes.BlockResponse{ + Block: &rosettatypes.BlockIdentifier{ + Index: block.Block.Height, + Hash: block.Block.Hash().String(), + }, + ParentBlock: parentBlock, + MillisecondTimestamp: timeToMilliseconds(block.Block.Time), + TxCount: int64(len(block.Block.Txs)), + } +} + +// Peers converts tm peers to rosetta peers +func (c converter) Peers(peers []tmcoretypes.Peer) []*rosettatypes.Peer { + converted := make([]*rosettatypes.Peer, len(peers)) + + for i, peer := range peers { + converted[i] = &rosettatypes.Peer{ + PeerID: peer.NodeInfo.Moniker, + Metadata: map[string]interface{}{ + "addr": peer.NodeInfo.ListenAddr, + }, + } + } + + return converted +} + +// OpsAndSigners takes transactions bytes and returns the operation, is signed is true it will return +// the account identifiers which have signed the transaction +func (c converter) OpsAndSigners(txBytes []byte) (ops []*rosettatypes.Operation, signers []*rosettatypes.AccountIdentifier, err error) { + + rosTx, err := c.ToRosetta().Tx(txBytes, nil) + if err != nil { + return nil, nil, err + } + ops = rosTx.Operations + + // get the signers + sdkTx, err := c.txDecode(txBytes) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + txBuilder, err := c.txBuilderFromTx(sdkTx) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + for _, signer := range txBuilder.GetTx().GetSigners() { + signers = append(signers, &rosettatypes.AccountIdentifier{ + Address: signer.String(), + }) + } + + return +} + +func (c converter) SignedTx(txBytes []byte, signatures []*rosettatypes.Signature) (signedTxBytes []byte, err error) { + rawTx, err := c.txDecode(txBytes) + if err != nil { + return nil, err + } + + txBuilder, err := c.txBuilderFromTx(rawTx) + if err != nil { + return nil, err + } + + notSignedSigs, err := txBuilder.GetTx().GetSignaturesV2() // + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + if len(notSignedSigs) != len(signatures) { + return nil, crgerrs.WrapError( + crgerrs.ErrInvalidTransaction, + fmt.Sprintf("expected transaction to have signers data matching the provided signatures: %d <-> %d", len(notSignedSigs), len(signatures))) + } + + signedSigs := make([]signing.SignatureV2, len(notSignedSigs)) + for i, signature := range signatures { + // TODO(fdymylja): here we should check that the public key matches... + signedSigs[i] = signing.SignatureV2{ + PubKey: notSignedSigs[i].PubKey, + Data: &signing.SingleSignatureData{ + SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, + Signature: signature.Bytes, + }, + Sequence: notSignedSigs[i].Sequence, + } + } + + if err = txBuilder.SetSignatures(signedSigs...); err != nil { + return nil, err + } + + txBytes, err = c.txEncode(txBuilder.GetTx()) + if err != nil { + return nil, err + } + + return txBytes, nil +} + +func (c converter) PubKey(pubKey *rosettatypes.PublicKey) (cryptotypes.PubKey, error) { + if pubKey.CurveType != "secp256k1" { + return nil, crgerrs.WrapError(crgerrs.ErrUnsupportedCurve, "only secp256k1 supported") + } + + cmp, err := btcec.ParsePubKey(pubKey.Bytes, btcec.S256()) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) + } + + compressedPublicKey := make([]byte, secp256k1.PubKeySize) + copy(compressedPublicKey, cmp.SerializeCompressed()) + + pk := &secp256k1.PubKey{Key: compressedPublicKey} + + return pk, nil +} + +// SigningComponents takes a sdk tx and construction metadata and returns signable components +func (c converter) SigningComponents(tx authsigning.Tx, metadata *ConstructionMetadata, rosPubKeys []*rosettatypes.PublicKey) (txBytes []byte, payloadsToSign []*rosettatypes.SigningPayload, err error) { + + // verify metadata correctness + feeAmount, err := sdk.ParseCoinsNormalized(metadata.GasPrice) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrBadArgument, err.Error()) + } + + signers := tx.GetSigners() + // assert the signers data provided in options are the same as the expected signing accounts + // and that the number of rosetta provided public keys equals the one of the signers + if len(metadata.SignersData) != len(signers) || len(signers) != len(rosPubKeys) { + return nil, nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "signers data and account identifiers mismatch") + } + + // add transaction metadata + builder, err := c.txBuilderFromTx(tx) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + builder.SetFeeAmount(feeAmount) + builder.SetGasLimit(metadata.GasLimit) + builder.SetMemo(metadata.Memo) + + // build signatures + partialSignatures := make([]signing.SignatureV2, len(signers)) + payloadsToSign = make([]*rosettatypes.SigningPayload, len(signers)) + + // pub key ordering matters, in a future release this check might be relaxed + for i, signer := range signers { + // assert that the provided public keys are correctly ordered + // by checking if the signer at index i matches the pubkey at index + pubKey, err := c.ToSDK().PubKey(rosPubKeys[0]) + if err != nil { + return nil, nil, err + } + if !bytes.Equal(pubKey.Address().Bytes(), signer.Bytes()) { + return nil, nil, crgerrs.WrapError( + crgerrs.ErrBadArgument, + fmt.Sprintf("public key at index %d does not match the expected transaction signer: %X <-> %X", i, rosPubKeys[i].Bytes, signer.Bytes()), + ) + } + + // set the signer data + signerData := authsigning.SignerData{ + ChainID: metadata.ChainID, + AccountNumber: metadata.SignersData[i].AccountNumber, + Sequence: metadata.SignersData[i].Sequence, + } + + // get signature bytes + signBytes, err := c.bytesToSign(tx, signerData) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrUnknown, fmt.Sprintf("unable to sign tx: %s", err.Error())) + } + + // set payload + payloadsToSign[i] = &rosettatypes.SigningPayload{ + AccountIdentifier: &rosettatypes.AccountIdentifier{Address: signer.String()}, + Bytes: signBytes, + SignatureType: rosettatypes.Ecdsa, + } + + // set partial signature + partialSignatures[i] = signing.SignatureV2{ + PubKey: pubKey, + Data: &signing.SingleSignatureData{}, // needs to be set to empty otherwise the codec will cry + Sequence: metadata.SignersData[i].Sequence, + } + + } + + // now we set the partial signatures in the tx + // because we will need to decode the sequence + // information of each account in a stateless way + err = builder.SetSignatures(partialSignatures...) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + // finally encode the tx + txBytes, err = c.txEncode(builder.GetTx()) + if err != nil { + return nil, nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + return txBytes, payloadsToSign, nil +} + +// SignerData converts the given any account to signer data +func (c converter) SignerData(anyAccount *codectypes.Any) (*SignerData, error) { + var acc auth.AccountI + err := c.ir.UnpackAny(anyAccount, &acc) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) + } + + return &SignerData{ + AccountNumber: acc.GetAccountNumber(), + Sequence: acc.GetSequence(), + }, nil +} diff --git a/server/rosetta/converter_test.go b/server/rosetta/converter_test.go new file mode 100644 index 000000000000..3ac0eedf007f --- /dev/null +++ b/server/rosetta/converter_test.go @@ -0,0 +1,355 @@ +package rosetta_test + +import ( + "encoding/hex" + "encoding/json" + "testing" + + "github.com/cosmos/cosmos-sdk/server/rosetta" + + abci "github.com/tendermint/tendermint/abci/types" + + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + + rosettatypes "github.com/coinbase/rosetta-sdk-go/types" + "github.com/stretchr/testify/suite" + crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + bank "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +type ConverterTestSuite struct { + suite.Suite + + c rosetta.Converter + unsignedTxBytes []byte + unsignedTx authsigning.Tx + + util struct { + ir codectypes.InterfaceRegistry + cdc *codec.ProtoCodec + txConf client.TxConfig + } +} + +func (s *ConverterTestSuite) SetupTest() { + // create an unsigned tx + const unsignedTxHex = "0a8e010a8b010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e64126b0a2d636f736d6f733134376b6c68377468356a6b6a793361616a736a3272717668747668396d666465333777713567122d636f736d6f73316d6e7670386c786b616679346c787777617175356561653764787630647a36687767797436331a0b0a057374616b651202313612600a4c0a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a21034c92046950c876f4a5cb6c7797d6eeb9ef80d67ced4d45fb62b1e859240ba9ad12020a0012100a0a0a057374616b651201311090a10f1a00" + unsignedTxBytes, err := hex.DecodeString(unsignedTxHex) + s.Require().NoError(err) + s.unsignedTxBytes = unsignedTxBytes + // instantiate converter + cdc, ir := rosetta.MakeCodec() + txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes) + s.c = rosetta.NewConverter(cdc, ir, txConfig) + // add utils + s.util = struct { + ir codectypes.InterfaceRegistry + cdc *codec.ProtoCodec + txConf client.TxConfig + }{ir: ir, cdc: cdc, txConf: txConfig} + // add authsigning tx + sdkTx, err := txConfig.TxDecoder()(unsignedTxBytes) + s.Require().NoError(err) + builder, err := txConfig.WrapTxBuilder(sdkTx) + s.Require().NoError(err) + + s.unsignedTx = builder.GetTx() +} + +func (s *ConverterTestSuite) TestFromRosettaOpsToTxSuccess() { + addr1 := sdk.AccAddress("address1").String() + addr2 := sdk.AccAddress("address2").String() + + msg1 := &bank.MsgSend{ + FromAddress: addr1, + ToAddress: addr2, + Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 10)), + } + + msg2 := &bank.MsgSend{ + FromAddress: addr2, + ToAddress: addr1, + Amount: sdk.NewCoins(sdk.NewInt64Coin("utxo", 10)), + } + + ops, err := s.c.ToRosetta().Ops("", msg1) + s.Require().NoError(err) + + ops2, err := s.c.ToRosetta().Ops("", msg2) + s.Require().NoError(err) + + ops = append(ops, ops2...) + + tx, err := s.c.ToSDK().UnsignedTx(ops) + s.Require().NoError(err) + + getMsgs := tx.GetMsgs() + + s.Require().Equal(2, len(getMsgs)) + + s.Require().Equal(getMsgs[0], msg1) + s.Require().Equal(getMsgs[1], msg2) + +} + +func (s *ConverterTestSuite) TestFromRosettaOpsToTxErrors() { + s.Run("unrecognized op", func() { + op := &rosettatypes.Operation{ + Type: "non-existent", + } + + _, err := s.c.ToSDK().UnsignedTx([]*rosettatypes.Operation{op}) + + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + }) + + s.Run("codec type but not sdk.Msg", func() { + op := &rosettatypes.Operation{ + Type: "cosmos.crypto.ed25519.PubKey", + } + + _, err := s.c.ToSDK().UnsignedTx([]*rosettatypes.Operation{op}) + + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + + }) + +} + +func (s *ConverterTestSuite) TestMsgToMetaMetaToMsg() { + msg := &bank.MsgSend{ + FromAddress: "addr1", + ToAddress: "addr2", + Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 10)), + } + + msg.Route() + + meta, err := s.c.ToRosetta().Meta(msg) + s.Require().NoError(err) + + copyMsg := new(bank.MsgSend) + + err = s.c.ToSDK().Msg(meta, copyMsg) + s.Require().NoError(err) + + s.Require().Equal(msg, copyMsg) +} + +func (s *ConverterTestSuite) TestSignedTx() { + + s.Run("success", func() { + const payloadsJSON = `[{"hex_bytes":"82ccce81a3e4a7272249f0e25c3037a316ee2acce76eb0c25db00ef6634a4d57303b2420edfdb4c9a635ad8851fe5c7a9379b7bc2baadc7d74f7e76ac97459b5","signing_payload":{"address":"cosmos147klh7th5jkjy3aajsj2rqvhtvh9mfde37wq5g","hex_bytes":"ed574d84b095250280de38bf8c254e4a1f8755e5bd300b1f6ca2671688136ecc","account_identifier":{"address":"cosmos147klh7th5jkjy3aajsj2rqvhtvh9mfde37wq5g"},"signature_type":"ecdsa"},"public_key":{"hex_bytes":"034c92046950c876f4a5cb6c7797d6eeb9ef80d67ced4d45fb62b1e859240ba9ad","curve_type":"secp256k1"},"signature_type":"ecdsa"}]` + const expectedSignedTxHex = "0a8e010a8b010a1c2f636f736d6f732e62616e6b2e763162657461312e4d736753656e64126b0a2d636f736d6f733134376b6c68377468356a6b6a793361616a736a3272717668747668396d666465333777713567122d636f736d6f73316d6e7670386c786b616679346c787777617175356561653764787630647a36687767797436331a0b0a057374616b651202313612620a4e0a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a21034c92046950c876f4a5cb6c7797d6eeb9ef80d67ced4d45fb62b1e859240ba9ad12040a02087f12100a0a0a057374616b651201311090a10f1a4082ccce81a3e4a7272249f0e25c3037a316ee2acce76eb0c25db00ef6634a4d57303b2420edfdb4c9a635ad8851fe5c7a9379b7bc2baadc7d74f7e76ac97459b5" + + var payloads []*rosettatypes.Signature + s.Require().NoError(json.Unmarshal([]byte(payloadsJSON), &payloads)) + + signedTx, err := s.c.ToSDK().SignedTx(s.unsignedTxBytes, payloads) + s.Require().NoError(err) + + signedTxHex := hex.EncodeToString(signedTx) + + s.Require().Equal(signedTxHex, expectedSignedTxHex) + }) + + s.Run("signers data and signing payloads mismatch", func() { + _, err := s.c.ToSDK().SignedTx(s.unsignedTxBytes, nil) + s.Require().ErrorIs(err, crgerrs.ErrInvalidTransaction) + }) +} + +func (s *ConverterTestSuite) TestOpsAndSigners() { + s.Run("success", func() { + addr1 := sdk.AccAddress("address1").String() + addr2 := sdk.AccAddress("address2").String() + + msg := &bank.MsgSend{ + FromAddress: addr1, + ToAddress: addr2, + Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 10)), + } + + builder := s.util.txConf.NewTxBuilder() + s.Require().NoError(builder.SetMsgs(msg)) + + sdkTx := builder.GetTx() + txBytes, err := s.util.txConf.TxEncoder()(sdkTx) + s.Require().NoError(err) + + ops, signers, err := s.c.ToRosetta().OpsAndSigners(txBytes) + s.Require().NoError(err) + + s.Require().Equal(len(ops), len(sdkTx.GetMsgs())*len(sdkTx.GetSigners()), "operation number mismatch") + + s.Require().Equal(len(signers), len(sdkTx.GetSigners()), "signers number mismatch") + }) +} + +func (s *ConverterTestSuite) TestBeginEndBlockAndHashToTxType() { + const deliverTxHex = "5229A67AA008B5C5F1A0AEA77D4DEBE146297A30AAEF01777AF10FAD62DD36AB" + + deliverTxBytes, err := hex.DecodeString(deliverTxHex) + s.Require().NoError(err) + + endBlockTxHex := s.c.ToRosetta().EndBlockTxHash(deliverTxBytes) + beginBlockTxHex := s.c.ToRosetta().BeginBlockTxHash(deliverTxBytes) + + txType, hash := s.c.ToSDK().HashToTxType(deliverTxBytes) + + s.Require().Equal(rosetta.DeliverTxTx, txType) + s.Require().Equal(deliverTxBytes, hash, "deliver tx hash should not change") + + endBlockTxBytes, err := hex.DecodeString(endBlockTxHex) + s.Require().NoError(err) + + txType, hash = s.c.ToSDK().HashToTxType(endBlockTxBytes) + + s.Require().Equal(rosetta.EndBlockTx, txType) + s.Require().Equal(deliverTxBytes, hash, "end block tx hash should be equal to a block hash") + + beginBlockTxBytes, err := hex.DecodeString(beginBlockTxHex) + s.Require().NoError(err) + + txType, hash = s.c.ToSDK().HashToTxType(beginBlockTxBytes) + + s.Require().Equal(rosetta.BeginBlockTx, txType) + s.Require().Equal(deliverTxBytes, hash, "begin block tx hash should be equal to a block hash") + + txType, hash = s.c.ToSDK().HashToTxType([]byte("invalid")) + + s.Require().Equal(rosetta.UnrecognizedTx, txType) + s.Require().Nil(hash) + + txType, hash = s.c.ToSDK().HashToTxType(append([]byte{0x3}, deliverTxBytes...)) + s.Require().Equal(rosetta.UnrecognizedTx, txType) + s.Require().Nil(hash) +} + +func (s *ConverterTestSuite) TestSigningComponents() { + s.Run("invalid metadata coins", func() { + _, _, err := s.c.ToRosetta().SigningComponents(nil, &rosetta.ConstructionMetadata{GasPrice: "invalid"}, nil) + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + }) + + s.Run("length signers data does not match signers", func() { + _, _, err := s.c.ToRosetta().SigningComponents(s.unsignedTx, &rosetta.ConstructionMetadata{GasPrice: "10stake"}, nil) + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + }) + + s.Run("length pub keys does not match signers", func() { + _, _, err := s.c.ToRosetta().SigningComponents( + s.unsignedTx, + &rosetta.ConstructionMetadata{GasPrice: "10stake", SignersData: []*rosetta.SignerData{ + { + AccountNumber: 0, + Sequence: 0, + }, + }}, + nil) + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + }) + + s.Run("ros pub key is valid but not the one we expect", func() { + validButUnexpected, err := hex.DecodeString("030da9096a40eb1d6c25f1e26e9cbf8941fc84b8f4dc509c8df5e62a29ab8f2415") + s.Require().NoError(err) + + _, _, err = s.c.ToRosetta().SigningComponents( + s.unsignedTx, + &rosetta.ConstructionMetadata{GasPrice: "10stake", SignersData: []*rosetta.SignerData{ + { + AccountNumber: 0, + Sequence: 0, + }, + }}, + []*rosettatypes.PublicKey{ + { + Bytes: validButUnexpected, + CurveType: rosettatypes.Secp256k1, + }, + }) + s.Require().ErrorIs(err, crgerrs.ErrBadArgument) + }) + + s.Run("success", func() { + expectedPubKey, err := hex.DecodeString("034c92046950c876f4a5cb6c7797d6eeb9ef80d67ced4d45fb62b1e859240ba9ad") + s.Require().NoError(err) + + _, _, err = s.c.ToRosetta().SigningComponents( + s.unsignedTx, + &rosetta.ConstructionMetadata{GasPrice: "10stake", SignersData: []*rosetta.SignerData{ + { + AccountNumber: 0, + Sequence: 0, + }, + }}, + []*rosettatypes.PublicKey{ + { + Bytes: expectedPubKey, + CurveType: rosettatypes.Secp256k1, + }, + }) + s.Require().NoError(err) + }) + +} + +func (s *ConverterTestSuite) TestBalanceOps() { + s.Run("not a balance op", func() { + notBalanceOp := abci.Event{ + Type: "not-a-balance-op", + } + + ops := s.c.ToRosetta().BalanceOps("", []abci.Event{notBalanceOp}) + s.Len(ops, 0, "expected no balance ops") + }) + + s.Run("multiple balance ops from 2 multicoins event", func() { + subBalanceOp := bank.NewCoinSpentEvent( + sdk.AccAddress("test"), + sdk.NewCoins(sdk.NewInt64Coin("test", 10), sdk.NewInt64Coin("utxo", 10)), + ) + + addBalanceOp := bank.NewCoinReceivedEvent( + sdk.AccAddress("test"), + sdk.NewCoins(sdk.NewInt64Coin("test", 10), sdk.NewInt64Coin("utxo", 10)), + ) + + ops := s.c.ToRosetta().BalanceOps("", []abci.Event{(abci.Event)(subBalanceOp), (abci.Event)(addBalanceOp)}) + s.Len(ops, 4) + }) + + s.Run("spec broken", func() { + s.Require().Panics(func() { + specBrokenSub := abci.Event{ + Type: bank.EventTypeCoinSpent, + } + _ = s.c.ToRosetta().BalanceOps("", []abci.Event{specBrokenSub}) + }) + + s.Require().Panics(func() { + specBrokenSub := abci.Event{ + Type: bank.EventTypeCoinBurn, + } + _ = s.c.ToRosetta().BalanceOps("", []abci.Event{specBrokenSub}) + }) + + s.Require().Panics(func() { + specBrokenSub := abci.Event{ + Type: bank.EventTypeCoinReceived, + } + _ = s.c.ToRosetta().BalanceOps("", []abci.Event{specBrokenSub}) + }) + }) +} + +func TestConverterTestSuite(t *testing.T) { + suite.Run(t, new(ConverterTestSuite)) +} diff --git a/server/rosetta/types.go b/server/rosetta/types.go index 626e7470ab91..0d1eada89272 100644 --- a/server/rosetta/types.go +++ b/server/rosetta/types.go @@ -1,41 +1,104 @@ package rosetta import ( - "github.com/coinbase/rosetta-sdk-go/types" - - sdk "github.com/cosmos/cosmos-sdk/types" + "crypto/sha256" ) // statuses const ( - StatusSuccess = "Success" - StatusReverted = "Reverted" - StageSynced = "synced" - StageSyncing = "syncing" + StatusTxSuccess = "Success" + StatusTxReverted = "Reverted" + StatusPeerSynced = "synced" + StatusPeerSyncing = "syncing" ) -// misc +// In rosetta all state transitions must be represented as transactions +// since in tendermint begin block and end block are state transitions +// which are not represented as transactions we mock only the balance changes +// happening at those levels as transactions. (check BeginBlockTxHash for more info) const ( - Log = "log" + DeliverTxSize = sha256.Size + BeginEndBlockTxSize = DeliverTxSize + 1 + EndBlockHashStart = 0x0 + BeginBlockHashStart = 0x1 ) -// operations const ( - OperationFee = "fee" + // BurnerAddressIdentifier mocks the account identifier of a burner address + // all coins burned in the sdk will be sent to this identifier, which per sdk.AccAddress + // design we will never be able to query (as of now). + // Rosetta does not understand supply contraction. + BurnerAddressIdentifier = "burner" ) -// options +// TransactionType is used to distinguish if a rosetta provided hash +// represents endblock, beginblock or deliver tx +type TransactionType int + const ( - OptionAccountNumber = "account_number" - OptionAddress = "address" - OptionChainID = "chain_id" - OptionSequence = "sequence" - OptionMemo = "memo" - OptionGas = "gas" + UnrecognizedTx TransactionType = iota + BeginBlockTx + EndBlockTx + DeliverTxTx ) -type Msg interface { - sdk.Msg - ToOperations(withStatus, hasError bool) []*types.Operation - FromOperations(ops []*types.Operation) (sdk.Msg, error) +// metadata options + +// misc +const ( + Log = "log" +) + +// ConstructionPreprocessMetadata is used to represent +// the metadata rosetta can provide during preprocess options +type ConstructionPreprocessMetadata struct { + Memo string `json:"memo"` + GasLimit uint64 `json:"gas_limit"` + GasPrice string `json:"gas_price"` +} + +func (c *ConstructionPreprocessMetadata) FromMetadata(meta map[string]interface{}) error { + return unmarshalMetadata(meta, c) +} + +// PreprocessOperationsOptionsResponse is the structured metadata options returned by the preprocess operations endpoint +type PreprocessOperationsOptionsResponse struct { + ExpectedSigners []string `json:"expected_signers"` + Memo string `json:"memo"` + GasLimit uint64 `json:"gas_limit"` + GasPrice string `json:"gas_price"` +} + +func (c PreprocessOperationsOptionsResponse) ToMetadata() (map[string]interface{}, error) { + return marshalMetadata(c) +} + +func (c *PreprocessOperationsOptionsResponse) FromMetadata(meta map[string]interface{}) error { + return unmarshalMetadata(meta, c) +} + +// SignerData contains information on the signers when the request +// is being created, used to populate the account information +type SignerData struct { + AccountNumber uint64 `json:"account_number"` + Sequence uint64 `json:"sequence"` +} + +// ConstructionMetadata are the metadata options used to +// construct a transaction. It is returned by ConstructionMetadataFromOptions +// and fed to ConstructionPayload to process the bytes to sign. +type ConstructionMetadata struct { + ChainID string `json:"chain_id"` + SignersData []*SignerData `json:"signer_data"` + GasLimit uint64 `json:"gas_limit"` + GasPrice string `json:"gas_price"` + Memo string `json:"memo"` +} + +func (c ConstructionMetadata) ToMetadata() (map[string]interface{}, error) { + return marshalMetadata(c) +} + +func (c *ConstructionMetadata) FromMetadata(meta map[string]interface{}) error { + return unmarshalMetadata(meta, c) } diff --git a/server/rosetta/util.go b/server/rosetta/util.go index 29e4a1587dc2..43626b5ed351 100644 --- a/server/rosetta/util.go +++ b/server/rosetta/util.go @@ -1,112 +1,43 @@ package rosetta import ( - "fmt" + "encoding/json" + "time" - "github.com/coinbase/rosetta-sdk-go/types" - - tmcoretypes "github.com/tendermint/tendermint/rpc/core/types" - tmtypes "github.com/tendermint/tendermint/types" - - sdk "github.com/cosmos/cosmos-sdk/types" + crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors" ) -// tmResultTxsToSdkTxsWithHash converts tendermint result txs to cosmos sdk.Tx -func tmResultTxsToSdkTxsWithHash(decode sdk.TxDecoder, txs []*tmcoretypes.ResultTx) ([]*sdkTxWithHash, error) { - converted := make([]*sdkTxWithHash, len(txs)) - for i, tx := range txs { - sdkTx, err := decode(tx.Tx) - if err != nil { - return nil, err - } - converted[i] = &sdkTxWithHash{ - HexHash: fmt.Sprintf("%X", tx.Tx.Hash()), - Code: tx.TxResult.Code, - Log: tx.TxResult.Log, - Tx: sdkTx, - } - } - - return converted, nil +// timeToMilliseconds converts time to milliseconds timestamp +func timeToMilliseconds(t time.Time) int64 { + return t.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) } -func tmTxToSdkTx(decode sdk.TxDecoder, tx tmtypes.Tx) (sdk.Tx, error) { - sdkTx, err := decode(tx) +// unmarshalMetadata unmarshals the given meta to the target +func unmarshalMetadata(meta map[string]interface{}, target interface{}) error { + b, err := json.Marshal(meta) if err != nil { - return nil, err - } - - return sdkTx, err -} - -type sdkTxWithHash struct { - HexHash string - Code uint32 - Log string - Tx sdk.Tx -} - -type PayloadReqMetadata struct { - ChainID string - Sequence uint64 - AccountNumber uint64 - Gas uint64 - Memo string -} - -// getMetadataFromPayloadReq obtains the metadata from the request to /construction/payloads endpoint. -func getMetadataFromPayloadReq(req *types.ConstructionPayloadsRequest) (*PayloadReqMetadata, error) { - chainID, ok := req.Metadata[OptionChainID].(string) - if !ok { - return nil, fmt.Errorf("chain_id metadata was not provided") - } - - sequence, ok := req.Metadata[OptionSequence] - if !ok { - return nil, fmt.Errorf("sequence metadata was not provided") - } - - seqNum, ok := sequence.(float64) - if !ok { - return nil, fmt.Errorf("invalid sequence value") - } - - accountNum, ok := req.Metadata[OptionAccountNumber] - if !ok { - return nil, fmt.Errorf("account_number metadata was not provided") - } - - accNum, ok := accountNum.(float64) - if !ok { - fmt.Printf("this is type %T", accountNum) - return nil, fmt.Errorf("invalid account_number value") + return crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) } - gasNum, ok := req.Metadata[OptionGas] - if !ok { - return nil, fmt.Errorf("gas metadata was not provided") + err = json.Unmarshal(b, target) + if err != nil { + return crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) } - gasF64, ok := gasNum.(float64) - if !ok { - return nil, fmt.Errorf("invalid gas value") - } + return nil +} - memo, ok := req.Metadata[OptionMemo] - if !ok { - memo = "" +// marshalMetadata marshals the given interface to map[string]interface{} +func marshalMetadata(o interface{}) (meta map[string]interface{}, err error) { + b, err := json.Marshal(o) + if err != nil { + return nil, crgerrs.WrapError(crgerrs.ErrCodec, err.Error()) } - - memoStr, ok := memo.(string) - if !ok { - return nil, fmt.Errorf("invalid memo") + meta = make(map[string]interface{}) + err = json.Unmarshal(b, &meta) + if err != nil { + return nil, err } - return &PayloadReqMetadata{ - ChainID: chainID, - Sequence: uint64(seqNum), - AccountNumber: uint64(accNum), - Gas: uint64(gasF64), - Memo: memoStr, - }, nil + return } diff --git a/types/codec.go b/types/codec.go index 152bb9d724f5..9622e52a7fb1 100644 --- a/types/codec.go +++ b/types/codec.go @@ -5,6 +5,13 @@ import ( "github.com/cosmos/cosmos-sdk/codec/types" ) +// List of know interface types names +// TODO(fdymylja): maybe we need to add versioning to those constants? +const ( + MsgInterfaceName = "cosmos.base.v1beta1.Msg" + ServiceMsgInterfaceName = "cosmos.base.v1beta1.ServiceMsg" +) + // RegisterLegacyAminoCodec registers the sdk message type. func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterInterface((*Msg)(nil), nil) @@ -13,8 +20,8 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // RegisterInterfaces registers the sdk message type. func RegisterInterfaces(registry types.InterfaceRegistry) { - registry.RegisterInterface("cosmos.base.v1beta1.Msg", (*Msg)(nil)) + registry.RegisterInterface(MsgInterfaceName, (*Msg)(nil)) // the interface name for MsgRequest is ServiceMsg because this is most useful for clients // to understand - it will be the way for clients to introspect on available Msg service methods - registry.RegisterInterface("cosmos.base.v1beta1.ServiceMsg", (*MsgRequest)(nil)) + registry.RegisterInterface(ServiceMsgInterfaceName, (*MsgRequest)(nil)) } diff --git a/x/bank/types/msgs.go b/x/bank/types/msgs.go index dd41975468ca..22fdc30b3886 100644 --- a/x/bank/types/msgs.go +++ b/x/bank/types/msgs.go @@ -1,13 +1,6 @@ package types import ( - "fmt" - "strconv" - "strings" - - "github.com/coinbase/rosetta-sdk-go/types" - "github.com/gogo/protobuf/proto" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -69,83 +62,6 @@ func (msg MsgSend) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{from} } -// Rosetta interface -func (msg *MsgSend) ToOperations(withStatus bool, hasError bool) []*types.Operation { - var operations []*types.Operation - - fromAddress := msg.FromAddress - toAddress := msg.ToAddress - amounts := msg.Amount - if len(amounts) == 0 { - return []*types.Operation{} - } - - coin := amounts[0] - sendOp := func(account, amount string, index int) *types.Operation { - var status string - if withStatus { - status = "Success" - if hasError { - status = "Reverted" - } - } - return &types.Operation{ - OperationIdentifier: &types.OperationIdentifier{ - Index: int64(index), - }, - Type: proto.MessageName(msg), - Status: status, - Account: &types.AccountIdentifier{ - Address: account, - }, - Amount: &types.Amount{ - Value: amount, - Currency: &types.Currency{ - Symbol: coin.Denom, - }, - }, - } - } - operations = append(operations, - sendOp(fromAddress, "-"+coin.Amount.String(), 0), - sendOp(toAddress, coin.Amount.String(), 1), - ) - - return operations -} - -func (msg MsgSend) FromOperations(ops []*types.Operation) (sdk.Msg, error) { - var ( - from, to sdk.AccAddress - sendAmt sdk.Coin - err error - ) - - for _, op := range ops { - if strings.HasPrefix(op.Amount.Value, "-") { - from, err = sdk.AccAddressFromBech32(op.Account.Address) - if err != nil { - return nil, err - } - continue - } - - to, err = sdk.AccAddressFromBech32(op.Account.Address) - if err != nil { - return nil, err - } - - amount, err := strconv.ParseInt(op.Amount.Value, 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid amount") - } - - sendAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount)) - } - - return NewMsgSend(from, to, sdk.NewCoins(sendAmt)), nil -} - var _ sdk.Msg = &MsgMultiSend{} // NewMsgMultiSend - construct arbitrary multi-in, multi-out send msg. diff --git a/x/distribution/types/msg.go b/x/distribution/types/msg.go index 62c8bfc2abbb..8dc72081e9ac 100644 --- a/x/distribution/types/msg.go +++ b/x/distribution/types/msg.go @@ -2,12 +2,6 @@ package types import ( - "fmt" - - rosettatypes "github.com/coinbase/rosetta-sdk-go/types" - "github.com/gogo/protobuf/proto" - - "github.com/cosmos/cosmos-sdk/server/rosetta" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -96,50 +90,6 @@ func (msg MsgWithdrawDelegatorReward) ValidateBasic() error { return nil } -func (msg *MsgWithdrawDelegatorReward) ToOperations(withStatus, hasError bool) []*rosettatypes.Operation { - - var status string - if withStatus { - status = rosetta.StatusSuccess - if hasError { - status = rosetta.StatusReverted - } - } - - op := &rosettatypes.Operation{ - OperationIdentifier: &rosettatypes.OperationIdentifier{ - Index: 0, - }, - RelatedOperations: nil, - Type: proto.MessageName(msg), - Status: status, - Account: &rosettatypes.AccountIdentifier{ - Address: msg.DelegatorAddress, - SubAccount: &rosettatypes.SubAccountIdentifier{ - Address: msg.ValidatorAddress, - }, - }, - } - return []*rosettatypes.Operation{op} -} - -func (msg *MsgWithdrawDelegatorReward) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) { - if len(ops) != 1 { - return nil, fmt.Errorf("expected one operation") - } - op := ops[0] - if op.Account == nil { - return nil, fmt.Errorf("account identifier must be specified") - } - if op.Account.SubAccount == nil { - return nil, fmt.Errorf("account identifier subaccount must be specified") - } - return &MsgWithdrawDelegatorReward{ - DelegatorAddress: op.Account.Address, - ValidatorAddress: op.Account.SubAccount.Address, - }, nil -} - func NewMsgWithdrawValidatorCommission(valAddr sdk.ValAddress) *MsgWithdrawValidatorCommission { return &MsgWithdrawValidatorCommission{ ValidatorAddress: valAddr.String(), diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index d1da12386ae1..e397046e5779 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -2,17 +2,9 @@ package types import ( "bytes" - "fmt" - "strconv" - "strings" - - "github.com/gogo/protobuf/proto" - - rosettatypes "github.com/coinbase/rosetta-sdk-go/types" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/server/rosetta" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -264,90 +256,6 @@ func (msg MsgDelegate) ValidateBasic() error { return nil } -// Rosetta Msg interface. -func (msg *MsgDelegate) ToOperations(withStatus bool, hasError bool) []*rosettatypes.Operation { - var operations []*rosettatypes.Operation - delAddr := msg.DelegatorAddress - valAddr := msg.ValidatorAddress - coin := msg.Amount - delOp := func(account *rosettatypes.AccountIdentifier, amount string, index int) *rosettatypes.Operation { - var status string - if withStatus { - status = rosetta.StatusSuccess - if hasError { - status = rosetta.StatusReverted - } - } - return &rosettatypes.Operation{ - OperationIdentifier: &rosettatypes.OperationIdentifier{ - Index: int64(index), - }, - Type: proto.MessageName(msg), - Status: status, - Account: account, - Amount: &rosettatypes.Amount{ - Value: amount, - Currency: &rosettatypes.Currency{ - Symbol: coin.Denom, - }, - }, - } - } - delAcc := &rosettatypes.AccountIdentifier{ - Address: delAddr, - } - valAcc := &rosettatypes.AccountIdentifier{ - Address: "staking_account", - SubAccount: &rosettatypes.SubAccountIdentifier{ - Address: valAddr, - }, - } - operations = append(operations, - delOp(delAcc, "-"+coin.Amount.String(), 0), - delOp(valAcc, coin.Amount.String(), 1), - ) - return operations -} - -func (msg *MsgDelegate) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) { - var ( - delAddr sdk.AccAddress - valAddr sdk.ValAddress - sendAmt sdk.Coin - err error - ) - - for _, op := range ops { - if strings.HasPrefix(op.Amount.Value, "-") { - if op.Account == nil { - return nil, fmt.Errorf("account identifier must be specified") - } - delAddr, err = sdk.AccAddressFromBech32(op.Account.Address) - if err != nil { - return nil, err - } - continue - } - - if op.Account.SubAccount == nil { - return nil, fmt.Errorf("account identifier subaccount must be specified") - } - valAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address) - if err != nil { - return nil, err - } - - amount, err := strconv.ParseInt(op.Amount.Value, 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid amount: %w", err) - } - - sendAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount)) - } - - return NewMsgDelegate(delAddr, valAddr, sendAmt), nil -} - // NewMsgBeginRedelegate creates a new MsgBeginRedelegate instance. //nolint:interfacer func NewMsgBeginRedelegate( @@ -403,103 +311,6 @@ func (msg MsgBeginRedelegate) ValidateBasic() error { return nil } -// Rosetta Msg interface. -func (msg *MsgBeginRedelegate) ToOperations(withStatus bool, hasError bool) []*rosettatypes.Operation { - var operations []*rosettatypes.Operation - delAddr := msg.DelegatorAddress - srcValAddr := msg.ValidatorSrcAddress - destValAddr := msg.ValidatorDstAddress - coin := msg.Amount - delOp := func(account *rosettatypes.AccountIdentifier, amount string, index int) *rosettatypes.Operation { - var status string - if withStatus { - status = rosetta.StatusSuccess - if hasError { - status = rosetta.StatusReverted - } - } - return &rosettatypes.Operation{ - OperationIdentifier: &rosettatypes.OperationIdentifier{ - Index: int64(index), - }, - Type: proto.MessageName(msg), - Status: status, - Account: account, - Amount: &rosettatypes.Amount{ - Value: amount, - Currency: &rosettatypes.Currency{ - Symbol: coin.Denom, - }, - }, - } - } - srcValAcc := &rosettatypes.AccountIdentifier{ - Address: delAddr, - SubAccount: &rosettatypes.SubAccountIdentifier{ - Address: srcValAddr, - }, - } - destValAcc := &rosettatypes.AccountIdentifier{ - Address: "staking_account", - SubAccount: &rosettatypes.SubAccountIdentifier{ - Address: destValAddr, - }, - } - operations = append(operations, - delOp(srcValAcc, "-"+coin.Amount.String(), 0), - delOp(destValAcc, coin.Amount.String(), 1), - ) - return operations -} - -func (msg *MsgBeginRedelegate) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) { - var ( - delAddr sdk.AccAddress - srcValAddr sdk.ValAddress - destValAddr sdk.ValAddress - sendAmt sdk.Coin - err error - ) - - for _, op := range ops { - if strings.HasPrefix(op.Amount.Value, "-") { - if op.Account == nil { - return nil, fmt.Errorf("account identifier must be specified") - } - delAddr, err = sdk.AccAddressFromBech32(op.Account.Address) - if err != nil { - return nil, err - } - - if op.Account.SubAccount == nil { - return nil, fmt.Errorf("account identifier subaccount must be specified") - } - srcValAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address) - if err != nil { - return nil, err - } - continue - } - - if op.Account.SubAccount == nil { - return nil, fmt.Errorf("account identifier subaccount must be specified") - } - destValAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address) - if err != nil { - return nil, err - } - - amount, err := strconv.ParseInt(op.Amount.Value, 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid amount: %w", err) - } - - sendAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount)) - } - - return NewMsgBeginRedelegate(delAddr, srcValAddr, destValAddr, sendAmt), nil -} - // NewMsgUndelegate creates a new MsgUndelegate instance. //nolint:interfacer func NewMsgUndelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) *MsgUndelegate { @@ -547,88 +358,3 @@ func (msg MsgUndelegate) ValidateBasic() error { return nil } - -// Rosetta Msg interface. -func (msg *MsgUndelegate) ToOperations(withStatus bool, hasError bool) []*rosettatypes.Operation { - var operations []*rosettatypes.Operation - delAddr := msg.DelegatorAddress - valAddr := msg.ValidatorAddress - coin := msg.Amount - delOp := func(account *rosettatypes.AccountIdentifier, amount string, index int) *rosettatypes.Operation { - var status string - if withStatus { - status = rosetta.StatusSuccess - if hasError { - status = rosetta.StatusReverted - } - } - return &rosettatypes.Operation{ - OperationIdentifier: &rosettatypes.OperationIdentifier{ - Index: int64(index), - }, - Type: proto.MessageName(msg), - Status: status, - Account: account, - Amount: &rosettatypes.Amount{ - Value: amount, - Currency: &rosettatypes.Currency{ - Symbol: coin.Denom, - }, - }, - } - } - delAcc := &rosettatypes.AccountIdentifier{ - Address: delAddr, - } - valAcc := &rosettatypes.AccountIdentifier{ - Address: "staking_account", - SubAccount: &rosettatypes.SubAccountIdentifier{ - Address: valAddr, - }, - } - operations = append(operations, - delOp(valAcc, "-"+coin.Amount.String(), 0), - delOp(delAcc, coin.Amount.String(), 1), - ) - return operations -} - -func (msg *MsgUndelegate) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) { - var ( - delAddr sdk.AccAddress - valAddr sdk.ValAddress - undelAmt sdk.Coin - err error - ) - - for _, op := range ops { - if strings.HasPrefix(op.Amount.Value, "-") { - if op.Account.SubAccount == nil { - return nil, fmt.Errorf("account identifier subaccount must be specified") - } - valAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address) - if err != nil { - return nil, err - } - continue - } - - if op.Account == nil { - return nil, fmt.Errorf("account identifier must be specified") - } - - delAddr, err = sdk.AccAddressFromBech32(op.Account.Address) - if err != nil { - return nil, err - } - - amount, err := strconv.ParseInt(op.Amount.Value, 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid amount") - } - - undelAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount)) - } - - return NewMsgUndelegate(delAddr, valAddr, undelAmt), nil -}