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(cli/api): add validator distribution info grpc gateway get endpoint #13144

Merged
merged 10 commits into from
Sep 5, 2022
2,136 changes: 1,709 additions & 427 deletions api/cosmos/distribution/v1beta1/query.pulsar.go

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions api/cosmos/distribution/v1beta1/query_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions proto/cosmos/distribution/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ service Query {
option (google.api.http).get = "/cosmos/distribution/v1beta1/params";
}

// ValidatorDistributionInfo queries validator commision and self-delegation rewards for validator
rpc ValidatorDistributionInfo(QueryValidatorDistributionInfoRequest)
returns (QueryValidatorDistributionInfoResponse) {
option (google.api.http).get = "/cosmos/distribution/v1beta1/validators/{validator_address}";
}

// ValidatorOutstandingRewards queries rewards of a validator address.
rpc ValidatorOutstandingRewards(QueryValidatorOutstandingRewardsRequest)
returns (QueryValidatorOutstandingRewardsResponse) {
Expand Down Expand Up @@ -74,6 +80,26 @@ message QueryParamsResponse {
Params params = 1 [(gogoproto.nullable) = false];
}

// QueryValidatorDistributionInfoRequest is the request type for the Query/ValidatorDistributionInfo RPC method.
message QueryValidatorDistributionInfoRequest {
// validator_address defines the validator address to query for.
string validator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}

// QueryValidatorDistributionInfoResponse is the response type for the Query/ValidatorDistributionInfo RPC method.
message QueryValidatorDistributionInfoResponse {
// operator_address defines the validator operator address.
string operator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// self_bond_rewards defines the self delegations rewards.
repeated cosmos.base.v1beta1.DecCoin self_bond_rewards = 2
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins"];
// commission defines the commision the validator received.
repeated cosmos.base.v1beta1.DecCoin commission = 3 [
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins",
(gogoproto.nullable) = false
];
}

// QueryValidatorOutstandingRewardsRequest is the request type for the
// Query/ValidatorOutstandingRewards RPC method.
message QueryValidatorOutstandingRewardsRequest {
Expand Down
45 changes: 45 additions & 0 deletions x/distribution/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func GetQueryCmd() *cobra.Command {

distQueryCmd.AddCommand(
GetCmdQueryParams(),
GetCmdQueryValidatorDistributionInfo(),
GetCmdQueryValidatorOutstandingRewards(),
GetCmdQueryValidatorCommission(),
GetCmdQueryValidatorSlashes(),
Expand Down Expand Up @@ -62,6 +63,50 @@ func GetCmdQueryParams() *cobra.Command {
return cmd
}

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

cmd := &cobra.Command{
Use: "validator-distribution-info [validator]",
Args: cobra.ExactArgs(1),
Short: "Query validator distribution info",
Long: strings.TrimSpace(
fmt.Sprintf(`Query validator distribution info.
Example:
$ %s query distribution validator-distribution-info %s1lwjmdnks33xwnmfayc64ycprww49n33mtm92ne
`,
version.AppName, bech32PrefixValAddr,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

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

queryClient := types.NewQueryClient(clientCtx)

res, err := queryClient.ValidatorDistributionInfo(cmd.Context(), &types.QueryValidatorDistributionInfoRequest{
ValidatorAddress: validatorAddr.String(),
})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)
return cmd
}

// GetCmdQueryValidatorOutstandingRewards implements the query validator
// outstanding rewards command.
func GetCmdQueryValidatorOutstandingRewards() *cobra.Command {
Expand Down
38 changes: 38 additions & 0 deletions x/distribution/client/testutil/grpc_query_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,44 @@ func (s *GRPCQueryTestSuite) TestQueryParamsGRPC() {
}
}

func (s *GRPCQueryTestSuite) TestQueryValidatorDistributionInfoGRPC() {
val := s.network.Validators[0]
baseURL := val.APIAddress

testCases := []struct {
name string
url string
expErr bool
respType proto.Message
}{
{
"gRPC request with wrong validator address",
fmt.Sprintf("%s/cosmos/distribution/v1beta1/validators/%s", baseURL, "wrongAddress"),
true,
&types.QueryValidatorDistributionInfoResponse{},
},
{
"gRPC request with valid validator address ",
fmt.Sprintf("%s/cosmos/distribution/v1beta1/validators/%s", baseURL, val.ValAddress.String()),
false,
&types.QueryValidatorDistributionInfoResponse{},
},
}

for _, tc := range testCases {
tc := tc
resp, err := rest.GetRequest(tc.url)
s.Run(tc.name, func() {
if tc.expErr {
s.Require().Error(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType))
} else {
s.Require().NoError(err)
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType))
}
})
}
}

func (s *GRPCQueryTestSuite) TestQueryOutstandingRewardsGRPC() {
val := s.network.Validators[0]
baseURL := val.APIAddress
Expand Down
42 changes: 42 additions & 0 deletions x/distribution/client/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,48 @@ withdraw_addr_enabled: true`,
}
}

func (s *IntegrationTestSuite) TestGetCmdQueryValidatorDistributionInfo() {
val := s.network.Validators[0]

testCases := []struct {
name string
args []string
expErr bool
}{
{
"invalid val address",
[]string{"invalid address", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
},
{
"json output",
[]string{val.ValAddress.String(), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
},
{
"text output",
[]string{val.ValAddress.String(), fmt.Sprintf("--%s=text", tmcli.OutputFlag)},
false,
},
}

for _, tc := range testCases {
tc := tc

s.Run(tc.name, func() {
cmd := cli.GetCmdQueryValidatorDistributionInfo()
clientCtx := val.ClientCtx

_, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
}
})
}
}

func (s *IntegrationTestSuite) TestGetCmdQueryValidatorOutstandingRewards() {
val := s.network.Validators[0]

Expand Down
47 changes: 47 additions & 0 deletions x/distribution/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"context"
"encoding/hex"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down Expand Up @@ -32,6 +33,52 @@ func (k Querier) Params(c context.Context, req *types.QueryParamsRequest) (*type
return &types.QueryParamsResponse{Params: params}, nil
}

// ValidatorDistributionInfo query validator's commission and self-delegation rewards
func (k Querier) ValidatorDistributionInfo(c context.Context, req *types.QueryValidatorDistributionInfoRequest) (*types.QueryValidatorDistributionInfoResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}

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

ctx := sdk.UnwrapSDKContext(c)

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

// self-delegation rewards
val := k.stakingKeeper.Validator(ctx, valAdr)
if val == nil {
return nil, sdkerrors.Wrap(types.ErrNoValidatorExists, req.ValidatorAddress)
}

delAdr, err := sdk.AccAddressFromHexUnsafe(hex.EncodeToString(valAdr.Bytes()))
gsk967 marked this conversation as resolved.
Show resolved Hide resolved
gsk967 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, err
}

del := k.stakingKeeper.Delegation(ctx, delAdr, valAdr)
if del == nil {
return nil, types.ErrNoDelegationExists
}

endingPeriod := k.IncrementValidatorPeriod(ctx, val)
rewards := k.CalculateDelegationRewards(ctx, val, del, endingPeriod)

// validator's commission
validatorCommission := k.GetValidatorAccumulatedCommission(ctx, valAdr)

return &types.QueryValidatorDistributionInfoResponse{
Commission: validatorCommission.Commission,
OperatorAddress: delAdr.String(),
SelfBondRewards: rewards,
}, nil
}

// ValidatorOutstandingRewards queries rewards of a validator address
func (k Querier) ValidatorOutstandingRewards(c context.Context, req *types.QueryValidatorOutstandingRewardsRequest) (*types.QueryValidatorOutstandingRewardsResponse, error) {
if req == nil {
Expand Down
Loading