gRPC gateway init (#7019)

* WIP: grpc server setup

* add register grpc routes

* updated go mod

* updated grpc for all modules

* added pb file for grpc gateway

* udpated gw file

* added a test for grpc route

* fixed conflicts

* added grpc server

* grpc tests added

* cleanup

* Fix gateway forward issue

* Add godoc

* updated tests

* fix lint

* fix tests

* fix tests

* fix tests

* fixed test

* Add grpc headers

* Fix error handling

* Fix tests - hacky

* Fix lint

* remove debug logs

* Fix review comments

* move grpc tests into a separate file

* Fix protobuf version

* Update x/capability/module.go

* Fix godoc

* Fix review suggestions

* Fix codec

* Add query params test for gateway request

* Fix gofmt

Co-authored-by: anilCSE <anil@vitwit.com>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
atheeshp 2020-08-25 21:14:13 +05:30 committed by GitHub
parent 1f7a2787aa
commit 78194e1cdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 423 additions and 11 deletions

View File

@ -27,6 +27,18 @@ func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, args, reply
if err != nil {
return err
}
// parse height header
md, _ := metadata.FromOutgoingContext(grpcCtx)
if heights := md.Get(grpctypes.GRPCBlockHeightHeader); len(heights) > 0 {
height, err := strconv.ParseInt(heights[0], 10, 64)
if err != nil {
return err
}
ctx = ctx.WithHeight(height)
}
req := abci.RequestQuery{
Path: method,
Data: reqBz,
@ -47,7 +59,7 @@ func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, args, reply
// We then parse all the call options, if the call option is a
// HeaderCallOption, then we manually set the value of that header to the
// metadata.
md := metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(res.Height, 10))
md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(res.Height, 10))
for _, callOpt := range opts {
header, ok := callOpt.(grpc.HeaderCallOption)
if !ok {

1
go.mod
View File

@ -14,6 +14,7 @@ require (
github.com/cosmos/iavl v0.15.0-rc2
github.com/cosmos/ledger-cosmos-go v0.11.1
github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25
github.com/gogo/gateway v1.1.0
github.com/gogo/protobuf v1.3.1
github.com/golang/mock v1.4.4
github.com/golang/protobuf v1.4.2

11
go.sum
View File

@ -178,6 +178,8 @@ github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0=
github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@ -213,6 +215,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@ -231,14 +234,10 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/handlers v1.5.0 h1:4wjo3sf9azi99c8hTmyaxp9y5S+pFszsy3pP0rAw/lw=
github.com/gorilla/handlers v1.5.0/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
@ -248,7 +247,9 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.14.7 h1:Nk5kuHrnWUTf/0GL1a/vchH/om9Ap2/HnVna+jYZgTY=
github.com/grpc-ecosystem/grpc-gateway v1.14.7/go.mod h1:oYZKL012gGh6LMyg/xA7Q2yq6j8bu0wa+9w14EEthWU=
@ -740,6 +741,7 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaR
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@ -761,6 +763,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=

View File

@ -7,8 +7,10 @@ import (
"strings"
"time"
"github.com/gogo/gateway"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/rakyll/statik/fs"
"github.com/tendermint/tendermint/libs/log"
tmrpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server"
@ -16,6 +18,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/server/config"
"github.com/cosmos/cosmos-sdk/telemetry"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"github.com/cosmos/cosmos-sdk/types/rest"
// unnamed import of statik for swagger UI support
@ -24,19 +27,54 @@ import (
// Server defines the server's API interface.
type Server struct {
Router *mux.Router
ClientCtx client.Context
Router *mux.Router
GRPCRouter *runtime.ServeMux
ClientCtx client.Context
logger log.Logger
metrics *telemetry.Metrics
listener net.Listener
}
// CustomGRPCHeaderMatcher for mapping request headers to
// GRPC metadata.
// HTTP headers that start with 'Grpc-Metadata-' are automatically mapped to
// gRPC metadata after removing prefix 'Grpc-Metadata-'. We can use this
// CustomGRPCHeaderMatcher if headers don't start with `Grpc-Metadata-`
func CustomGRPCHeaderMatcher(key string) (string, bool) {
switch strings.ToLower(key) {
case grpctypes.GRPCBlockHeightHeader:
return grpctypes.GRPCBlockHeightHeader, true
default:
return runtime.DefaultHeaderMatcher(key)
}
}
func New(clientCtx client.Context, logger log.Logger) *Server {
// The default JSON marshaller used by the gRPC-Gateway is unable to marshal non-nullable non-scalar fields.
// Using the gogo/gateway package with the gRPC-Gateway WithMarshaler option fixes the scalar field marshalling issue.
marshalerOption := &gateway.JSONPb{
EmitDefaults: true,
Indent: " ",
OrigName: true,
}
return &Server{
Router: mux.NewRouter(),
ClientCtx: clientCtx,
logger: logger,
GRPCRouter: runtime.NewServeMux(
// Custom marshaler option is required for gogo proto
runtime.WithMarshalerOption(runtime.MIMEWildcard, marshalerOption),
// This is necessary to get error details properly
// marshalled in unary requests.
runtime.WithProtoErrorHandler(runtime.DefaultHTTPProtoErrorHandler),
// Custom header matcher for mapping request headers to
// GRPC metadata
runtime.WithIncomingHeaderMatcher(CustomGRPCHeaderMatcher),
),
}
}
@ -70,6 +108,7 @@ func (s *Server) Start(cfg config.Config) error {
return err
}
s.registerGRPCRoutes()
s.listener = listener
var h http.Handler = s.Router
@ -93,7 +132,11 @@ func (s *Server) registerSwaggerUI() {
}
staticServer := http.FileServer(statikFS)
s.Router.PathPrefix("/").Handler(staticServer)
s.Router.PathPrefix("/legacy").Handler(staticServer)
}
func (s *Server) registerGRPCRoutes() {
s.Router.PathPrefix("/").Handler(s.GRPCRouter)
}
func (s *Server) registerMetrics() {

View File

@ -240,7 +240,6 @@ func startInProcess(ctx *Context, legacyAminoCdc *codec.LegacyAmino, appCreator
apiSrv = api.New(clientCtx, ctx.Logger.With("module", "api-server"))
app.RegisterAPIRoutes(apiSrv)
errCh := make(chan error)
go func() {

View File

@ -512,6 +512,7 @@ func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server) {
rpc.RegisterRoutes(clientCtx, apiSvr.Router)
authrest.RegisterTxRoutes(clientCtx, apiSvr.Router)
ModuleBasics.RegisterRESTRoutes(clientCtx, apiSvr.Router)
ModuleBasics.RegisterGRPCRoutes(apiSvr.ClientCtx, apiSvr.GRPCRouter)
}
// GetMaccPerms returns a copy of the module account permissions

View File

@ -15,6 +15,7 @@ import (
grpc "github.com/gogo/protobuf/grpc"
gomock "github.com/golang/mock/gomock"
mux "github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
cobra "github.com/spf13/cobra"
types1 "github.com/tendermint/tendermint/abci/types"
)
@ -120,6 +121,18 @@ func (mr *MockAppModuleBasicMockRecorder) RegisterRESTRoutes(arg0, arg1 interfac
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterRESTRoutes), arg0, arg1)
}
// RegisterGRPCRoutes mocks base method
func (m *MockAppModuleBasic) RegisterGRPCRoutes(arg0 client.Context, arg1 *runtime.ServeMux) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RegisterGRPCRoutes", arg0, arg1)
}
// RegisterGRPCRoutes indicates an expected call of RegisterGRPCRoutes
func (mr *MockAppModuleBasicMockRecorder) RegisterGRPCRoutes(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterGRPCRoutes", reflect.TypeOf((*MockAppModuleBasic)(nil).RegisterGRPCRoutes), arg0, arg1)
}
// GetTxCmd mocks base method
func (m *MockAppModuleBasic) GetTxCmd() *cobra.Command {
m.ctrl.T.Helper()
@ -249,6 +262,18 @@ func (mr *MockAppModuleGenesisMockRecorder) RegisterRESTRoutes(arg0, arg1 interf
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModuleGenesis)(nil).RegisterRESTRoutes), arg0, arg1)
}
// RegisterGRPCRoutes mocks base method
func (m *MockAppModuleGenesis) RegisterGRPCRoutes(arg0 client.Context, arg1 *runtime.ServeMux) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RegisterRESTRoutes", arg0, arg1)
}
// RegisterGRPCRoutes indicates an expected call of RegisterGRPCRoutes
func (mr *MockAppModuleGenesisMockRecorder) RegisterGRPCRoutes(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterGRPCRoutes", reflect.TypeOf((*MockAppModuleGenesis)(nil).RegisterGRPCRoutes), arg0, arg1)
}
// GetTxCmd mocks base method
func (m *MockAppModuleGenesis) GetTxCmd() *cobra.Command {
m.ctrl.T.Helper()
@ -406,6 +431,18 @@ func (mr *MockAppModuleMockRecorder) RegisterRESTRoutes(arg0, arg1 interface{})
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRESTRoutes", reflect.TypeOf((*MockAppModule)(nil).RegisterRESTRoutes), arg0, arg1)
}
// RegisterGRPCRoutes mocks base method
func (m *MockAppModule) RegisterGRPCRoutes(arg0 client.Context, arg1 *runtime.ServeMux) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RegisterGRPCRoutes", arg0, arg1)
}
// RegisterGRPCRoutes indicates an expected call of RegisterGRPCRoutes
func (mr *MockAppModuleMockRecorder) RegisterGRPCRoutes(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterGRPCRoutes", reflect.TypeOf((*MockAppModule)(nil).RegisterGRPCRoutes), arg0, arg1)
}
// GetTxCmd mocks base method
func (m *MockAppModule) GetTxCmd() *cobra.Command {
m.ctrl.T.Helper()

38
testutil/rest.go Normal file
View File

@ -0,0 +1,38 @@
package testutil
import (
"io/ioutil"
"net/http"
)
// GetRequestWithHeaders defines a wrapper around an HTTP GET request with a provided URL
// and custom headers
// An error is returned if the request or reading the body fails.
func GetRequestWithHeaders(url string, headers map[string]string) ([]byte, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
client := &http.Client{}
for key, value := range headers {
req.Header.Set(key, value)
}
res, err := client.Do(req)
if err != nil {
return nil, err
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
if err = res.Body.Close(); err != nil {
return nil, err
}
return body, nil
}

View File

@ -32,6 +32,7 @@ import (
"encoding/json"
"github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -56,6 +57,7 @@ type AppModuleBasic interface {
// client functionality
RegisterRESTRoutes(client.Context, *mux.Router)
RegisterGRPCRoutes(client.Context, *runtime.ServeMux)
GetTxCmd() *cobra.Command
GetQueryCmd() *cobra.Command
}
@ -114,6 +116,13 @@ func (bm BasicManager) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rou
}
}
// RegisterGRPCRoutes registers all module rest routes
func (bm BasicManager) RegisterGRPCRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
//
// TODO: Remove clientCtx argument.

