fix(serverv2/cometbft): properly decode and route gRPC transactions (#20808)

Co-authored-by: marbar3778 <marbar3778@yahoo.com>
Co-authored-by: Marko <marko@baricevic.me>
This commit is contained in:
testinginprod
2024-07-16 10:14:02 +00:00
committed by GitHub
co-authored by marbar3778 Marko
parent 511fb07914
commit 86ea861c25
7 changed files with 83 additions and 43 deletions
+9
View File
@@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
gogoproto "github.com/cosmos/gogoproto/proto"
"golang.org/x/exp/slices"
runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2"
@@ -44,6 +45,10 @@ type App[T transaction.Tx] struct {
interfaceRegistrar registry.InterfaceRegistrar
amino legacy.Amino
moduleManager *MM[T]
// GRPCQueryDecoders maps gRPC method name to a function that decodes the request
// bytes into a gogoproto.Message, which then can be passed to appmanager.
GRPCQueryDecoders map[string]func(requestBytes []byte) (gogoproto.Message, error)
}
// Logger returns the app logger.
@@ -109,3 +114,7 @@ func (a *App[T]) ExecuteGenesisTx(_ []byte) error {
func (a *App[T]) GetAppManager() *appmanager.AppManager[T] {
return a.AppManager
}
func (a *App[T]) GetGRPCQueryDecoders() map[string]func(requestBytes []byte) (gogoproto.Message, error) {
return a.GRPCQueryDecoders
}
+33 -10
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"reflect"
"sort"
gogoproto "github.com/cosmos/gogoproto/proto"
@@ -555,17 +556,28 @@ func (m *MM[T]) assertNoForgottenModules(
func registerServices[T transaction.Tx](s appmodule.HasServices, app *App[T], registry *protoregistry.Files) error {
c := &configurator{
stfQueryRouter: app.queryRouterBuilder,
stfMsgRouter: app.msgRouterBuilder,
registry: registry,
err: nil,
grpcQueryDecoders: map[string]func([]byte) (gogoproto.Message, error){},
stfQueryRouter: app.queryRouterBuilder,
stfMsgRouter: app.msgRouterBuilder,
registry: registry,
err: nil,
}
return s.RegisterServices(c)
err := s.RegisterServices(c)
if err != nil {
return fmt.Errorf("unable to register services: %w", err)
}
app.GRPCQueryDecoders = c.grpcQueryDecoders
return nil
}
var _ grpc.ServiceRegistrar = (*configurator)(nil)
type configurator struct {
// grpcQueryDecoders is required because module expose queries through gRPC
// this provides a way to route to modules using gRPC.
grpcQueryDecoders map[string]func([]byte) (gogoproto.Message, error)
stfQueryRouter *stf.MsgRouterBuilder
stfMsgRouter *stf.MsgRouterBuilder
registry *protoregistry.Files
@@ -596,17 +608,28 @@ func (c *configurator) RegisterService(sd *grpc.ServiceDesc, ss interface{}) {
func (c *configurator) registerQueryHandlers(sd *grpc.ServiceDesc, ss interface{}) error {
for _, md := range sd.Methods {
// TODO(tip): what if a query is not deterministic?
err := registerMethod(c.stfQueryRouter, sd, md, ss)
requestFullName, err := registerMethod(c.stfQueryRouter, sd, md, ss)
if err != nil {
return fmt.Errorf("unable to register query handler %s: %w", md.MethodName, err)
}
// register gRPC query method.
typ := gogoproto.MessageType(requestFullName)
if typ == nil {
return fmt.Errorf("unable to find message in gogotype registry: %w", err)
}
decoderFunc := func(bytes []byte) (gogoproto.Message, error) {
msg := reflect.New(typ.Elem()).Interface().(gogoproto.Message)
return msg, gogoproto.Unmarshal(bytes, msg)
}
c.grpcQueryDecoders[md.MethodName] = decoderFunc
}
return nil
}
func (c *configurator) registerMsgHandlers(sd *grpc.ServiceDesc, ss interface{}) error {
for _, md := range sd.Methods {
err := registerMethod(c.stfMsgRouter, sd, md, ss)
_, err := registerMethod(c.stfMsgRouter, sd, md, ss)
if err != nil {
return fmt.Errorf("unable to register msg handler %s: %w", md.MethodName, err)
}
@@ -633,13 +656,13 @@ func registerMethod(
sd *grpc.ServiceDesc,
md grpc.MethodDesc,
ss interface{},
) error {
) (string, error) {
requestName, err := requestFullNameFromMethodDesc(sd, md)
if err != nil {
return err
return "", err
}
return stfRouter.RegisterHandler(string(requestName), func(
return string(requestName), stfRouter.RegisterHandler(string(requestName), func(
ctx context.Context,
msg appmodulev2.Message,
) (resp appmodulev2.Message, err error) {