Skip to content

Commit

Permalink
Merge pull request #135 from decentrio/validator-api
Browse files Browse the repository at this point in the history
!feat: Add validator query
  • Loading branch information
jiujiteiro authored Mar 18, 2024
2 parents 35a63e7 + 26a796b commit c2610c3
Show file tree
Hide file tree
Showing 8 changed files with 2,148 additions and 162 deletions.
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

0 comments on commit c2610c3

Please sign in to comment.