View File

@ -6,6 +6,7 @@ import (
"math/rand"
"github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -64,6 +65,10 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rout
rest.RegisterRoutes(clientCtx, rtr, types.StoreKey)
}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the auth module.
func (a AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {
}
// GetTxCmd returns the root tx command for the auth module.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.GetTxCmd()

View File

@ -0,0 +1,93 @@
package rest_test
import (
"fmt"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"github.com/cosmos/cosmos-sdk/x/bank/types"
)
func (s *IntegrationTestSuite) TestTotalSupplyGRPCHandler() {
val := s.network.Validators[0]
baseURL := val.APIAddress
testCases := []struct {
name string
url string
headers map[string]string
respType fmt.Stringer
expected fmt.Stringer
}{
{
"test GRPC total supply",
fmt.Sprintf("%s/cosmos/bank/v1beta1/supply", baseURL),
map[string]string{
grpctypes.GRPCBlockHeightHeader: "1",
},
&types.QueryTotalSupplyResponse{},
&types.QueryTotalSupplyResponse{
Supply: sdk.NewCoins(
sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), s.cfg.AccountTokens),
sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(sdk.NewInt(10))),
),
},
},
{
"GRPC total supply of a specific denom",
fmt.Sprintf("%s/cosmos/bank/v1beta1/supply/%s", baseURL, s.cfg.BondDenom),
map[string]string{
grpctypes.GRPCBlockHeightHeader: "1",
},
&types.QuerySupplyOfResponse{},
&types.QuerySupplyOfResponse{
Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(sdk.NewInt(10))),
},
},
{
"Query for `height` > 1",
fmt.Sprintf("%s/cosmos/bank/v1beta1/supply/%s", baseURL, s.cfg.BondDenom),
map[string]string{
grpctypes.GRPCBlockHeightHeader: "2",
},
&types.QuerySupplyOfResponse{},
&types.QuerySupplyOfResponse{
Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(sdk.NewInt(20))),
},
},
{
"Query params shouldn't be considered as height",
fmt.Sprintf("%s/cosmos/bank/v1beta1/supply/%s?height=2", baseURL, s.cfg.BondDenom),
map[string]string{
grpctypes.GRPCBlockHeightHeader: "1",
},
&types.QuerySupplyOfResponse{},
&types.QuerySupplyOfResponse{
Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(sdk.NewInt(10))),
},
},
{
"GRPC total supply of a bogus denom",
fmt.Sprintf("%s/cosmos/bank/v1beta1/supply/foobar", baseURL),
map[string]string{
grpctypes.GRPCBlockHeightHeader: "1",
},
&types.QuerySupplyOfResponse{},
&types.QuerySupplyOfResponse{
Amount: sdk.NewCoin("foobar", sdk.ZeroInt()),
},
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers)
s.Require().NoError(err)
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, tc.respType))
s.Require().Equal(tc.expected.String(), tc.respType.String())
})
}
}

