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:
co-authored by
Robert Zaremba
Marie Gauthier
mergify[bot]
parent
1b0d6540d8
commit
82f15f306e
@@ -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 }
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user