github.com/Finschia/finschia-sdk@v0.48.1/server/grpc/reflection/v2/reflection.go (about) 1 package v2 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/gogo/protobuf/proto" 8 "google.golang.org/grpc" 9 10 codectypes "github.com/Finschia/finschia-sdk/codec/types" 11 sdk "github.com/Finschia/finschia-sdk/types" 12 "github.com/Finschia/finschia-sdk/types/tx" 13 ) 14 15 type Config struct { 16 SigningModes map[string]int32 17 ChainID string 18 SdkConfig *sdk.Config 19 InterfaceRegistry codectypes.InterfaceRegistry 20 } 21 22 // Register registers the cosmos sdk reflection service 23 // to the provided *grpc.Server given a Config 24 func Register(srv *grpc.Server, conf Config) error { 25 reflectionServer, err := newReflectionServiceServer(srv, conf) 26 if err != nil { 27 return err 28 } 29 RegisterReflectionServiceServer(srv, reflectionServer) 30 return nil 31 } 32 33 type reflectionServiceServer struct { 34 desc *AppDescriptor 35 } 36 37 func (r reflectionServiceServer) GetAuthnDescriptor(_ context.Context, _ *GetAuthnDescriptorRequest) (*GetAuthnDescriptorResponse, error) { 38 return &GetAuthnDescriptorResponse{Authn: r.desc.Authn}, nil 39 } 40 41 func (r reflectionServiceServer) GetChainDescriptor(_ context.Context, _ *GetChainDescriptorRequest) (*GetChainDescriptorResponse, error) { 42 return &GetChainDescriptorResponse{Chain: r.desc.Chain}, nil 43 } 44 45 func (r reflectionServiceServer) GetCodecDescriptor(_ context.Context, _ *GetCodecDescriptorRequest) (*GetCodecDescriptorResponse, error) { 46 return &GetCodecDescriptorResponse{Codec: r.desc.Codec}, nil 47 } 48 49 func (r reflectionServiceServer) GetConfigurationDescriptor(_ context.Context, _ *GetConfigurationDescriptorRequest) (*GetConfigurationDescriptorResponse, error) { 50 return &GetConfigurationDescriptorResponse{Config: r.desc.Configuration}, nil 51 } 52 53 func (r reflectionServiceServer) GetQueryServicesDescriptor(_ context.Context, _ *GetQueryServicesDescriptorRequest) (*GetQueryServicesDescriptorResponse, error) { 54 return &GetQueryServicesDescriptorResponse{Queries: r.desc.QueryServices}, nil 55 } 56 57 func (r reflectionServiceServer) GetTxDescriptor(_ context.Context, _ *GetTxDescriptorRequest) (*GetTxDescriptorResponse, error) { 58 return &GetTxDescriptorResponse{Tx: r.desc.Tx}, nil 59 } 60 61 func newReflectionServiceServer(grpcSrv *grpc.Server, conf Config) (reflectionServiceServer, error) { 62 // set chain descriptor 63 chainDescriptor := &ChainDescriptor{Id: conf.ChainID} 64 // set configuration descriptor 65 configurationDescriptor := &ConfigurationDescriptor{ 66 Bech32AccountAddressPrefix: conf.SdkConfig.GetBech32AccountAddrPrefix(), 67 } 68 // set codec descriptor 69 codecDescriptor, err := newCodecDescriptor(conf.InterfaceRegistry) 70 if err != nil { 71 return reflectionServiceServer{}, fmt.Errorf("unable to create codec descriptor: %w", err) 72 } 73 // set query service descriptor 74 queryServiceDescriptor := newQueryServiceDescriptor(grpcSrv) 75 // set deliver descriptor 76 txDescriptor, err := newTxDescriptor(conf.InterfaceRegistry) 77 if err != nil { 78 return reflectionServiceServer{}, fmt.Errorf("unable to create deliver descriptor: %w", err) 79 } 80 authnDescriptor := newAuthnDescriptor(conf.SigningModes) 81 desc := &AppDescriptor{ 82 Authn: authnDescriptor, 83 Chain: chainDescriptor, 84 Codec: codecDescriptor, 85 Configuration: configurationDescriptor, 86 QueryServices: queryServiceDescriptor, 87 Tx: txDescriptor, 88 } 89 90 ifaceList := make([]string, len(desc.Codec.Interfaces)) 91 ifaceImplementers := make(map[string][]string, len(desc.Codec.Interfaces)) 92 for i, iface := range desc.Codec.Interfaces { 93 ifaceList[i] = iface.Fullname 94 impls := make([]string, len(iface.InterfaceImplementers)) 95 for j, impl := range iface.InterfaceImplementers { 96 impls[j] = impl.TypeUrl 97 } 98 ifaceImplementers[iface.Fullname] = impls 99 } 100 return reflectionServiceServer{ 101 desc: desc, 102 }, nil 103 } 104 105 // newCodecDescriptor describes the codec given the codectypes.InterfaceRegistry 106 func newCodecDescriptor(ir codectypes.InterfaceRegistry) (*CodecDescriptor, error) { 107 registeredInterfaces := ir.ListAllInterfaces() 108 interfaceDescriptors := make([]*InterfaceDescriptor, len(registeredInterfaces)) 109 110 for i, iface := range registeredInterfaces { 111 implementers := ir.ListImplementations(iface) 112 interfaceImplementers := make([]*InterfaceImplementerDescriptor, len(implementers)) 113 for j, implementer := range implementers { 114 pb, err := ir.Resolve(implementer) 115 if err != nil { 116 return nil, fmt.Errorf("unable to resolve implementing type %s for interface %s", implementer, iface) 117 } 118 pbName := proto.MessageName(pb) 119 if pbName == "" { 120 return nil, fmt.Errorf("unable to get proto name for implementing type %s for interface %s", implementer, iface) 121 } 122 interfaceImplementers[j] = &InterfaceImplementerDescriptor{ 123 Fullname: pbName, 124 TypeUrl: implementer, 125 } 126 } 127 interfaceDescriptors[i] = &InterfaceDescriptor{ 128 Fullname: iface, 129 // NOTE(fdymylja): this could be filled, but it won't be filled as of now 130 // doing this would require us to fully rebuild in a (dependency) transitive way the proto 131 // registry of the supported proto.Messages for the application, this could be easily 132 // done if we weren't relying on gogoproto which does not allow us to iterate over the 133 // registry. Achieving this right now would mean to start slowly building descriptors 134 // getting their files dependencies, building those dependencies then rebuilding the 135 // descriptor builder. It's too much work as of now. 136 InterfaceAcceptingMessages: nil, 137 InterfaceImplementers: interfaceImplementers, 138 } 139 } 140 141 return &CodecDescriptor{ 142 Interfaces: interfaceDescriptors, 143 }, nil 144 } 145 146 func newQueryServiceDescriptor(srv *grpc.Server) *QueryServicesDescriptor { 147 svcInfo := srv.GetServiceInfo() 148 queryServices := make([]*QueryServiceDescriptor, 0, len(svcInfo)) 149 for name, info := range svcInfo { 150 methods := make([]*QueryMethodDescriptor, len(info.Methods)) 151 for i, svcMethod := range info.Methods { 152 methods[i] = &QueryMethodDescriptor{ 153 Name: svcMethod.Name, 154 FullQueryPath: fmt.Sprintf("/%s/%s", name, svcMethod.Name), 155 } 156 } 157 queryServices = append(queryServices, &QueryServiceDescriptor{ 158 Fullname: name, 159 Methods: methods, 160 }) 161 } 162 return &QueryServicesDescriptor{QueryServices: queryServices} 163 } 164 165 func newTxDescriptor(ir codectypes.InterfaceRegistry) (*TxDescriptor, error) { 166 // get base tx type name 167 txPbName := proto.MessageName(&tx.Tx{}) 168 if txPbName == "" { 169 return nil, fmt.Errorf("unable to get *tx.Tx protobuf name") 170 } 171 // get msgs 172 sdkMsgImplementers := ir.ListImplementations(sdk.MsgInterfaceProtoName) 173 174 msgsDesc := make([]*MsgDescriptor, 0, len(sdkMsgImplementers)) 175 176 // process sdk.Msg 177 for _, msgTypeURL := range sdkMsgImplementers { 178 msgsDesc = append(msgsDesc, &MsgDescriptor{ 179 MsgTypeUrl: msgTypeURL, 180 }) 181 } 182 183 return &TxDescriptor{ 184 Fullname: txPbName, 185 Msgs: msgsDesc, 186 }, nil 187 } 188 189 func newAuthnDescriptor(signingModes map[string]int32) *AuthnDescriptor { 190 signModesDesc := make([]*SigningModeDescriptor, 0, len(signingModes)) 191 for i, m := range signingModes { 192 signModesDesc = append(signModesDesc, &SigningModeDescriptor{ 193 Name: i, 194 Number: m, 195 // NOTE(fdymylja): this cannot be filled as of now, auth and the sdk itself don't support as of now 196 // a service which allows to get authentication metadata for the provided sign mode. 197 AuthnInfoProviderMethodFullname: "", 198 }) 199 } 200 return &AuthnDescriptor{SignModes: signModesDesc} 201 }