RegisterInterfaces registers service Msg type_urls (#7671)

* Add RegisterMsgServiceDesc

* Refactor newSendTxMsgServiceCmd

* Add test

* Register in all modules

* Remove RegisterMsgServiceDesc from baseapp

* Add explicit error message

* Add comment

* Update comment

* Add test

* Update comment

* Remove duplicate import

* Fix lint

* Forgot vesting

* Fix lint

* Fix test

* Put in types/module

* Put in types/msgservice

* Add comment about panic

* Update baseapp/msg_service_router.go

Co-authored-by: Robert Zaremba <robert@zaremba.ch>

* Update baseapp/msg_service_router.go

Co-authored-by: Robert Zaremba <robert@zaremba.ch>

* Update baseapp/msg_service_router.go

Co-authored-by: Robert Zaremba <robert@zaremba.ch>

* Add comment

* Add better test

* Update baseapp/msg_service_router.go

Co-authored-by: Marie Gauthier <marie.gauthier63@gmail.com>

Co-authored-by: Robert Zaremba <robert@zaremba.ch>
Co-authored-by: Marie Gauthier <marie.gauthier63@gmail.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
Amaury Martiny
2020-10-28 19:20:45 +00:00
committed by GitHub
co-authored by Robert Zaremba Marie Gauthier mergify[bot]
parent 1b0d6540d8
commit 82f15f306e
19 changed files with 259 additions and 117 deletions
+20 -20
View File
@@ -39,27 +39,32 @@ func (msr *MsgServiceRouter) Handler(methodName string) MsgServiceHandler {
// RegisterService implements the gRPC Server.RegisterService method. sd is a gRPC
// service description, handler is an object which implements that gRPC service.
//
// This function PANICs if it is called before the service `Msg`s have been
// registered using RegisterInterfaces.
func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler interface{}) {
// Adds a top-level query handler based on the gRPC service name.
for _, method := range sd.Methods {
fqMethod := fmt.Sprintf("/%s/%s", sd.ServiceName, method.MethodName)
methodHandler := method.Handler
// 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.(proto.Message)
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("can't register request type %T for service method %s", i, fqMethod))
}
msr.interfaceRegistry.RegisterCustomTypeURL((*sdk.MsgRequest)(nil), fqMethod, msg)
return nil
}, noopInterceptor)
// Check that the service Msg fully-qualified method name has already
// been registered (via RegisterInterfaces). If the user registers a
// service without registering according service Msg type, there might be
// some unexpected behavior down the road. Since we can't return an error
// (`Server.RegisterService` interface restriction) we panic (at startup).
serviceMsg, err := msr.interfaceRegistry.Resolve(fqMethod)
if err != nil || serviceMsg == nil {
panic(
fmt.Errorf(
"type_url %s has not been registered yet. "+
"Before calling RegisterService, you must register all interfaces by calling the `RegisterInterfaces` "+
"method on module.BasicManager. Each module should call `msgservice.RegisterMsgServiceDesc` inside its "+
"`RegisterInterfaces` method with the `_Msg_serviceDesc` generated by proto-gen",
fqMethod,
),
)
}
msr.routes[fqMethod] = func(ctx sdk.Context, req sdk.MsgRequest) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
@@ -89,9 +94,4 @@ func (msr *MsgServiceRouter) SetInterfaceRegistry(interfaceRegistry codectypes.I
msr.interfaceRegistry = interfaceRegistry
}
// gRPC NOOP interceptor
func noopInterceptor(_ context.Context, _ interface{}, _ *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (interface{}, error) {
return nil, nil
}
func noopDecoder(_ interface{}) error { return nil }
+27 -4
View File
@@ -4,15 +4,13 @@ import (
"os"
"testing"
"github.com/cosmos/cosmos-sdk/baseapp"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
@@ -20,9 +18,34 @@ import (
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
)
func TestRegisterService(t *testing.T) {
db := dbm.NewMemDB()
// Create an encoding config that doesn't register testdata Msg services.
encCfg := simapp.MakeTestEncodingConfig()
app := baseapp.NewBaseApp("test", log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, encCfg.TxConfig.TxDecoder())
app.SetInterfaceRegistry(encCfg.InterfaceRegistry)
require.Panics(t, func() {
testdata.RegisterMsgServer(
app.MsgServiceRouter(),
testdata.MsgServerImpl{},
)
})
// Register testdata Msg services, and rerun `RegisterService`.
testdata.RegisterInterfaces(encCfg.InterfaceRegistry)
require.NotPanics(t, func() {
testdata.RegisterMsgServer(
app.MsgServiceRouter(),
testdata.MsgServerImpl{},
)
})
}
func TestMsgService(t *testing.T) {
priv, _, _ := testdata.KeyTestPubAddr()
encCfg := simapp.MakeTestEncodingConfig()
testdata.RegisterInterfaces(encCfg.InterfaceRegistry)
db := dbm.NewMemDB()
app := baseapp.NewBaseApp("test", log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, encCfg.TxConfig.TxDecoder())
app.SetInterfaceRegistry(encCfg.InterfaceRegistry)