Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/evidence: gRPC query service #6593

Merged
merged 14 commits into from
Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions proto/cosmos/evidence/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
syntax = "proto3";
package cosmos.evidence;

import "cosmos/query/pagination.proto";
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/evidence/types";

// Query defines the gRPC querier service
service Query {
// Evidence queries evidence based on evidence hash
rpc Evidence(QueryEvidenceRequest) returns (QueryEvidenceResponse) {}

// AllEvidence queries all evidence
rpc AllEvidence(QueryAllEvidenceRequest) returns (QueryAllEvidenceResponse) {}
}

// QueryEvidenceRequest is the request type for the Query/Evidence RPC method
message QueryEvidenceRequest {
bytes evidence_hash = 1 [(gogoproto.casttype) = "github.com/tendermint/tendermint/libs/bytes.HexBytes"];;
}

// QueryEvidenceResponse is the response type for the Query/Evidence RPC method
message QueryEvidenceResponse {
google.protobuf.Any evidence = 1;
}

// QueryEvidenceRequest is the request type for the Query/AllEvidence RPC method
message QueryAllEvidenceRequest {
cosmos.query.PageRequest req = 1;
}

// QueryAllEvidenceResponse is the response type for the Query/AllEvidence RPC method
message QueryAllEvidenceResponse {
repeated google.protobuf.Any evidence = 1;

cosmos.query.PageResponse res = 2;
}
1 change: 1 addition & 0 deletions store/rootmulti/internal/proofs/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"sort"

ics23 "github.com/confio/ics23/go"

sdkmaps "github.com/cosmos/cosmos-sdk/store/rootmulti/internal/maps"
)

Expand Down
5 changes: 3 additions & 2 deletions x/evidence/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,12 @@ func QueryEvidenceCmd(cdc *codec.Codec) func(*cobra.Command, []string) error {
}

func queryEvidence(cdc *codec.Codec, clientCtx client.Context, hash string) error {
if _, err := hex.DecodeString(hash); err != nil {
decodedHash, err := hex.DecodeString(hash)
if err != nil {
return fmt.Errorf("invalid evidence hash: %w", err)
}

params := types.NewQueryEvidenceParams(hash)
params := types.NewQueryEvidenceRequest(decodedHash)
bz, err := cdc.MarshalJSON(params)
if err != nil {
return fmt.Errorf("failed to marshal query params: %w", err)
Expand Down
9 changes: 8 additions & 1 deletion x/evidence/client/rest/query.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package rest

import (
"encoding/hex"
"fmt"
"net/http"
"strings"
Expand Down Expand Up @@ -39,7 +40,13 @@ func queryEvidenceHandler(clientCtx client.Context) http.HandlerFunc {
return
}

params := types.NewQueryEvidenceParams(evidenceHash)
decodedHash, err := hex.DecodeString(evidenceHash)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, "invalid evidence hash")
return
}

params := types.NewQueryEvidenceRequest(decodedHash)
bz, err := clientCtx.JSONMarshaler.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err))
Expand Down
88 changes: 88 additions & 0 deletions x/evidence/keeper/grpc_query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package keeper

import (
"context"

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

"github.com/cosmos/cosmos-sdk/store/prefix"
"github.com/cosmos/cosmos-sdk/types/query"

proto "github.com/gogo/protobuf/proto"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/evidence/types"
)

var _ types.QueryServer = Keeper{}

// Evidence implements the Query/Evidence gRPC method
func (k Keeper) Evidence(c context.Context, req *types.QueryEvidenceRequest) (*types.QueryEvidenceResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}

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

ctx := sdk.UnwrapSDKContext(c)

evidence, _ := k.GetEvidence(ctx, req.EvidenceHash)
if evidence == nil {
return nil, status.Errorf(codes.NotFound, "evidence %s not found", req.EvidenceHash)
}

msg, ok := evidence.(proto.Message)
if !ok {
return nil, status.Errorf(codes.Internal, "can't protomarshal %T", msg)
}

evidenceAny, err := codectypes.NewAnyWithValue(msg)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
}

return &types.QueryEvidenceResponse{Evidence: evidenceAny}, nil
}

// AllEvidence implements the Query/AllEvidence gRPC method
func (k Keeper) AllEvidence(c context.Context, req *types.QueryAllEvidenceRequest) (*types.QueryAllEvidenceResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}
ctx := sdk.UnwrapSDKContext(c)

k.GetAllEvidence(ctx)

var evidence []*codectypes.Any
store := ctx.KVStore(k.storeKey)
evidenceStore := prefix.NewStore(store, types.KeyPrefixEvidence)

res, err := query.Paginate(evidenceStore, req.Req, func(key []byte, value []byte) error {
result, err := k.UnmarshalEvidence(value)
if err != nil {
return err
}

msg, ok := result.(proto.Message)
if !ok {
return status.Errorf(codes.Internal, "can't protomarshal %T", msg)
}

evidenceAny, err := codectypes.NewAnyWithValue(msg)
if err != nil {
return err
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto unregistered evidence test case

}
evidence = append(evidence, evidenceAny)
return nil
})

