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/Slashing: gRPC query service #6597

Merged
merged 13 commits into from
Jul 6, 2020
52 changes: 52 additions & 0 deletions proto/cosmos/slashing/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
syntax = "proto3";
package cosmos.slashing;

import "cosmos/query/pagination.proto";
import "gogoproto/gogo.proto";
import "cosmos/slashing/slashing.proto";

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

// Query provides defines the gRPC querier service
service Query {
// Params queries the parameters of slashing module
rpc Params (QueryParamsRequest) returns (QueryParamsResponse){}

// SigningInfo queries the signing info of given cons address
rpc SigningInfo (QuerySigningInfoRequest) returns (QuerySigningInfoResponse) {}

// SigningInfos queries signing info of all validators
rpc SigningInfos (QuerySigningInfosRequest) returns (QuerySigningInfosResponse) {}
}

// QueryParamsRequest is the request type for the Query/Parameters RPC method
message QueryParamsRequest{}

// QueryParamsResponse is the response type for the Query/Parameters RPC method
message QueryParamsResponse{
cosmos.slashing.Params params = 1[(gogoproto.nullable) = false];
}

// QuerySigningInfoRequest is the request type for the Query/SigningInfo RPC method
message QuerySigningInfoRequest{
// cons_address is the address to query signing info of
bytes cons_address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ConsAddress"];
}

// QuerySigningInfoResponse is the response type for the Query/SigningInfo RPC method
message QuerySigningInfoResponse{
// val_signing_info is the signing info of requested val cons address
cosmos.slashing.ValidatorSigningInfo val_signing_info = 1[(gogoproto.nullable)= false];
}

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

// QuerySigningInfosResponse is the response type for the Query/SigningInfos RPC method
message QuerySigningInfosResponse{
// info is the signing info of all validators
repeated cosmos.slashing.ValidatorSigningInfo info = 1[(gogoproto.nullable)= false];
cosmos.query.PageResponse res =2;
}
23 changes: 23 additions & 0 deletions proto/cosmos/slashing/slashing.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ option go_package = "github.com/cosmos/cosmos-sdk/x/slashing/types";
option (gogoproto.equal_all) = true;

import "gogoproto/gogo.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";

// MsgUnjail - struct for unjailing jailed validator
Expand Down Expand Up @@ -40,3 +41,25 @@ message ValidatorSigningInfo {
// missed blocks counter (to avoid scanning the array every time)
int64 missed_blocks_counter = 6 [(gogoproto.moretags) = "yaml:\"missed_blocks_counter\""];
}

// Params - used for initializing default parameter for slashing at genesis
message Params{
int64 signed_blocks_window = 1 [(gogoproto.jsontag) = "json:\"signed_blocks_window\"",
(gogoproto.moretags) = "yaml:\"signed_blocks_window\""];
bytes min_signed_per_window = 2 [(gogoproto.jsontag) = "json:\"min_signed_per_window\"",
(gogoproto.moretags) = "yaml:\"min_signed_per_window\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false];
google.protobuf.Duration downtime_jail_duration = 3 [(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.jsontag) = "json:\"downtime_jail_duration\"",
(gogoproto.moretags) = "yaml:\"downtime_jail_duration\""];
bytes slash_fraction_double_sign = 4 [(gogoproto.jsontag) = "json:\"slash_fraction_double_sign\"",
(gogoproto.moretags) = "yaml:\"slash_fraction_double_sign\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false];
bytes slash_fraction_downtime = 5 [(gogoproto.jsontag) = "json:\"slash_fraction_downtime\"",
(gogoproto.moretags) = "yaml:\"slash_fraction_downtime\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false];
}
69 changes: 69 additions & 0 deletions x/slashing/keeper/grpc_query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package keeper

import (
"context"

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

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

var _ types.QueryServer = Keeper{}

func (k Keeper) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}

ctx := sdk.UnwrapSDKContext(c)
params := k.GetParams(ctx)

return &types.QueryParamsResponse{Params: params}, nil
}

func (k Keeper) SigningInfo(c context.Context, req *types.QuerySigningInfoRequest) (*types.QuerySigningInfoResponse, error) {
sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}

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

ctx := sdk.UnwrapSDKContext(c)
signingInfo, found := k.GetValidatorSigningInfo(ctx, req.ConsAddress)
if !found {
return nil, status.Errorf(codes.NotFound, "SigningInfo not found for validator %s", req.ConsAddress)
}

return &types.QuerySigningInfoResponse{ValSigningInfo: signingInfo}, nil
}

func (k Keeper) SigningInfos(c context.Context, req *types.QuerySigningInfosRequest) (*types.QuerySigningInfosResponse, error) {
sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}

ctx := sdk.UnwrapSDKContext(c)
store := ctx.KVStore(k.storeKey)
var signInfos []types.ValidatorSigningInfo

sigInfoStore := prefix.NewStore(store, types.ValidatorSigningInfoKeyPrefix)
res, err := query.Paginate(sigInfoStore, req.Req, func(key []byte, value []byte) error {
var info types.ValidatorSigningInfo
err := k.cdc.UnmarshalBinaryBare(value, &info)
if err != nil {
return err
}
signInfos = append(signInfos, info)
return nil
})
if err != nil {
return nil, err
}
return &types.QuerySigningInfosResponse{Info: signInfos, Res: res}, nil
}
109 changes: 109 additions & 0 deletions x/slashing/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package keeper_test

