x/evidence: gRPC query service (#6593)
* Add basic grpc query service for x/evidence * Add grpc query test for AllEvidences query * linting * Add AnyUnpacker to query test helper and some var renaming * Add test to check Evidence query result * Update proto/cosmos/evidence/query.proto Co-authored-by: Amaury Martiny <amaury.martiny@protonmail.com> * Use table tests * Use NewQueryEvidenceRequest in place of QueryEvidenceParams * Remove ConvertEvidence Co-authored-by: Amaury Martiny <amaury.martiny@protonmail.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
parent
59cd0659a5
commit
1e23679066
|
@ -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;
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"sort"
|
||||
|
||||
ics23 "github.com/confio/ics23/go"
|
||||
|
||||
sdkmaps "github.com/cosmos/cosmos-sdk/store/rootmulti/internal/maps"
|
||||
)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
@ -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))
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
evidence = append(evidence, evidenceAny)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return &types.QueryAllEvidenceResponse{}, err
|
||||
}
|
||||
|
||||
return &types.QueryAllEvidenceResponse{Evidence: evidence, Res: res}, nil
|
||||
}
|
|
@ -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() {
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
@ -73,6 +74,8 @@ type KeeperTestSuite struct {
|
|||
ctx sdk.Context
|
||||
querier sdk.Querier
|
||||
app *simapp.SimApp
|
||||
|
||||
queryClient types.QueryClient
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) SetupTest() {
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
|
@ -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, ¶ms)
|
||||
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)
|
||||
|
|
|
@ -15,7 +15,7 @@ const (
|
|||
custom = "custom"
|
||||
)
|
||||
|
||||
func (suite *KeeperTestSuite) TestQueryEvidence_Existing() {
|
||||
func (suite *KeeperTestSuite) TestQuerier_QueryEvidence_Existing() {
|
||||
ctx := suite.ctx.WithIsCheckTx(false)
|
||||
numEvidence := 100
|
||||
cdc, _ := simapp.MakeCodecs()
|
||||
|
@ -23,7 +23,7 @@ func (suite *KeeperTestSuite) TestQueryEvidence_Existing() {
|
|||
evidence := suite.populateEvidence(ctx, numEvidence)
|
||||
query := abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryEvidence}, "/"),
|
||||
Data: cdc.MustMarshalJSON(types.NewQueryEvidenceParams(evidence[0].Hash().String())),
|
||||
Data: cdc.MustMarshalJSON(types.NewQueryEvidenceRequest(evidence[0].Hash())),
|
||||
}
|
||||
|
||||
bz, err := suite.querier(ctx, []string{types.QueryEvidence}, query)
|
||||
|
@ -35,7 +35,7 @@ func (suite *KeeperTestSuite) TestQueryEvidence_Existing() {
|
|||
suite.Equal(evidence[0], e)
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestQueryEvidence_NonExisting() {
|
||||
func (suite *KeeperTestSuite) TestQuerier_QueryEvidence_NonExisting() {
|
||||
ctx := suite.ctx.WithIsCheckTx(false)
|
||||
cdc, _ := simapp.MakeCodecs()
|
||||
numEvidence := 100
|
||||
|
@ -43,7 +43,7 @@ func (suite *KeeperTestSuite) TestQueryEvidence_NonExisting() {
|
|||
suite.populateEvidence(ctx, numEvidence)
|
||||
query := abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryEvidence}, "/"),
|
||||
Data: cdc.MustMarshalJSON(types.NewQueryEvidenceParams("0000000000000000000000000000000000000000000000000000000000000000")),
|
||||
Data: cdc.MustMarshalJSON(types.NewQueryEvidenceRequest([]byte("0000000000000000000000000000000000000000000000000000000000000000"))),
|
||||
}
|
||||
|
||||
bz, err := suite.querier(ctx, []string{types.QueryEvidence}, query)
|
||||
|
@ -51,7 +51,7 @@ func (suite *KeeperTestSuite) TestQueryEvidence_NonExisting() {
|
|||
suite.Nil(bz)
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestQueryAllEvidence() {
|
||||
func (suite *KeeperTestSuite) TestQuerier_QueryAllEvidence() {
|
||||
ctx := suite.ctx.WithIsCheckTx(false)
|
||||
cdc, _ := simapp.MakeCodecs()
|
||||
numEvidence := 100
|
||||
|
@ -71,7 +71,7 @@ func (suite *KeeperTestSuite) TestQueryAllEvidence() {
|
|||
suite.Len(e, numEvidence)
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestQueryAllEvidence_InvalidPagination() {
|
||||
func (suite *KeeperTestSuite) TestQuerier_QueryAllEvidence_InvalidPagination() {
|
||||
ctx := suite.ctx.WithIsCheckTx(false)
|
||||
cdc, _ := simapp.MakeCodecs()
|
||||
numEvidence := 100
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
|
||||
query "github.com/cosmos/cosmos-sdk/types/query"
|
||||
)
|
||||
|
||||
// Querier routes for the evidence module
|
||||
const (
|
||||
QueryEvidence = "evidence"
|
||||
QueryAllEvidence = "all_evidence"
|
||||
)
|
||||
|
||||
// QueryEvidenceParams defines the parameters necessary for querying Evidence.
|
||||
type QueryEvidenceParams struct {
|
||||
EvidenceHash string `json:"evidence_hash" yaml:"evidence_hash"`
|
||||
// NewQueryEvidenceRequest creates a new instance of QueryEvidenceRequest.
|
||||
func NewQueryEvidenceRequest(hash tmbytes.HexBytes) *QueryEvidenceRequest {
|
||||
return &QueryEvidenceRequest{EvidenceHash: hash}
|
||||
}
|
||||
|
||||
func NewQueryEvidenceParams(hash string) QueryEvidenceParams {
|
||||
return QueryEvidenceParams{EvidenceHash: hash}
|
||||
// NewQueryAllEvidenceRequest creates a new instance of QueryAllEvidenceRequest.
|
||||
func NewQueryAllEvidenceRequest(req *query.PageRequest) *QueryAllEvidenceRequest {
|
||||
return &QueryAllEvidenceRequest{Req: req}
|
||||
}
|
||||
|
||||
// QueryAllEvidenceParams defines the parameters necessary for querying for all Evidence.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,8 +7,8 @@ import (
|
|||
context "context"
|
||||
fmt "fmt"
|
||||
github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types"
|
||||
grpc1 "github.com/gogo/protobuf/grpc"
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
grpc1 "github.com/gogo/protobuf/grpc"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
|
|
Loading…
Reference in New Issue