Skip to content

Commit

Permalink
Add basic x/bank gRPC query service (#6343)
Browse files Browse the repository at this point in the history
* Add basic x/bank gRPC query server

* proto lint

* Add pb.go file

* cleanup

* add separate grpc query tests

* Add request validation

* Use gRPC status errors

Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com>
  • Loading branch information
aaronc and alexanderbez committed Jun 5, 2020
1 parent 6139c04 commit 72925fa
Show file tree
Hide file tree
Showing 12 changed files with 2,073 additions and 30 deletions.
1 change: 1 addition & 0 deletions buf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ lint:
- UNARY_RPC
- COMMENT_FIELD
- PACKAGE_DIRECTORY_MATCH
- SERVICE_SUFFIX
ignore:
- third_party
- codec/testdata
Expand Down
9 changes: 4 additions & 5 deletions x/bank/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ var (
NewBaseKeeper = keeper.NewBaseKeeper
NewBaseSendKeeper = keeper.NewBaseSendKeeper
NewBaseViewKeeper = keeper.NewBaseViewKeeper
NewQuerier = keeper.NewQuerier
RegisterCodec = types.RegisterCodec
ErrNoInputs = types.ErrNoInputs
ErrNoOutputs = types.ErrNoOutputs
Expand All @@ -44,8 +43,8 @@ var (
NewOutput = types.NewOutput
ValidateInputsOutputs = types.ValidateInputsOutputs
ParamKeyTable = types.ParamKeyTable
NewQueryBalanceParams = types.NewQueryBalanceParams
NewQueryAllBalancesParams = types.NewQueryAllBalancesParams
NewQueryBalanceRequest = types.NewQueryBalanceRequest
NewQueryAllBalancesRequest = types.NewQueryAllBalancesRequest
ModuleCdc = types.ModuleCdc
ParamStoreKeySendEnabled = types.ParamStoreKeySendEnabled
BalancesPrefix = types.BalancesPrefix
Expand All @@ -67,8 +66,8 @@ type (
MsgMultiSend = types.MsgMultiSend
Input = types.Input
Output = types.Output
QueryBalanceParams = types.QueryBalanceParams
QueryAllBalancesParams = types.QueryAllBalancesParams
QueryBalanceRequest = types.QueryBalanceRequest
QueryAllBalancesRequest = types.QueryAllBalancesRequest
GenesisBalancesIterator = types.GenesisBalancesIterator
Keeper = keeper.Keeper
GenesisState = types.GenesisState
Expand Down
4 changes: 2 additions & 2 deletions x/bank/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ func GetBalancesCmd(cdc *codec.Codec) *cobra.Command {

denom := viper.GetString(flagDenom)
if denom == "" {
params = types.NewQueryAllBalancesParams(addr)
params = types.NewQueryAllBalancesRequest(addr)
route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAllBalances)
} else {
params = types.NewQueryBalanceParams(addr, denom)
params = types.NewQueryBalanceRequest(addr, denom)
route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryBalance)
}

Expand Down
4 changes: 2 additions & 2 deletions x/bank/client/rest/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ func QueryBalancesRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {

denom := r.FormValue("denom")
if denom == "" {
params = types.NewQueryAllBalancesParams(addr)
params = types.NewQueryAllBalancesRequest(addr)
route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAllBalances)
} else {
params = types.NewQueryBalanceParams(addr, denom)
params = types.NewQueryBalanceRequest(addr, denom)
route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryBalance)
}

Expand Down
73 changes: 73 additions & 0 deletions x/bank/keeper/grpc_query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package keeper

import (
"context"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank/types"
)

var _ types.QueryServer = BaseKeeper{}

// Balance implements the Query/Balance gRPC method
func (q BaseKeeper) Balance(c context.Context, req *types.QueryBalanceRequest) (*types.QueryBalanceResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}

if len(req.Address) == 0 {
return nil, status.Errorf(codes.InvalidArgument, "invalid address")
}

if req.Denom == "" {
return nil, status.Errorf(codes.InvalidArgument, "invalid denom")
}

ctx := sdk.UnwrapSDKContext(c)
balance := q.GetBalance(ctx, req.Address, req.Denom)

return &types.QueryBalanceResponse{Balance: &balance}, nil
}

// AllBalances implements the Query/AllBalances gRPC method
func (q BaseKeeper) AllBalances(c context.Context, req *types.QueryAllBalancesRequest) (*types.QueryAllBalancesResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}

if len(req.Address) == 0 {
return nil, status.Errorf(codes.InvalidArgument, "invalid address")
}

ctx := sdk.UnwrapSDKContext(c)
balances := q.GetAllBalances(ctx, req.Address)

return &types.QueryAllBalancesResponse{Balances: balances}, nil
}

