Skip to content

Commit 849429e

Browse files
authored
Add proper support for Any in gRPC queries (cosmos#6594)
* Add proper gRPC Any support via AnyUnpacker * Wire up grpc query router AnyUnpacker
1 parent 4f3efad commit 849429e

File tree

13 files changed

+599
-73
lines changed

13 files changed

+599
-73
lines changed

baseapp/baseapp.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"reflect"
66
"strings"
77

8-
"github.com/gogo/protobuf/grpc"
98
"github.com/gogo/protobuf/proto"
109

1110
abci "github.com/tendermint/tendermint/abci/types"
@@ -292,7 +291,7 @@ func (app *BaseApp) Router() sdk.Router {
292291
func (app *BaseApp) QueryRouter() sdk.QueryRouter { return app.queryRouter }
293292

294293
// GRPCQueryRouter returns the GRPCQueryRouter of a BaseApp.
295-
func (app *BaseApp) GRPCQueryRouter() grpc.Server { return app.grpcQueryRouter }
294+
func (app *BaseApp) GRPCQueryRouter() *GRPCQueryRouter { return app.grpcQueryRouter }
296295

297296
// Seal seals a BaseApp. It prohibits any further modifications to a BaseApp.
298297
func (app *BaseApp) Seal() { app.sealed = true }

baseapp/grpcrouter.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package baseapp
33
import (
44
"fmt"
55

6+
"github.com/cosmos/cosmos-sdk/codec/types"
7+
68
gogogrpc "github.com/gogo/protobuf/grpc"
79
abci "github.com/tendermint/tendermint/abci/types"
810
"google.golang.org/grpc"
@@ -16,7 +18,8 @@ var protoCodec = encoding.GetCodec(proto.Name)
1618

1719
// GRPCQueryRouter routes ABCI Query requests to GRPC handlers
1820
type GRPCQueryRouter struct {
19-
routes map[string]GRPCQueryHandler
21+
routes map[string]GRPCQueryHandler
22+
anyUnpacker types.AnyUnpacker
2023
}
2124

2225
var _ gogogrpc.Server
@@ -54,7 +57,14 @@ func (qrt *GRPCQueryRouter) RegisterService(sd *grpc.ServiceDesc, handler interf
5457
// call the method handler from the service description with the handler object,
5558
// a wrapped sdk.Context with proto-unmarshaled data from the ABCI request data
5659
res, err := methodHandler(handler, sdk.WrapSDKContext(ctx), func(i interface{}) error {
57-
return protoCodec.Unmarshal(req.Data, i)
60+
err := protoCodec.Unmarshal(req.Data, i)
61+
if err != nil {
62+
return err
63+
}
64+
if qrt.anyUnpacker != nil {
65+
return types.UnpackInterfaces(i, qrt.anyUnpacker)
66+
}
67+
return nil
5868
}, nil)
5969
if err != nil {
6070
return abci.ResponseQuery{}, err
@@ -74,3 +84,13 @@ func (qrt *GRPCQueryRouter) RegisterService(sd *grpc.ServiceDesc, handler interf
7484
}
7585
}
7686
}
87+
88+
// AnyUnpacker returns the AnyUnpacker for the router
89+
func (qrt *GRPCQueryRouter) AnyUnpacker() types.AnyUnpacker {
90+
return qrt.anyUnpacker
91+
}
92+
93+
// SetAnyUnpacker sets the AnyUnpacker for the router
94+
func (qrt *GRPCQueryRouter) SetAnyUnpacker(anyUnpacker types.AnyUnpacker) {
95+
qrt.anyUnpacker = anyUnpacker
96+
}

baseapp/grpcrouter_helpers.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
gocontext "context"
55
"fmt"
66

7+
"github.com/cosmos/cosmos-sdk/codec/types"
8+
79
gogogrpc "github.com/gogo/protobuf/grpc"
810
abci "github.com/tendermint/tendermint/abci/types"
911
"google.golang.org/grpc"
@@ -22,8 +24,10 @@ type QueryServiceTestHelper struct {
2224

2325
// NewQueryServerTestHelper creates a new QueryServiceTestHelper that wraps
2426
// the provided sdk.Context
25-
func NewQueryServerTestHelper(ctx sdk.Context) *QueryServiceTestHelper {
26-
return &QueryServiceTestHelper{GRPCQueryRouter: NewGRPCQueryRouter(), ctx: ctx}
27+
func NewQueryServerTestHelper(ctx sdk.Context, anyUnpacker types.AnyUnpacker) *QueryServiceTestHelper {
28+
qrt := NewGRPCQueryRouter()
29+
qrt.SetAnyUnpacker(anyUnpacker)
30+
return &QueryServiceTestHelper{GRPCQueryRouter: qrt, ctx: ctx}
2731
}
2832

2933
// Invoke implements the grpc ClientConn.Invoke method
@@ -36,12 +40,22 @@ func (q *QueryServiceTestHelper) Invoke(_ gocontext.Context, method string, args
3640
if err != nil {
3741
return err
3842
}
43+
3944
res, err := querier(q.ctx, abci.RequestQuery{Data: reqBz})
45+
if err != nil {
46+
return err
47+
}
4048

49+
err = protoCodec.Unmarshal(res.Value, reply)
4150
if err != nil {
4251
return err
4352
}
44-
return protoCodec.Unmarshal(res.Value, reply)
53+
54+
if q.anyUnpacker != nil {
55+
return types.UnpackInterfaces(reply, q.anyUnpacker)
56+
}
57+
58+
return nil
4559
}
4660

4761
// NewStream implements the grpc ClientConn.NewStream method

baseapp/grpcrouter_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"context"
55
"testing"
66

7+
"github.com/cosmos/cosmos-sdk/codec/types"
8+
79
"github.com/stretchr/testify/require"
810

911
"github.com/cosmos/cosmos-sdk/codec/testdata"
@@ -12,6 +14,8 @@ import (
1214

1315
func TestGRPCRouter(t *testing.T) {
1416
qr := NewGRPCQueryRouter()
17+
interfaceRegistry := testdata.NewTestInterfaceRegistry()
18+
qr.SetAnyUnpacker(interfaceRegistry)
1519
testdata.RegisterTestServiceServer(qr, testdata.TestServiceImpl{})
1620
helper := &QueryServiceTestHelper{
1721
GRPCQueryRouter: qr,
@@ -32,4 +36,12 @@ func TestGRPCRouter(t *testing.T) {
3236
require.Nil(t, err)
3337
require.NotNil(t, res)
3438
require.Equal(t, "Hello Foo!", res2.Greeting)
39+
40+
spot := &testdata.Dog{Name: "Spot", Size_: "big"}
41+
any, err := types.NewAnyWithValue(spot)
42+
require.NoError(t, err)
43+
res3, err := client.TestAny(context.Background(), &testdata.TestAnyRequest{AnyAnimal: any})
44+
require.NoError(t, err)
45+
require.NotNil(t, res3)
46+
require.Equal(t, spot, res3.HasAnimal.Animal.GetCachedValue())
3547
}

client/context.go

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"io"
88
"os"
99

10+
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
11+
1012
"github.com/pkg/errors"
1113
"github.com/spf13/viper"
1214
yaml "gopkg.in/yaml.v2"
@@ -25,29 +27,30 @@ import (
2527
// Context implements a typical context created in SDK modules for transaction
2628
// handling and queries.
2729
type Context struct {
28-
FromAddress sdk.AccAddress
29-
Client rpcclient.Client
30-
ChainID string
31-
JSONMarshaler codec.JSONMarshaler
32-
Input io.Reader
33-
Keyring keyring.Keyring
34-
Output io.Writer
35-
OutputFormat string
36-
Height int64
37-
HomeDir string
38-
From string
39-
BroadcastMode string
40-
FromName string
41-
TrustNode bool
42-
UseLedger bool
43-
Simulate bool
44-
GenerateOnly bool
45-
Offline bool
46-
SkipConfirm bool
47-
TxGenerator TxGenerator
48-
AccountRetriever AccountRetriever
49-
NodeURI string
50-
Verifier tmlite.Verifier
30+
FromAddress sdk.AccAddress
31+
Client rpcclient.Client
32+
ChainID string
33+
JSONMarshaler codec.JSONMarshaler
34+
InterfaceRegistry codectypes.InterfaceRegistry
35+
Input io.Reader
36+
Keyring keyring.Keyring
37+
Output io.Writer
38+
OutputFormat string
39+
Height int64
40+
HomeDir string
41+
From string
42+
BroadcastMode string
43+
FromName string
44+
TrustNode bool
45+
UseLedger bool
46+
Simulate bool
47+
GenerateOnly bool
48+
Offline bool
49+
SkipConfirm bool
50+
TxGenerator TxGenerator
51+
AccountRetriever AccountRetriever
52+
NodeURI string
53+
Verifier tmlite.Verifier
5154

5255
// TODO: Deprecated (remove).
5356
Codec *codec.Codec
@@ -328,6 +331,12 @@ func (ctx Context) WithAccountRetriever(retriever AccountRetriever) Context {
328331
return ctx
329332
}
330333

334+
// WithInterfaceRegistry returns the context with an updated InterfaceRegistry
335+
func (ctx Context) WithInterfaceRegistry(interfaceRegistry codectypes.InterfaceRegistry) Context {
336+
ctx.InterfaceRegistry = interfaceRegistry
337+
return ctx
338+
}
339+
331340
// PrintOutput outputs toPrint to the ctx.Output based on ctx.OutputFormat which is
332341
// either text or json. If text, toPrint will be YAML encoded. Otherwise, toPrint
333342
// will be JSON encoded using ctx.JSONMarshaler. An error is returned upon failure.

client/grpc_query.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
gocontext "context"
55
"fmt"
66

7+
"github.com/cosmos/cosmos-sdk/codec/types"
78
gogogrpc "github.com/gogo/protobuf/grpc"
89
"google.golang.org/grpc"
910
"google.golang.org/grpc/encoding"
@@ -24,7 +25,17 @@ func (ctx Context) Invoke(_ gocontext.Context, method string, args, reply interf
2425
if err != nil {
2526
return err
2627
}
27-
return protoCodec.Unmarshal(resBz, reply)
28+
29+
err = protoCodec.Unmarshal(resBz, reply)
30+
if err != nil {
31+
return err
32+
}
33+
34+
if ctx.InterfaceRegistry != nil {
35+
return types.UnpackInterfaces(reply, ctx.InterfaceRegistry)
36+
}
37+
38+
return nil
2839
}
2940

3041
// NewStream implements the grpc ClientConn.NewStream method

0 commit comments

Comments
 (0)