202 lines
7.2 KiB
Go
202 lines
7.2 KiB
Go
package v2alpha1
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
"google.golang.org/grpc"
|
|
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/cosmos/cosmos-sdk/types/tx"
|
|
)
|
|
|
|
type Config struct {
|
|
SigningModes map[string]int32
|
|
ChainID string
|
|
SdkConfig *sdk.Config
|
|
InterfaceRegistry codectypes.InterfaceRegistry
|
|
}
|
|
|
|
// Register registers the cosmos sdk reflection service
|
|
// to the provided *grpc.Server given a Config
|
|
func Register(srv *grpc.Server, conf Config) error {
|
|
reflectionServer, err := newReflectionServiceServer(srv, conf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
RegisterReflectionServiceServer(srv, reflectionServer)
|
|
return nil
|
|
}
|
|
|
|
type reflectionServiceServer struct {
|
|
desc *AppDescriptor
|
|
}
|
|
|
|
func (r reflectionServiceServer) GetAuthnDescriptor(_ context.Context, _ *GetAuthnDescriptorRequest) (*GetAuthnDescriptorResponse, error) {
|
|
return &GetAuthnDescriptorResponse{Authn: r.desc.Authn}, nil
|
|
}
|
|
|
|
func (r reflectionServiceServer) GetChainDescriptor(_ context.Context, _ *GetChainDescriptorRequest) (*GetChainDescriptorResponse, error) {
|
|
return &GetChainDescriptorResponse{Chain: r.desc.Chain}, nil
|
|
}
|
|
|
|
func (r reflectionServiceServer) GetCodecDescriptor(_ context.Context, _ *GetCodecDescriptorRequest) (*GetCodecDescriptorResponse, error) {
|
|
return &GetCodecDescriptorResponse{Codec: r.desc.Codec}, nil
|
|
}
|
|
|
|
func (r reflectionServiceServer) GetConfigurationDescriptor(_ context.Context, _ *GetConfigurationDescriptorRequest) (*GetConfigurationDescriptorResponse, error) {
|
|
return &GetConfigurationDescriptorResponse{Config: r.desc.Configuration}, nil
|
|
}
|
|
|
|
func (r reflectionServiceServer) GetQueryServicesDescriptor(_ context.Context, _ *GetQueryServicesDescriptorRequest) (*GetQueryServicesDescriptorResponse, error) {
|
|
return &GetQueryServicesDescriptorResponse{Queries: r.desc.QueryServices}, nil
|
|
}
|
|
|
|
func (r reflectionServiceServer) GetTxDescriptor(_ context.Context, _ *GetTxDescriptorRequest) (*GetTxDescriptorResponse, error) {
|
|
return &GetTxDescriptorResponse{Tx: r.desc.Tx}, nil
|
|
}
|
|
|
|
func newReflectionServiceServer(grpcSrv *grpc.Server, conf Config) (reflectionServiceServer, error) {
|
|
// set chain descriptor
|
|
chainDescriptor := &ChainDescriptor{Id: conf.ChainID}
|
|
// set configuration descriptor
|
|
configurationDescriptor := &ConfigurationDescriptor{
|
|
Bech32AccountAddressPrefix: conf.SdkConfig.GetBech32AccountAddrPrefix(),
|
|
}
|
|
// set codec descriptor
|
|
codecDescriptor, err := newCodecDescriptor(conf.InterfaceRegistry)
|
|
if err != nil {
|
|
return reflectionServiceServer{}, fmt.Errorf("unable to create codec descriptor: %w", err)
|
|
}
|
|
// set query service descriptor
|
|
queryServiceDescriptor := newQueryServiceDescriptor(grpcSrv)
|
|
// set deliver descriptor
|
|
txDescriptor, err := newTxDescriptor(conf.InterfaceRegistry)
|
|
if err != nil {
|
|
return reflectionServiceServer{}, fmt.Errorf("unable to create deliver descriptor: %w", err)
|
|
}
|
|
authnDescriptor := newAuthnDescriptor(conf.SigningModes)
|
|
desc := &AppDescriptor{
|
|
Authn: authnDescriptor,
|
|
Chain: chainDescriptor,
|
|
Codec: codecDescriptor,
|
|
Configuration: configurationDescriptor,
|
|
QueryServices: queryServiceDescriptor,
|
|
Tx: txDescriptor,
|
|
}
|
|
|
|
ifaceList := make([]string, len(desc.Codec.Interfaces))
|
|
ifaceImplementers := make(map[string][]string, len(desc.Codec.Interfaces))
|
|
for i, iface := range desc.Codec.Interfaces {
|
|
ifaceList[i] = iface.Fullname
|
|
impls := make([]string, len(iface.InterfaceImplementers))
|
|
for j, impl := range iface.InterfaceImplementers {
|
|
impls[j] = impl.TypeUrl
|
|
}
|
|
ifaceImplementers[iface.Fullname] = impls
|
|
}
|
|
return reflectionServiceServer{
|
|
desc: desc,
|
|
}, nil
|
|
}
|
|
|
|
// newCodecDescriptor describes the codec given the codectypes.InterfaceRegistry
|
|
func newCodecDescriptor(ir codectypes.InterfaceRegistry) (*CodecDescriptor, error) {
|
|
registeredInterfaces := ir.ListAllInterfaces()
|
|
interfaceDescriptors := make([]*InterfaceDescriptor, len(registeredInterfaces))
|
|
|
|
for i, iface := range registeredInterfaces {
|
|
implementers := ir.ListImplementations(iface)
|
|
interfaceImplementers := make([]*InterfaceImplementerDescriptor, len(implementers))
|
|
for j, implementer := range implementers {
|
|
pb, err := ir.Resolve(implementer)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("unable to resolve implementing type %s for interface %s", implementer, iface)
|
|
}
|
|
pbName := proto.MessageName(pb)
|
|
if pbName == "" {
|
|
return nil, fmt.Errorf("unable to get proto name for implementing type %s for interface %s", implementer, iface)
|
|
}
|
|
interfaceImplementers[j] = &InterfaceImplementerDescriptor{
|
|
Fullname: pbName,
|
|
TypeUrl: implementer,
|
|
}
|
|
}
|
|
interfaceDescriptors[i] = &InterfaceDescriptor{
|
|
Fullname: iface,
|
|
// NOTE(fdymylja): this could be filled, but it won't be filled as of now
|
|
// doing this would require us to fully rebuild in a (dependency) transitive way the proto
|
|
// registry of the supported proto.Messages for the application, this could be easily
|
|
// done if we weren't relying on gogoproto which does not allow us to iterate over the
|
|
// registry. Achieving this right now would mean to start slowly building descriptors
|
|
// getting their files dependencies, building those dependencies then rebuilding the
|
|
// descriptor builder. It's too much work as of now.
|
|
InterfaceAcceptingMessages: nil,
|
|
InterfaceImplementers: interfaceImplementers,
|
|
}
|
|
}
|
|
|
|
return &CodecDescriptor{
|
|
Interfaces: interfaceDescriptors,
|
|
}, nil
|
|
}
|
|
|
|
func newQueryServiceDescriptor(srv *grpc.Server) *QueryServicesDescriptor {
|
|
svcInfo := srv.GetServiceInfo()
|
|
queryServices := make([]*QueryServiceDescriptor, 0, len(svcInfo))
|
|
for name, info := range svcInfo {
|
|
methods := make([]*QueryMethodDescriptor, len(info.Methods))
|
|
for i, svcMethod := range info.Methods {
|
|
methods[i] = &QueryMethodDescriptor{
|
|
Name: svcMethod.Name,
|
|
FullQueryPath: fmt.Sprintf("/%s/%s", name, svcMethod.Name),
|
|
}
|
|
}
|
|
queryServices = append(queryServices, &QueryServiceDescriptor{
|
|
Fullname: name,
|
|
Methods: methods,
|
|
})
|
|
}
|
|
return &QueryServicesDescriptor{QueryServices: queryServices}
|
|
}
|
|
|
|
func newTxDescriptor(ir codectypes.InterfaceRegistry) (*TxDescriptor, error) {
|
|
// get base tx type name
|
|
txPbName := proto.MessageName(&tx.Tx{})
|
|
if txPbName == "" {
|
|
return nil, fmt.Errorf("unable to get *tx.Tx protobuf name")
|
|
}
|
|
// get msgs
|
|
sdkMsgImplementers := ir.ListImplementations(sdk.MsgInterfaceProtoName)
|
|
|
|
msgsDesc := make([]*MsgDescriptor, 0, len(sdkMsgImplementers))
|
|
|
|
// process sdk.Msg
|
|
for _, msgTypeURL := range sdkMsgImplementers {
|
|
msgsDesc = append(msgsDesc, &MsgDescriptor{
|
|
MsgTypeUrl: msgTypeURL,
|
|
})
|
|
}
|
|
|
|
return &TxDescriptor{
|
|
Fullname: txPbName,
|
|
Msgs: msgsDesc,
|
|
}, nil
|
|
}
|
|
|
|
func newAuthnDescriptor(signingModes map[string]int32) *AuthnDescriptor {
|
|
signModesDesc := make([]*SigningModeDescriptor, 0, len(signingModes))
|
|
for i, m := range signingModes {
|
|
signModesDesc = append(signModesDesc, &SigningModeDescriptor{
|
|
Name: i,
|
|
Number: m,
|
|
// NOTE(fdymylja): this cannot be filled as of now, auth and the sdk itself don't support as of now
|
|
// a service which allows to get authentication metadata for the provided sign mode.
|
|
AuthnInfoProviderMethodFullname: "",
|
|
})
|
|
}
|
|
return &AuthnDescriptor{SignModes: signModesDesc}
|
|
}
|