View File

@ -1,12 +1,14 @@
package bank
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"github.com/gogo/protobuf/grpc"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
@ -61,6 +63,11 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rout
rest.RegisterHandlers(clientCtx, rtr)
}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the bank module.
func (a AppModuleBasic) RegisterGRPCRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx))
}
// GetTxCmd returns the root tx command for the bank module.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.NewTxCmd()

View File

@ -5,15 +5,16 @@ import (
"fmt"
"math/rand"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/gogo/protobuf/grpc"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
@ -71,6 +72,10 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxE
// RegisterRESTRoutes registers the capability module's REST service handlers.
func (a AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the capability module.
func (a AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {
}
// GetTxCmd returns the capability module's root tx command.
func (a AppModuleBasic) GetTxCmd() *cobra.Command { return nil }

View File

@ -6,6 +6,7 @@ import (
"github.com/gogo/protobuf/grpc"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
@ -56,6 +57,9 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxE
// RegisterRESTRoutes registers no REST routes for the crisis module.
func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the capability module.
func (AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {}
// GetTxCmd returns the root tx command for the crisis module.
func (b AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.NewTxCmd()

View File

@ -6,6 +6,7 @@ import (
"math/rand"
"github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -67,6 +68,9 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx sdkclient.Context, rtr *mux.R
rest.RegisterHandlers(clientCtx, rtr)
}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the distribution module.
func (AppModuleBasic) RegisterGRPCRoutes(_ sdkclient.Context, _ *runtime.ServeMux) {}
// GetTxCmd returns the root tx command for the distribution module.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.NewTxCmd()

View File

@ -6,6 +6,7 @@ import (
"math/rand"
"github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -84,6 +85,10 @@ func (a AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Ro
rest.RegisterRoutes(clientCtx, rtr, evidenceRESTHandlers)
}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the evidence module.
func (a AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {
}
// GetTxCmd returns the evidence module's root tx command.
func (a AppModuleBasic) GetTxCmd() *cobra.Command {
evidenceCLIHandlers := make([]*cobra.Command, len(a.evidenceHandlers))

View File

@ -5,6 +5,7 @@ import (
"fmt"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
@ -55,6 +56,10 @@ func (b AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, txEncodingConfi
// RegisterRESTRoutes registers the REST routes for the genutil module.
func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the genutil module.
func (AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {
}
// GetTxCmd returns no root tx command for the genutil module.
func (AppModuleBasic) GetTxCmd() *cobra.Command { return nil }

View File

@ -8,6 +8,7 @@ import (
"math/rand"
"github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -83,6 +84,10 @@ func (a AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Ro
rest.RegisterHandlers(clientCtx, rtr, proposalRESTHandlers)
}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the gov module.
func (a AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {
}
// GetTxCmd returns the root tx command for the gov module.
func (a AppModuleBasic) GetTxCmd() *cobra.Command {
proposalCLIHandlers := make([]*cobra.Command, 0, len(a.proposalHandlers))

View File

@ -6,6 +6,7 @@ import (
"math/rand"
"github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -66,6 +67,10 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxE
func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) {
}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the ibc-transfer module.
func (a AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {
}
// GetTxCmd implements AppModuleBasic interface
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.NewTxCmd()

View File

@ -7,6 +7,7 @@ import (
"github.com/gogo/protobuf/grpc"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
@ -63,6 +64,10 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxE
// RegisterRESTRoutes does nothing. IBC does not support legacy REST routes.
func (AppModuleBasic) RegisterRESTRoutes(client.Context, *mux.Router) {}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the ibc module.
func (a AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {
}
// GetTxCmd returns the root tx command for the ibc module.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.GetTxCmd()

View File

@ -7,6 +7,7 @@ import (
"github.com/gogo/protobuf/grpc"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
@ -68,6 +69,10 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rout
rest.RegisterRoutes(clientCtx, rtr)
}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the mint module.
func (AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {
}
// GetTxCmd returns no root tx command for the mint module.
func (AppModuleBasic) GetTxCmd() *cobra.Command { return nil }

View File

@ -5,6 +5,7 @@ import (
"math/rand"
"github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -54,6 +55,9 @@ func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, config client.TxEnc
// RegisterRESTRoutes registers the REST routes for the params module.
func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the params module.
func (AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {}
// GetTxCmd returns no root tx command for the params module.
func (AppModuleBasic) GetTxCmd() *cobra.Command { return nil }

View File

@ -6,6 +6,7 @@ import (
"math/rand"
"github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -75,6 +76,10 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rout
rest.RegisterHandlers(clientCtx, rtr)
}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the slashig module.
func (AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {
}
// GetTxCmd returns the root tx command for the slashing module.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.NewTxCmd()

View File

@ -0,0 +1,101 @@
package rest_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"github.com/cosmos/cosmos-sdk/x/staking/types"
)
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
cfg := network.DefaultConfig()
cfg.NumValidators = 1
s.cfg = cfg
s.network = network.New(s.T(), cfg)
_, err := s.network.WaitForHeight(1)
s.Require().NoError(err)
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}
func (s *IntegrationTestSuite) TestQueryValidatorsGRPCHandler() {
val := s.network.Validators[0]
baseURL := val.APIAddress
testCases := []struct {
name string
url string
headers map[string]string
error bool
}{
{
"test query validators gRPC route with invalid status",
fmt.Sprintf("%s/cosmos/staking/v1beta1/validators?status=active", baseURL),
map[string]string{
grpctypes.GRPCBlockHeightHeader: "1",
},
true,
},
{
"test query validators gRPC route without status query param",
fmt.Sprintf("%s/cosmos/staking/v1beta1/validators", baseURL),
map[string]string{
grpctypes.GRPCBlockHeightHeader: "1",
},
true,
},
{
"test query validators gRPC route with valid status",
fmt.Sprintf("%s/cosmos/staking/v1beta1/validators?status=%s", baseURL, sdk.Bonded.String()),
map[string]string{
grpctypes.GRPCBlockHeightHeader: "1",
},
false,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers)
s.Require().NoError(err)
var valRes types.QueryValidatorsResponse
err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(resp, &valRes)
if tc.error {
s.Require().Error(err)
s.Require().Nil(valRes.Validators)
s.Require().Equal(0, len(valRes.Validators))
} else {
s.Require().NoError(err)
s.Require().NotNil(valRes.Validators)
s.Require().Equal(len(s.network.Validators), len(valRes.Validators))
}
})
}
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}

View File

@ -1,11 +1,13 @@
package staking
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -73,6 +75,11 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rout
rest.RegisterHandlers(clientCtx, rtr)
}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the staking module.
func (AppModuleBasic) RegisterGRPCRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx))
}
// GetTxCmd returns the root tx command for the staking module.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.NewTxCmd()

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -51,6 +52,9 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, r *mux.Router
rest.RegisterRoutes(clientCtx, r)
}
// RegisterGRPCRoutes registers the gRPC Gateway routes for the upgrade module.
func (AppModuleBasic) RegisterGRPCRoutes(_ client.Context, _ *runtime.ServeMux) {}
// GetQueryCmd returns the cli query commands for this module
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
return cli.GetQueryCmd()