if err != nil {
return &types.QueryAllEvidenceResponse{}, err
}

return &types.QueryAllEvidenceResponse{Evidence: evidence, Res: res}, nil
}
143 changes: 143 additions & 0 deletions x/evidence/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package keeper_test

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/x/evidence/exported"
"github.com/cosmos/cosmos-sdk/x/evidence/types"

tmbytes "github.com/tendermint/tendermint/libs/bytes"
)

func (suite *KeeperTestSuite) TestQueryEvidence() {
var (
req *types.QueryEvidenceRequest
evidence []exported.Evidence
)

testCases := []struct {
msg string
malleate func()
expPass bool
posttests func(res *types.QueryEvidenceResponse)
}{
{
"empty request",
func() {
req = &types.QueryEvidenceRequest{}
},
false,
func(res *types.QueryEvidenceResponse) {},
},
{
"invalid request with empty evidence hash",
func() {
req = &types.QueryEvidenceRequest{EvidenceHash: tmbytes.HexBytes{}}
},
false,
func(res *types.QueryEvidenceResponse) {},
},
{
"success",
func() {
numEvidence := 100
evidence = suite.populateEvidence(suite.ctx, numEvidence)
req = types.NewQueryEvidenceRequest(evidence[0].Hash())
},
true,
func(res *types.QueryEvidenceResponse) {
var evi exported.Evidence
err := suite.app.InterfaceRegistry().UnpackAny(res.Evidence, &evi)
suite.Require().NoError(err)
suite.Require().NotNil(evi)
suite.Require().Equal(evi, evidence[0])
},
},
}

for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest()

tc.malleate()
ctx := sdk.WrapSDKContext(suite.ctx)

res, err := suite.queryClient.Evidence(ctx, req)

if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
} else {
suite.Require().Error(err)
suite.Require().Nil(res)
}

tc.posttests(res)
})
}
}

func (suite *KeeperTestSuite) TestQueryAllEvidence() {
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
var (
req *types.QueryAllEvidenceRequest
)

testCases := []struct {
msg string
malleate func()
expPass bool
posttests func(res *types.QueryAllEvidenceResponse)
}{
{
"success without evidence",
func() {
req = &types.QueryAllEvidenceRequest{}
},
true,
func(res *types.QueryAllEvidenceResponse) {
suite.Require().Empty(res.Evidence)
},
},
{
"success",
func() {
numEvidence := 100
_ = suite.populateEvidence(suite.ctx, numEvidence)
pageReq := &query.PageRequest{
Key: nil,
Limit: 50,
CountTotal: false,
}
req = types.NewQueryAllEvidenceRequest(pageReq)
},
true,
func(res *types.QueryAllEvidenceResponse) {
suite.Equal(len(res.Evidence), 50)
suite.NotNil(res.Res.NextKey)
},
},
}

for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest()

tc.malleate()
ctx := sdk.WrapSDKContext(suite.ctx)

res, err := suite.queryClient.AllEvidence(ctx, req)

if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
} else {
suite.Require().Error(err)
suite.Require().Nil(res)
}

tc.posttests(res)
})
}
}
7 changes: 7 additions & 0 deletions x/evidence/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"
"time"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
Expand Down Expand Up @@ -73,6 +74,8 @@ type KeeperTestSuite struct {
ctx sdk.Context
querier sdk.Querier
app *simapp.SimApp

queryClient types.QueryClient
}

func (suite *KeeperTestSuite) SetupTest() {
Expand All @@ -97,6 +100,10 @@ func (suite *KeeperTestSuite) SetupTest() {
addr := sdk.AccAddress(addr)
app.AccountKeeper.SetAccount(suite.ctx, authtypes.NewBaseAccount(addr, pubkeys[i], uint64(i), 0))
}

queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, app.EvidenceKeeper)
suite.queryClient = types.NewQueryClient(queryHelper)
}

func (suite *KeeperTestSuite) populateEvidence(ctx sdk.Context, numEvidence int) []exported.Evidence {
Expand Down
13 changes: 3 additions & 10 deletions x/evidence/keeper/querier.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package keeper

import (
"encoding/hex"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -36,21 +34,16 @@ func NewQuerier(k Keeper) sdk.Querier {
}

func queryEvidence(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryEvidenceParams
var params types.QueryEvidenceRequest

err := k.cdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}

hash, err := hex.DecodeString(params.EvidenceHash)
if err != nil {
return nil, sdkerrors.Wrap(err, "failed to decode evidence hash string query")
}

evidence, ok := k.GetEvidence(ctx, hash)
evidence, ok := k.GetEvidence(ctx, params.EvidenceHash)
if !ok {
return nil, sdkerrors.Wrap(types.ErrNoEvidenceExists, params.EvidenceHash)
return nil, sdkerrors.Wrap(types.ErrNoEvidenceExists, params.EvidenceHash.String())
}

res, err := codec.MarshalJSONIndent(k.cdc, evidence)
Expand Down
Loading