// TotalSupply implements the Query/TotalSupply gRPC method
func (q BaseKeeper) TotalSupply(c context.Context, _ *types.QueryTotalSupplyRequest) (*types.QueryTotalSupplyResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
totalSupply := q.GetSupply(ctx).GetTotal()

return &types.QueryTotalSupplyResponse{Supply: totalSupply}, nil
}

// SupplyOf implements the Query/SupplyOf gRPC method
func (q BaseKeeper) SupplyOf(c context.Context, req *types.QuerySupplyOfRequest) (*types.QuerySupplyOfResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}

if req.Denom == "" {
return nil, status.Errorf(codes.InvalidArgument, "invalid denom")
}

ctx := sdk.UnwrapSDKContext(c)
supply := q.GetSupply(ctx).GetTotal().AmountOf(req.Denom)

return &types.QuerySupplyOfResponse{Amount: supply}, nil
}
110 changes: 110 additions & 0 deletions x/bank/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package keeper_test

import (
gocontext "context"

"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/bank/types"
)

func (suite *IntegrationTestSuite) TestQueryBalance() {
app, ctx := suite.app, suite.ctx
_, _, addr := authtypes.KeyTestPubAddr()

queryHelper := baseapp.NewQueryServerTestHelper(ctx)
types.RegisterQueryServer(queryHelper, app.BankKeeper)
queryClient := types.NewQueryClient(queryHelper)

_, err := queryClient.Balance(gocontext.Background(), &types.QueryBalanceRequest{})
suite.Require().Error(err)

_, err = queryClient.Balance(gocontext.Background(), &types.QueryBalanceRequest{Address: addr})
suite.Require().Error(err)

req := types.NewQueryBalanceRequest(addr, fooDenom)
res, err := queryClient.Balance(gocontext.Background(), req)
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.True(res.Balance.IsZero())

origCoins := sdk.NewCoins(newFooCoin(50), newBarCoin(30))
acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr)

app.AccountKeeper.SetAccount(ctx, acc)
suite.Require().NoError(app.BankKeeper.SetBalances(ctx, acc.GetAddress(), origCoins))

res, err = queryClient.Balance(gocontext.Background(), req)
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.True(res.Balance.IsEqual(newFooCoin(50)))
}

func (suite *IntegrationTestSuite) TestQueryAllBalances() {
app, ctx := suite.app, suite.ctx
_, _, addr := authtypes.KeyTestPubAddr()

queryHelper := baseapp.NewQueryServerTestHelper(ctx)
types.RegisterQueryServer(queryHelper, app.BankKeeper)
queryClient := types.NewQueryClient(queryHelper)

_, err := queryClient.AllBalances(gocontext.Background(), &types.QueryAllBalancesRequest{})
suite.Require().Error(err)

req := types.NewQueryAllBalancesRequest(addr)
res, err := queryClient.AllBalances(gocontext.Background(), req)
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.True(res.Balances.IsZero())

origCoins := sdk.NewCoins(newFooCoin(50), newBarCoin(30))
acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr)

app.AccountKeeper.SetAccount(ctx, acc)
suite.Require().NoError(app.BankKeeper.SetBalances(ctx, acc.GetAddress(), origCoins))

res, err = queryClient.AllBalances(gocontext.Background(), req)
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.True(res.Balances.IsEqual(origCoins))
}

func (suite *IntegrationTestSuite) TestQueryTotalSupply() {
app, ctx := suite.app, suite.ctx
expectedTotalSupply := bank.NewSupply(sdk.NewCoins(sdk.NewInt64Coin("test", 400000000)))
app.BankKeeper.SetSupply(ctx, expectedTotalSupply)

queryHelper := baseapp.NewQueryServerTestHelper(ctx)
types.RegisterQueryServer(queryHelper, app.BankKeeper)
queryClient := types.NewQueryClient(queryHelper)

res, err := queryClient.TotalSupply(gocontext.Background(), &types.QueryTotalSupplyRequest{})
suite.Require().NoError(err)
suite.Require().NotNil(res)

suite.Require().Equal(expectedTotalSupply.Total, res.Supply)
}

