2020-06-03 06:33:51 -07:00
|
|
|
package baseapp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
gogogrpc "github.com/gogo/protobuf/grpc"
|
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
"google.golang.org/grpc/encoding"
|
|
|
|
"google.golang.org/grpc/encoding/proto"
|
|
|
|
|
2020-08-17 10:02:13 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/client/grpc/reflection"
|
2020-08-24 07:41:08 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/client/grpc/simulate"
|
|
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
|
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
2020-06-03 06:33:51 -07:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
var protoCodec = encoding.GetCodec(proto.Name)
|
|
|
|
|
2020-06-04 11:48:06 -07:00
|
|
|
// GRPCQueryRouter routes ABCI Query requests to GRPC handlers
|
|
|
|
type GRPCQueryRouter struct {
|
2020-08-17 10:02:13 -07:00
|
|
|
routes map[string]GRPCQueryHandler
|
2020-08-24 07:41:08 -07:00
|
|
|
interfaceRegistry codectypes.InterfaceRegistry
|
2020-08-17 10:02:13 -07:00
|
|
|
serviceData []serviceData
|
2020-07-27 10:57:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// serviceData represents a gRPC service, along with its handler.
|
|
|
|
type serviceData struct {
|
|
|
|
serviceDesc *grpc.ServiceDesc
|
|
|
|
handler interface{}
|
2020-06-03 06:33:51 -07:00
|
|
|
}
|
|
|
|
|
2020-08-17 10:02:13 -07:00
|
|
|
var _ gogogrpc.Server = &GRPCQueryRouter{}
|
2020-06-03 06:33:51 -07:00
|
|
|
|
2020-06-04 11:48:06 -07:00
|
|
|
// NewGRPCQueryRouter creates a new GRPCQueryRouter
|
|
|
|
func NewGRPCQueryRouter() *GRPCQueryRouter {
|
|
|
|
return &GRPCQueryRouter{
|
2020-06-03 06:33:51 -07:00
|
|
|
routes: map[string]GRPCQueryHandler{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GRPCQueryHandler defines a function type which handles ABCI Query requests
|
|
|
|
// using gRPC
|
|
|
|
type GRPCQueryHandler = func(ctx sdk.Context, req abci.RequestQuery) (abci.ResponseQuery, error)
|
|
|
|
|
|
|
|
// Route returns the GRPCQueryHandler for a given query route path or nil
|
|
|
|
// if not found
|
2020-06-04 11:48:06 -07:00
|
|
|
func (qrt *GRPCQueryRouter) Route(path string) GRPCQueryHandler {
|
2020-06-03 06:33:51 -07:00
|
|
|
handler, found := qrt.routes[path]
|
|
|
|
if !found {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return handler
|
|
|
|
}
|
|
|
|
|
|
|
|
// RegisterService implements the gRPC Server.RegisterService method. sd is a gRPC
|
|
|
|
// service description, handler is an object which implements that gRPC service
|
2020-06-04 11:48:06 -07:00
|
|
|
func (qrt *GRPCQueryRouter) RegisterService(sd *grpc.ServiceDesc, handler interface{}) {
|
2020-06-03 06:33:51 -07:00
|
|
|
// adds a top-level query handler based on the gRPC service name
|
|
|
|
for _, method := range sd.Methods {
|
|
|
|
fqName := fmt.Sprintf("/%s/%s", sd.ServiceName, method.MethodName)
|
|
|
|
methodHandler := method.Handler
|
|
|
|
|
|
|
|
qrt.routes[fqName] = func(ctx sdk.Context, req abci.RequestQuery) (abci.ResponseQuery, error) {
|
|
|
|
// call the method handler from the service description with the handler object,
|
|
|
|
// a wrapped sdk.Context with proto-unmarshaled data from the ABCI request data
|
|
|
|
res, err := methodHandler(handler, sdk.WrapSDKContext(ctx), func(i interface{}) error {
|
2020-07-03 09:42:12 -07:00
|
|
|
err := protoCodec.Unmarshal(req.Data, i)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-08-17 10:02:13 -07:00
|
|
|
if qrt.interfaceRegistry != nil {
|
2020-08-24 07:41:08 -07:00
|
|
|
return codectypes.UnpackInterfaces(i, qrt.interfaceRegistry)
|
2020-07-03 09:42:12 -07:00
|
|
|
}
|
|
|
|
return nil
|
2020-06-03 06:33:51 -07:00
|
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
|
|
return abci.ResponseQuery{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// proto marshal the result bytes
|
|
|
|
resBytes, err := protoCodec.Marshal(res)
|
|
|
|
if err != nil {
|
|
|
|
return abci.ResponseQuery{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// return the result bytes as the response value
|
|
|
|
return abci.ResponseQuery{
|
|
|
|
Height: req.Height,
|
|
|
|
Value: resBytes,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
}
|
2020-07-27 10:57:15 -07:00
|
|
|
|
|
|
|
qrt.serviceData = append(qrt.serviceData, serviceData{
|
|
|
|
serviceDesc: sd,
|
|
|
|
handler: handler,
|
|
|
|
})
|
2020-06-03 06:33:51 -07:00
|
|
|
}
|
2020-07-03 09:42:12 -07:00
|
|
|
|
2020-08-24 07:41:08 -07:00
|
|
|
// SetInterfaceRegistry sets the interface registry for the router. This will
|
|
|
|
// also register the interface reflection gRPC service.
|
|
|
|
func (qrt *GRPCQueryRouter) SetInterfaceRegistry(interfaceRegistry codectypes.InterfaceRegistry) {
|
2020-08-17 10:02:13 -07:00
|
|
|
qrt.interfaceRegistry = interfaceRegistry
|
2020-07-03 09:42:12 -07:00
|
|
|
|
2020-08-17 10:02:13 -07:00
|
|
|
// Once we have an interface registry, we can register the interface
|
|
|
|
// registry reflection gRPC service.
|
|
|
|
reflection.RegisterReflectionServiceServer(
|
|
|
|
qrt,
|
2020-08-24 07:41:08 -07:00
|
|
|
reflection.NewReflectionServiceServer(interfaceRegistry),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// RegisterSimulateService registers the simulate service on the gRPC router.
|
|
|
|
func (qrt *GRPCQueryRouter) RegisterSimulateService(
|
|
|
|
simulateFn simulate.BaseAppSimulateFn,
|
|
|
|
interfaceRegistry codectypes.InterfaceRegistry,
|
|
|
|
pubkeyCodec cryptotypes.PublicKeyCodec,
|
|
|
|
) {
|
|
|
|
simulate.RegisterSimulateServiceServer(
|
|
|
|
qrt,
|
2020-09-01 13:59:48 -07:00
|
|
|
simulate.NewSimulateServer(simulateFn, interfaceRegistry, pubkeyCodec),
|
2020-08-17 10:02:13 -07:00
|
|
|
)
|
2020-07-03 09:42:12 -07:00
|
|
|
}
|