Skip to content

Commit

Permalink
fix: make RegisterMsgServiceDesc not use the global registry (#19835)
Browse files Browse the repository at this point in the history
Co-authored-by: Marko <marko@baricevic.me>
  • Loading branch information
aaronc and tac0turtle committed May 3, 2024
1 parent 14f3ca0 commit 921ab72
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 58 deletions.
10 changes: 8 additions & 2 deletions baseapp/msg_service_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package baseapp
import (
"context"
"fmt"
"reflect"

abci "github.com/cometbft/cometbft/abci/types"
gogogrpc "github.com/cosmos/gogoproto/grpc"
Expand Down Expand Up @@ -139,20 +140,22 @@ 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
// work correctly anyway.
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)

Expand All @@ -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
Expand Down
78 changes: 22 additions & 56 deletions types/msgservice/msg_service.go
Original file line number Diff line number Diff line change
@@ -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"

Expand All @@ -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))
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))
}
}

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))
}
}

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
}

0 comments on commit 921ab72

Please sign in to comment.