func (suite *IntegrationTestSuite) TestQueryTotalSupplyOf() {
app, ctx := suite.app, suite.ctx

test1Supply := sdk.NewInt64Coin("test1", 4000000)
test2Supply := sdk.NewInt64Coin("test2", 700000000)
expectedTotalSupply := bank.NewSupply(sdk.NewCoins(test1Supply, test2Supply))
app.BankKeeper.SetSupply(ctx, expectedTotalSupply)

queryHelper := baseapp.NewQueryServerTestHelper(ctx)
types.RegisterQueryServer(queryHelper, app.BankKeeper)
queryClient := types.NewQueryClient(queryHelper)

_, err := queryClient.SupplyOf(gocontext.Background(), &types.QuerySupplyOfRequest{})
suite.Require().Error(err)

res, err := queryClient.SupplyOf(gocontext.Background(), &types.QuerySupplyOfRequest{Denom: test1Supply.Denom})
suite.Require().NoError(err)
suite.Require().NotNil(res)

suite.Require().Equal(test1Supply.Amount, res.Amount)
}
2 changes: 2 additions & 0 deletions x/bank/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type Keeper interface {
UnmarshalSupply(bz []byte) (exported.SupplyI, error)
MarshalSupplyJSON(supply exported.SupplyI) ([]byte, error)
UnmarshalSupplyJSON(bz []byte) (exported.SupplyI, error)

types.QueryServer
}

// BaseKeeper manages transfers between accounts. It implements the Keeper interface.
Expand Down
4 changes: 2 additions & 2 deletions x/bank/keeper/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func NewQuerier(k Keeper) sdk.Querier {
}

func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryBalanceParams
var params types.QueryBalanceRequest

if err := types.ModuleCdc.UnmarshalJSON(req.Data, &params); err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
Expand All @@ -50,7 +50,7 @@ func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, err
}

func queryAllBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryAllBalancesParams
var params types.QueryAllBalancesRequest

if err := types.ModuleCdc.UnmarshalJSON(req.Data, &params); err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
Expand Down
4 changes: 2 additions & 2 deletions x/bank/keeper/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func (suite *IntegrationTestSuite) TestQuerier_QueryBalance() {
suite.Require().NotNil(err)
suite.Require().Nil(res)

req.Data = app.Codec().MustMarshalJSON(types.NewQueryBalanceParams(addr, fooDenom))
req.Data = app.Codec().MustMarshalJSON(types.NewQueryBalanceRequest(addr, fooDenom))
res, err = querier(ctx, []string{types.QueryBalance}, req)
suite.Require().NoError(err)
suite.Require().NotNil(res)
Expand Down Expand Up @@ -62,7 +62,7 @@ func (suite *IntegrationTestSuite) TestQuerier_QueryAllBalances() {
suite.Require().NotNil(err)
suite.Require().Nil(res)

req.Data = app.Codec().MustMarshalJSON(types.NewQueryAllBalancesParams(addr))
req.Data = app.Codec().MustMarshalJSON(types.NewQueryAllBalancesRequest(addr))
res, err = querier(ctx, []string{types.QueryAllBalances}, req)
suite.Require().NoError(err)
suite.Require().NotNil(res)
Expand Down
23 changes: 6 additions & 17 deletions x/bank/types/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,14 @@ const (
QuerySupplyOf = "supply_of"
)

// QueryBalanceParams defines the params for querying an account balance.
type QueryBalanceParams struct {
Address sdk.AccAddress
Denom string
// NewQueryBalanceRequest creates a new instance of QueryBalanceRequest.
func NewQueryBalanceRequest(addr sdk.AccAddress, denom string) *QueryBalanceRequest {
return &QueryBalanceRequest{Address: addr, Denom: denom}
}

// NewQueryBalanceParams creates a new instance of QueryBalanceParams.
func NewQueryBalanceParams(addr sdk.AccAddress, denom string) QueryBalanceParams {
return QueryBalanceParams{Address: addr, Denom: denom}
}

// QueryAllBalancesParams defines the params for querying all account balances
type QueryAllBalancesParams struct {
Address sdk.AccAddress
}

// NewQueryAllBalancesParams creates a new instance of QueryAllBalancesParams.
func NewQueryAllBalancesParams(addr sdk.AccAddress) QueryAllBalancesParams {
return QueryAllBalancesParams{Address: addr}
// NewQueryAllBalancesRequest creates a new instance of QueryAllBalancesRequest.
func NewQueryAllBalancesRequest(addr sdk.AccAddress) *QueryAllBalancesRequest {
return &QueryAllBalancesRequest{Address: addr}
}

// QueryTotalSupply defines the params for the following queries:
Expand Down
Loading

0 comments on commit 72925fa

Please sign in to comment.