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

!feat: Add validator query #135

Merged
merged 7 commits into from
Mar 18, 2024
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
33 changes: 33 additions & 0 deletions proto/multistaking/v1/multi_staking.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ package multistaking.v1;
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/v1beta1/coin.proto";
import "cosmos/staking/v1beta1/staking.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/any.proto";

option go_package = "github.com/realiotech/multi-staking/x/multi-staking/types";

Expand Down Expand Up @@ -71,4 +73,35 @@ message MultiStakingCoinInfo {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

message ValidatorInfo {
option (gogoproto.equal) = false;
option (gogoproto.goproto_stringer) = false;
option (gogoproto.goproto_getters) = false;

string operator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
google.protobuf.Any consensus_pubkey = 2 [(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey"];
bool jailed = 3;
cosmos.staking.v1beta1.BondStatus status = 4;
string tokens = 5 [
(cosmos_proto.scalar) = "cosmos.Int",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string delegator_shares = 6 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
cosmos.staking.v1beta1.Description description = 7 [(gogoproto.nullable) = false];
int64 unbonding_height = 8;
google.protobuf.Timestamp unbonding_time = 9 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
cosmos.staking.v1beta1.Commission commission = 10 [(gogoproto.nullable) = false];
string min_self_delegation = 11 [
(cosmos_proto.scalar) = "cosmos.Int",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string bond_denom = 12;
}
27 changes: 26 additions & 1 deletion proto/multistaking/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ service Query {
rpc BondWeight(QueryBondWeightRequest) returns (QueryBondWeightResponse) {
option (google.api.http).get = "/realiotech/multistaking/v1/weight/{denom}";
}
rpc Validators(QueryValidatorsRequest)
returns (QueryValidatorsResponse) {
option (google.api.http).get = "/realiotech/multistaking/v1/validators";
}
rpc Validator(QueryValidatorRequest) returns (QueryValidatorResponse) {
option (google.api.http).get = "/realiotech/multistaking/v1/validators/{validator_addr}";
}
}

message QueryMultiStakingLocksRequest {
Expand Down Expand Up @@ -116,4 +123,22 @@ message QueryValidatorMultiStakingCoinRequest {
string validator_addr = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
}

message QueryValidatorMultiStakingCoinResponse { string denom = 1; }
message QueryValidatorMultiStakingCoinResponse { string denom = 1; }

message QueryValidatorsRequest {
string status = 1;
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}

message QueryValidatorsResponse {
repeated ValidatorInfo validators = 1 [(gogoproto.nullable) = false];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

message QueryValidatorRequest {
string validator_addr = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}

message QueryValidatorResponse {
ValidatorInfo validator = 1 [(gogoproto.nullable) = false];
}
92 changes: 92 additions & 0 deletions x/multi-staking/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package cli

import (
"fmt"
"strings"

"github.com/realio-tech/multi-staking-module/x/multi-staking/types"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
)

func GetQueryCmd() *cobra.Command {
Expand All @@ -28,6 +30,8 @@ func GetQueryCmd() *cobra.Command {
GetCmdQueryMultiStakingUnlock(),
GetCmdQueryMultiStakingUnlocks(),
GetCmdQueryValidatorMultiStakingCoin(),
GetCmdQueryValidator(),
GetCmdQueryValidators(),
)

return cmd
Expand Down Expand Up @@ -289,3 +293,91 @@ func GetCmdQueryValidatorMultiStakingCoin() *cobra.Command {

return cmd
}

// GetCmdQueryValidator implements the validator query command.
func GetCmdQueryValidator() *cobra.Command {
bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix()

cmd := &cobra.Command{
Use: "validator [validator-addr]",
Short: "Query a validator",
Long: strings.TrimSpace(
fmt.Sprintf(`Query details about an individual validator.

Example:
$ %s query multistaking validator %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj
`,
version.AppName, bech32PrefixValAddr,
),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

addr, err := sdk.ValAddressFromBech32(args[0])
if err != nil {
return err
}

params := &types.QueryValidatorRequest{ValidatorAddr: addr.String()}
res, err := queryClient.Validator(cmd.Context(), params)
if err != nil {
return err
}

return clientCtx.PrintProto(&res.Validator)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// GetCmdQueryValidators implements the query all validators command.
func GetCmdQueryValidators() *cobra.Command {
cmd := &cobra.Command{
Use: "validators",
Short: "Query for all validators",
Args: cobra.NoArgs,
Long: strings.TrimSpace(
fmt.Sprintf(`Query details about all validators on a network.

Example:
$ %s query multistaking validators
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}

result, err := queryClient.Validators(cmd.Context(), &types.QueryValidatorsRequest{
// Leaving status empty on purpose to query all validators.
Pagination: pageReq,
})
if err != nil {
return err
}

return clientCtx.PrintProto(result)
},
}

flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "validators")

return cmd
}
84 changes: 84 additions & 0 deletions x/multi-staking/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,23 @@ import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)

type queryServer struct {
Keeper
stakingQuerier stakingkeeper.Querier
}

// NewMsgServerImpl returns an implementation of the bank MsgServer interface
// for the provided Keeper.
func NewQueryServerImpl(keeper Keeper) types.QueryServer {
return &queryServer{
Keeper: keeper,
stakingQuerier: stakingkeeper.Querier{
Keeper: keeper.stakingKeeper,
},
}
}

Expand Down Expand Up @@ -183,3 +189,81 @@ func (k queryServer) ValidatorMultiStakingCoin(c context.Context, req *types.Que
Denom: denom,
}, nil
}

func (k queryServer) Validators(c context.Context, req *types.QueryValidatorsRequest) (*types.QueryValidatorsResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
sdkReq := stakingtypes.QueryValidatorsRequest{
Status: req.Status,
Pagination: req.Pagination,
}

resp, err := k.stakingQuerier.Validators(c, &sdkReq)
if err != nil {
return nil, err
}

vals := []types.ValidatorInfo{}
for _, val := range resp.Validators {
valAcc, err := sdk.ValAddressFromBech32(val.OperatorAddress)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "invalid validator address")
}

denom := k.Keeper.GetValidatorMultiStakingCoin(ctx, valAcc)
valInfo := types.ValidatorInfo{
OperatorAddress: val.OperatorAddress,
ConsensusPubkey: val.ConsensusPubkey,
Jailed: val.Jailed,
Status: val.Status,
Tokens: val.Tokens,
DelegatorShares: val.DelegatorShares,
Description: val.Description,
UnbondingHeight: val.UnbondingHeight,
UnbondingTime: val.UnbondingTime,
Commission: val.Commission,
MinSelfDelegation: val.MinSelfDelegation,
BondDenom: denom,
}
vals = append(vals, valInfo)
}

return &types.QueryValidatorsResponse{Validators: vals, Pagination: resp.Pagination}, nil
}

func (k queryServer) Validator(c context.Context, req *types.QueryValidatorRequest) (*types.QueryValidatorResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}

if req.ValidatorAddr == "" {
return nil, status.Error(codes.InvalidArgument, "validator address cannot be empty")
}

valAddr, err := sdk.ValAddressFromBech32(req.ValidatorAddr)
if err != nil {
return nil, err
}

ctx := sdk.UnwrapSDKContext(c)
validator, found := k.stakingKeeper.GetValidator(ctx, valAddr)
if !found {
return nil, status.Errorf(codes.NotFound, "validator %s not found", req.ValidatorAddr)
}

denom := k.Keeper.GetValidatorMultiStakingCoin(ctx, valAddr)
valInfo := types.ValidatorInfo{
OperatorAddress: validator.OperatorAddress,
ConsensusPubkey: validator.ConsensusPubkey,
Jailed: validator.Jailed,
Status: validator.Status,
Tokens: validator.Tokens,
DelegatorShares: validator.DelegatorShares,
Description: validator.Description,
UnbondingHeight: validator.UnbondingHeight,
UnbondingTime: validator.UnbondingTime,
Commission: validator.Commission,
MinSelfDelegation: validator.MinSelfDelegation,
BondDenom: denom,
}
return &types.QueryValidatorResponse{Validator: valInfo}, nil
}
Loading
Loading