fix: make RegisterMsgServiceDesc not use the global registry (#19835)
Co-authored-by: Marko <marko@baricevic.me>
This commit is contained in:
parent
14f3ca0ae9
commit
921ab722e4
@ -3,6 +3,7 @@ package baseapp
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
abci "github.com/cometbft/cometbft/abci/types"
|
||||
gogogrpc "github.com/cosmos/gogoproto/grpc"
|
||||
@ -139,12 +140,14 @@ func (msr *MsgServiceRouter) registerMsgServiceHandler(sd *grpc.ServiceDesc, met
|
||||
methodHandler := method.Handler
|
||||
|
||||
var requestTypeName string
|
||||
var theMsg sdk.Msg
|
||||
|
||||
// NOTE: This is how we pull the concrete request type for each handler for registering in the InterfaceRegistry.
|
||||
// This approach is maybe a bit hacky, but less hacky than reflecting on the handler object itself.
|
||||
// We use a no-op interceptor to avoid actually calling into the handler itself.
|
||||
_, _ = methodHandler(nil, context.Background(), func(i interface{}) error {
|
||||
msg, ok := i.(sdk.Msg)
|
||||
var ok bool
|
||||
theMsg, ok = i.(sdk.Msg)
|
||||
if !ok {
|
||||
// We panic here because there is no other alternative and the app cannot be initialized correctly
|
||||
// this should only happen if there is a problem with code generation in which case the app won't
|
||||
@ -152,7 +155,7 @@ func (msr *MsgServiceRouter) registerMsgServiceHandler(sd *grpc.ServiceDesc, met
|
||||
panic(fmt.Errorf("unable to register service method %s: %T does not implement sdk.Msg", fqMethod, i))
|
||||
}
|
||||
|
||||
requestTypeName = sdk.MsgTypeURL(msg)
|
||||
requestTypeName = sdk.MsgTypeURL(theMsg)
|
||||
return nil
|
||||
}, noopInterceptor)
|
||||
|
||||
@ -171,6 +174,9 @@ func (msr *MsgServiceRouter) registerMsgServiceHandler(sd *grpc.ServiceDesc, met
|
||||
requestTypeName,
|
||||
)
|
||||
}
|
||||
if reflect.TypeOf(reqType) != reflect.TypeOf(theMsg) {
|
||||
return fmt.Errorf("the type registered with the interface registry %T does not match the type in the handler %T", reqType, theMsg)
|
||||
}
|
||||
|
||||
// Check that each service is only registered once. If a service is
|
||||
// registered more than once, then we should error. Since we can't
|
||||
|
||||
@ -1,18 +1,10 @@
|
||||
package msgservice
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/cosmos/gogoproto/proto"
|
||||
"google.golang.org/grpc"
|
||||
proto2 "google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protodesc"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/types/descriptorpb"
|
||||
|
||||
"cosmossdk.io/core/registry"
|
||||
|
||||
@ -21,54 +13,28 @@ import (
|
||||
)
|
||||
|
||||
// RegisterMsgServiceDesc registers all type_urls from Msg services described
|
||||
// in `sd` into the registry.
|
||||
// in `sd` into the registry. The ServiceDesc must be a standard gRPC ServiceDesc
|
||||
// from a generated file as this function will use reflection to extract the
|
||||
// concrete types and expects the HandlerType to follow the normal
|
||||
// generated type conventions.
|
||||
func RegisterMsgServiceDesc(registrar registry.InterfaceRegistrar, sd *grpc.ServiceDesc) {
|
||||
fdBytesUnzipped := unzip(proto.FileDescriptor(sd.Metadata.(string)))
|
||||
if fdBytesUnzipped == nil {
|
||||
panic(fmt.Errorf("error unzipping file description for MsgService %s", sd.ServiceName))
|
||||
}
|
||||
|
||||
fdRaw := &descriptorpb.FileDescriptorProto{}
|
||||
err := proto2.Unmarshal(fdBytesUnzipped, fdRaw)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fd, err := protodesc.FileOptions{
|
||||
AllowUnresolvable: true,
|
||||
}.New(fdRaw, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
prefSd := fd.Services().ByName(protoreflect.FullName(sd.ServiceName).Name())
|
||||
for i := 0; i < prefSd.Methods().Len(); i++ {
|
||||
md := prefSd.Methods().Get(i)
|
||||
requestDesc := md.Input()
|
||||
responseDesc := md.Output()
|
||||
|
||||
reqTyp := proto.MessageType(string(requestDesc.FullName()))
|
||||
respTyp := proto.MessageType(string(responseDesc.FullName()))
|
||||
|
||||
// Register sdk.Msg and sdk.MsgResponse to the registry.
|
||||
registrar.RegisterImplementations((*sdk.Msg)(nil), reflect.New(reqTyp).Elem().Interface().(proto.Message))
|
||||
registrar.RegisterImplementations((*tx.MsgResponse)(nil), reflect.New(respTyp).Elem().Interface().(proto.Message))
|
||||
handlerType := reflect.TypeOf(sd.HandlerType).Elem()
|
||||
msgType := reflect.TypeOf((*proto.Message)(nil)).Elem()
|
||||
numMethods := handlerType.NumMethod()
|
||||
for i := 0; i < numMethods; i++ {
|
||||
method := handlerType.Method(i)
|
||||
numIn := method.Type.NumIn()
|
||||
numOut := method.Type.NumOut()
|
||||
if numIn != 2 || numOut != 2 {
|
||||
continue
|
||||
}
|
||||
reqType := method.Type.In(1)
|
||||
resType := method.Type.Out(0)
|
||||
if reqType.AssignableTo(msgType) && resType.AssignableTo(msgType) {
|
||||
req := reflect.New(reqType.Elem()).Interface()
|
||||
registrar.RegisterImplementations((*sdk.Msg)(nil), req.(proto.Message))
|
||||
res := reflect.New(resType.Elem()).Interface()
|
||||
registrar.RegisterImplementations((*tx.MsgResponse)(nil), res.(proto.Message))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func unzip(b []byte) []byte {
|
||||
if b == nil {
|
||||
return nil
|
||||
}
|
||||
r, err := gzip.NewReader(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
unzipped, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return unzipped
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user