import (
gocontext "context"
"testing"
"time"

"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/slashing/keeper"
"github.com/cosmos/cosmos-sdk/x/slashing/types"
)

type SlashingTestSuite struct {
suite.Suite

app *simapp.SimApp
ctx sdk.Context
queryClient types.QueryClient
addrDels []sdk.AccAddress
}

func (suite *SlashingTestSuite) SetupTest() {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, abci.Header{})

app.AccountKeeper.SetParams(ctx, authtypes.DefaultParams())
app.BankKeeper.SetSendEnabled(ctx, true)
app.SlashingKeeper.SetParams(ctx, keeper.TestParams())

addrDels := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.TokensFromConsensusPower(200))

info1 := types.NewValidatorSigningInfo(sdk.ConsAddress(addrDels[0]), int64(4), int64(3),
time.Unix(2, 0), false, int64(10))
info2 := types.NewValidatorSigningInfo(sdk.ConsAddress(addrDels[1]), int64(5), int64(4),
time.Unix(2, 0), false, int64(10))

app.SlashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[0]), info1)
app.SlashingKeeper.SetValidatorSigningInfo(ctx, sdk.ConsAddress(addrDels[1]), info2)

suite.app = app
suite.ctx = ctx
suite.addrDels = addrDels

queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, app.SlashingKeeper)
queryClient := types.NewQueryClient(queryHelper)
sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
suite.queryClient = queryClient
}

func (suite *SlashingTestSuite) TestGRPCQueryParams() {
queryClient := suite.queryClient
paramsResp, err := queryClient.Params(gocontext.Background(), &types.QueryParamsRequest{})

suite.NoError(err)
suite.Equal(keeper.TestParams(), paramsResp.Params)
}

func (suite *SlashingTestSuite) TestGRPCSigningInfo() {
queryClient := suite.queryClient

infoResp, err := queryClient.SigningInfo(gocontext.Background(), &types.QuerySigningInfoRequest{ConsAddress: nil})
suite.Error(err)
suite.Nil(infoResp)

consAddr := sdk.ConsAddress(suite.addrDels[0])
info, found := suite.app.SlashingKeeper.GetValidatorSigningInfo(suite.ctx, consAddr)
suite.True(found)

infoResp, err = queryClient.SigningInfo(gocontext.Background(),
&types.QuerySigningInfoRequest{ConsAddress: consAddr})
suite.NoError(err)
suite.Equal(info, infoResp.ValSigningInfo)
}

func (suite *SlashingTestSuite) TestGRPCSigningInfos() {
queryClient := suite.queryClient

var signingInfos []types.ValidatorSigningInfo

suite.app.SlashingKeeper.IterateValidatorSigningInfos(suite.ctx, func(consAddr sdk.ConsAddress, info types.ValidatorSigningInfo) (stop bool) {
signingInfos = append(signingInfos, info)
return false
})

// verify all values are returned without pagination
var infoResp, err = queryClient.SigningInfos(gocontext.Background(),
&types.QuerySigningInfosRequest{Req: nil})
suite.NoError(err)
suite.Equal(signingInfos, infoResp.Info)

infoResp, err = queryClient.SigningInfos(gocontext.Background(),
&types.QuerySigningInfosRequest{Req: &query.PageRequest{Limit: 1, CountTotal: true}})
suite.NoError(err)
suite.Len(infoResp.Info, 1)
suite.Equal(signingInfos[0], infoResp.Info[0])
suite.NotNil(infoResp.Res.NextKey)
suite.Equal(uint64(2), infoResp.Res.Total)
}

func TestSlashingTestSuite(t *testing.T) {
suite.Run(t, new(SlashingTestSuite))
}
22 changes: 0 additions & 22 deletions x/slashing/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,6 @@ func ParamKeyTable() paramtypes.KeyTable {
return paramtypes.NewKeyTable().RegisterParamSet(&Params{})
}

// Params - used for initializing default parameter for slashing at genesis
type Params struct {
SignedBlocksWindow int64 `json:"signed_blocks_window" yaml:"signed_blocks_window"`
MinSignedPerWindow sdk.Dec `json:"min_signed_per_window" yaml:"min_signed_per_window"`
DowntimeJailDuration time.Duration `json:"downtime_jail_duration" yaml:"downtime_jail_duration"`
SlashFractionDoubleSign sdk.Dec `json:"slash_fraction_double_sign" yaml:"slash_fraction_double_sign"`
SlashFractionDowntime sdk.Dec `json:"slash_fraction_downtime" yaml:"slash_fraction_downtime"`
}

// NewParams creates a new Params object
func NewParams(
signedBlocksWindow int64, minSignedPerWindow sdk.Dec, downtimeJailDuration time.Duration,
Expand All @@ -58,19 +49,6 @@ func NewParams(
}
}

// String implements the stringer interface for Params
func (p Params) String() string {
return fmt.Sprintf(`Slashing Params:
SignedBlocksWindow: %d
MinSignedPerWindow: %s
DowntimeJailDuration: %s
SlashFractionDoubleSign: %s
SlashFractionDowntime: %s`,
p.SignedBlocksWindow, p.MinSignedPerWindow,
p.DowntimeJailDuration, p.SlashFractionDoubleSign,
p.SlashFractionDowntime)
}

sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
// ParamSetPairs - Implements params.ParamSet
func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
return paramtypes.ParamSetPairs{
Expand Down
Loading