-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
x/distribution: gRPC query service (#6600)
* WIP: adding grpc * added grpc for query withdraw address * Fix outstanding rewards query * added inteerface registry * added gRPC for delegation rewards * added remaining commands * lint issue * added tests * added test for community pool * fixed error * added test for delegator validators * updated to use test suite * updated tests * more test checks added * updated tests * Add sdk wrap * removed pagination for outstanding rewards * fixed distr tests issue * fixed slashes issue * migrated tests to table driven tests * docs updated * review changes * review changes * review changes * Update x/distribution/keeper/grpc_query.go Co-authored-by: sahith-narahari <sahithnarahari@gmail.com> Co-authored-by: anilCSE <anil@vitwit.com> Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
- Loading branch information
1 parent
7678f8a
commit be111ef
Showing
9 changed files
with
5,374 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
syntax = "proto3"; | ||
package cosmos.distribution; | ||
|
||
import "cosmos/query/pagination.proto"; | ||
import "gogoproto/gogo.proto"; | ||
import "cosmos/cosmos.proto"; | ||
import "cosmos/distribution/distribution.proto"; | ||
|
||
option go_package = "github.com/cosmos/cosmos-sdk/x/distribution/types"; | ||
|
||
// Query defines the gRPC querier service for distribution module | ||
service Query { | ||
// Params queries params of distribution module | ||
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {} | ||
|
||
// ValidatorOutstandingRewards queries rewards of a validator address | ||
rpc ValidatorOutstandingRewards(QueryValidatorOutstandingRewardsRequest) returns (QueryValidatorOutstandingRewardsResponse) {} | ||
|
||
// ValidatorCommission queries accumulated commission for a validator | ||
rpc ValidatorCommission (QueryValidatorCommissionRequest) returns (QueryValidatorCommissionResponse) {} | ||
|
||
// ValidatorSlashes queries slash events of a validator | ||
rpc ValidatorSlashes (QueryValidatorSlashesRequest) returns (QueryValidatorSlashesResponse) {} | ||
|
||
// DelegationRewards the total rewards accrued by a delegation | ||
rpc DelegationRewards (QueryDelegationRewardsRequest) returns (QueryDelegationRewardsResponse) {} | ||
|
||
// DelegationTotalRewards the total rewards accrued by a each validator | ||
rpc DelegationTotalRewards (QueryDelegationTotalRewardsRequest) returns (QueryDelegationTotalRewardsResponse) {} | ||
|
||
// DelegatorValidators queries the validators of a delegator | ||
rpc DelegatorValidators (QueryDelegatorValidatorsRequest) returns (QueryDelegatorValidatorsResponse) {} | ||
|
||
// DelegatorWithdrawAddress queries withdraw address of a delegator | ||
rpc DelegatorWithdrawAddress (QueryDelegatorWithdrawAddressRequest) returns (QueryDelegatorWithdrawAddressResponse) {} | ||
|
||
// CommunityPool queries the community pool coins | ||
rpc CommunityPool (QueryCommunityPoolRequest) returns (QueryCommunityPoolResponse) {} | ||
} | ||
|
||
// QueryParamsRequest is the request type for the Query/Params RPC method | ||
message QueryParamsRequest { } | ||
|
||
// QueryParamsResponse is the response type for the Query/Params RPC method | ||
message QueryParamsResponse { | ||
Params params = 1 [(gogoproto.nullable) = false]; | ||
} | ||
|
||
// QueryValidatorOutstandingRewardsRequest is the request type for the Query/ValidatorOutstandingRewards RPC method | ||
message QueryValidatorOutstandingRewardsRequest { | ||
bytes validator_address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress"]; | ||
} | ||
|
||
// QueryValidatorOutstandingRewardsResponse is the response type for the Query/ValidatorOutstandingRewards RPC method | ||
message QueryValidatorOutstandingRewardsResponse { | ||
ValidatorOutstandingRewards rewards = 1 [(gogoproto.nullable) = false]; | ||
} | ||
|
||
// QueryValidatorCommissionRequest is the request type for the Query/ValidatorCommission RPC method | ||
message QueryValidatorCommissionRequest { | ||
bytes validator_address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress"]; | ||
} | ||
|
||
// QueryValidatorCommissionResponse is the response type for the Query/ValidatorCommission RPC method | ||
message QueryValidatorCommissionResponse { | ||
ValidatorAccumulatedCommission commission = 1 [(gogoproto.nullable) = false]; | ||
} | ||
|
||
// QueryValidatorSlashesRequest is the request type for the Query/ValidatorSlashes RPC method | ||
message QueryValidatorSlashesRequest { | ||
bytes validator_address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress"]; | ||
uint64 starting_height = 2; | ||
uint64 ending_height = 3; | ||
cosmos.query.PageRequest req = 4; | ||
} | ||
|
||
// QueryValidatorSlashesResponse is the response type for the Query/ValidatorSlashes RPC method | ||
message QueryValidatorSlashesResponse { | ||
repeated ValidatorSlashEvent slashes = 1 [(gogoproto.nullable) = false]; | ||
|
||
cosmos.query.PageResponse res = 2; | ||
} | ||
|
||
// QueryDelegationRewardsRequest is the request type for the Query/DelegationRewards RPC method | ||
message QueryDelegationRewardsRequest { | ||
bytes delegator_address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; | ||
bytes validator_address = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress"]; | ||
} | ||
|
||
// QueryDelegationRewardsResponse is the response type for the Query/DelegationRewards RPC method | ||
message QueryDelegationRewardsResponse { | ||
repeated cosmos.DecCoin rewards = 1 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins" | ||
]; | ||
} | ||
|
||
// QueryDelegationTotalRewardsRequest is the request type for the Query/DelegationTotalRewards RPC method | ||
message QueryDelegationTotalRewardsRequest { | ||
bytes delegator_address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; | ||
} | ||
|
||
// QueryDelegationTotalRewardsResponse is the response type for the Query/DelegationTotalRewards RPC method | ||
message QueryDelegationTotalRewardsResponse { | ||
repeated DelegationDelegatorReward rewards = 1 [(gogoproto.nullable) = false]; | ||
repeated cosmos.DecCoin total = 2 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins" | ||
]; | ||
} | ||
|
||
// QueryDelegatorValidatorsRequest is the request type for the Query/DelegatorValidators RPC method | ||
message QueryDelegatorValidatorsRequest { | ||
bytes delegator_address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; | ||
} | ||
|
||
// QueryDelegatorValidatorsResponse is the response type for the Query/DelegatorValidators RPC method | ||
message QueryDelegatorValidatorsResponse { | ||
repeated bytes validators = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ValAddress"]; | ||
} | ||
|
||
// QueryDelegatorWithdrawAddressRequest is the request type for the Query/DelegatorWithdrawAddress RPC method | ||
message QueryDelegatorWithdrawAddressRequest { | ||
bytes delegator_address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; | ||
} | ||
|
||
// QueryDelegatorWithdrawAddressResponse is the response type for the Query/DelegatorWithdrawAddress RPC method | ||
message QueryDelegatorWithdrawAddressResponse { | ||
bytes withdraw_address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; | ||
} | ||
|
||
// QueryCommunityPoolRequest is the request type for the Query/CommunityPool RPC method | ||
message QueryCommunityPoolRequest {} | ||
|
||
// QueryCommunityPoolResponse is the response type for the Query/CommunityPool RPC method | ||
message QueryCommunityPoolResponse { | ||
repeated cosmos.DecCoin pool = 1 [ | ||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", | ||
(gogoproto.nullable) = false | ||
]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
package keeper | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/cosmos/cosmos-sdk/store/prefix" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
"github.com/cosmos/cosmos-sdk/types/query" | ||
"github.com/cosmos/cosmos-sdk/x/distribution/types" | ||
"github.com/cosmos/cosmos-sdk/x/staking/exported" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/status" | ||
) | ||
|
||
var _ types.QueryServer = Keeper{} | ||
|
||
// Params queries params of distribution module | ||
func (k Keeper) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { | ||
ctx := sdk.UnwrapSDKContext(c) | ||
var params types.Params | ||
k.paramSpace.GetParamSet(ctx, ¶ms) | ||
|
||
return &types.QueryParamsResponse{Params: params}, nil | ||
} | ||
|
||
// ValidatorOutstandingRewards queries rewards of a validator address | ||
func (k Keeper) ValidatorOutstandingRewards(c context.Context, req *types.QueryValidatorOutstandingRewardsRequest) (*types.QueryValidatorOutstandingRewardsResponse, error) { | ||
if req == nil { | ||
return nil, status.Error(codes.InvalidArgument, "invalid request") | ||
} | ||
|
||
if req.ValidatorAddress.Empty() { | ||
return nil, status.Error(codes.InvalidArgument, "empty validator address") | ||
} | ||
|
||
ctx := sdk.UnwrapSDKContext(c) | ||
rewards := k.GetValidatorOutstandingRewards(ctx, req.ValidatorAddress) | ||
|
||
return &types.QueryValidatorOutstandingRewardsResponse{Rewards: rewards}, nil | ||
} | ||
|
||
// ValidatorCommission queries accumulated commission for a validator | ||
func (k Keeper) ValidatorCommission(c context.Context, req *types.QueryValidatorCommissionRequest) (*types.QueryValidatorCommissionResponse, error) { | ||
if req == nil { | ||
return nil, status.Error(codes.InvalidArgument, "invalid request") | ||
} | ||
|
||
if req.ValidatorAddress.Empty() { | ||
return nil, status.Error(codes.InvalidArgument, "empty validator address") | ||
} | ||
|
||
ctx := sdk.UnwrapSDKContext(c) | ||
commission := k.GetValidatorAccumulatedCommission(ctx, req.ValidatorAddress) | ||
|
||
return &types.QueryValidatorCommissionResponse{Commission: commission}, nil | ||
} | ||
|
||
// ValidatorSlashes queries slash events of a validator | ||
func (k Keeper) ValidatorSlashes(c context.Context, req *types.QueryValidatorSlashesRequest) (*types.QueryValidatorSlashesResponse, error) { | ||
if req == nil { | ||
return nil, status.Error(codes.InvalidArgument, "invalid request") | ||
} | ||
|
||
if req.ValidatorAddress.Empty() { | ||
return nil, status.Error(codes.InvalidArgument, "empty validator address") | ||
} | ||
|
||
if req.EndingHeight < req.StartingHeight { | ||
return nil, status.Errorf(codes.InvalidArgument, "starting height greater than ending height (%d > %d)", req.StartingHeight, req.EndingHeight) | ||
} | ||
|
||
ctx := sdk.UnwrapSDKContext(c) | ||
events := make([]types.ValidatorSlashEvent, 0) | ||
store := ctx.KVStore(k.storeKey) | ||
slashesStore := prefix.NewStore(store, types.GetValidatorSlashEventPrefix(req.ValidatorAddress)) | ||
|
||
res, err := query.FilteredPaginate(slashesStore, req.Req, func(key []byte, value []byte, accumulate bool) (bool, error) { | ||
var result types.ValidatorSlashEvent | ||
err := k.cdc.UnmarshalBinaryBare(value, &result) | ||
|
||
if err != nil { | ||
return false, err | ||
} | ||
|
||
if result.ValidatorPeriod < req.StartingHeight || result.ValidatorPeriod > req.EndingHeight { | ||
return false, nil | ||
} | ||
|
||
if accumulate { | ||
events = append(events, result) | ||
} | ||
return true, nil | ||
}) | ||
|
||
if err != nil { | ||
return &types.QueryValidatorSlashesResponse{}, err | ||
} | ||
|
||
return &types.QueryValidatorSlashesResponse{Slashes: events, Res: res}, nil | ||
} | ||
|
||
// DelegationRewards the total rewards accrued by a delegation | ||
func (k Keeper) DelegationRewards(c context.Context, req *types.QueryDelegationRewardsRequest) (*types.QueryDelegationRewardsResponse, error) { | ||
if req == nil { | ||
return nil, status.Error(codes.InvalidArgument, "invalid request") | ||
} | ||
|
||
if req.DelegatorAddress.Empty() { | ||
return nil, status.Error(codes.InvalidArgument, "empty delegator address") | ||
} | ||
|
||
if req.ValidatorAddress.Empty() { | ||
return nil, status.Error(codes.InvalidArgument, "empty validator address") | ||
} | ||
|
||
ctx := sdk.UnwrapSDKContext(c) | ||
|
||
val := k.stakingKeeper.Validator(ctx, req.ValidatorAddress) | ||
if val == nil { | ||
return nil, sdkerrors.Wrap(types.ErrNoValidatorExists, req.ValidatorAddress.String()) | ||
} | ||
|
||
del := k.stakingKeeper.Delegation(ctx, req.DelegatorAddress, req.ValidatorAddress) | ||
if del == nil { | ||
return nil, types.ErrNoDelegationExists | ||
} | ||
|
||
endingPeriod := k.IncrementValidatorPeriod(ctx, val) | ||
rewards := k.CalculateDelegationRewards(ctx, val, del, endingPeriod) | ||
|
||
return &types.QueryDelegationRewardsResponse{Rewards: rewards}, nil | ||
} | ||
|
||
// DelegationTotalRewards the total rewards accrued by a each validator | ||
func (k Keeper) DelegationTotalRewards(c context.Context, req *types.QueryDelegationTotalRewardsRequest) (*types.QueryDelegationTotalRewardsResponse, error) { | ||
if req == nil { | ||
return nil, status.Error(codes.InvalidArgument, "invalid request") | ||
} | ||
|
||
if req.DelegatorAddress.Empty() { | ||
return nil, status.Error(codes.InvalidArgument, "empty delegator address") | ||
} | ||
|
||
ctx := sdk.UnwrapSDKContext(c) | ||
|
||
total := sdk.DecCoins{} | ||
var delRewards []types.DelegationDelegatorReward | ||
|
||
k.stakingKeeper.IterateDelegations( | ||
ctx, req.DelegatorAddress, | ||
func(_ int64, del exported.DelegationI) (stop bool) { | ||
valAddr := del.GetValidatorAddr() | ||
val := k.stakingKeeper.Validator(ctx, valAddr) | ||
endingPeriod := k.IncrementValidatorPeriod(ctx, val) | ||
delReward := k.CalculateDelegationRewards(ctx, val, del, endingPeriod) | ||
|
||
delRewards = append(delRewards, types.NewDelegationDelegatorReward(valAddr, delReward)) | ||
total = total.Add(delReward...) | ||
return false | ||
}, | ||
) | ||
|
||
return &types.QueryDelegationTotalRewardsResponse{Rewards: delRewards, Total: total}, nil | ||
} | ||
|
||
// DelegatorValidators queries the validators list of a delegator | ||
func (k Keeper) DelegatorValidators(c context.Context, req *types.QueryDelegatorValidatorsRequest) (*types.QueryDelegatorValidatorsResponse, error) { | ||
if req == nil { | ||
return nil, status.Error(codes.InvalidArgument, "invalid request") | ||
} | ||
|
||
if req.DelegatorAddress.Empty() { | ||
return nil, status.Error(codes.InvalidArgument, "empty delegator address") | ||
} | ||
|
||
ctx := sdk.UnwrapSDKContext(c) | ||
|
||
var validators []sdk.ValAddress | ||
|
||
k.stakingKeeper.IterateDelegations( | ||
ctx, req.DelegatorAddress, | ||
func(_ int64, del exported.DelegationI) (stop bool) { | ||
validators = append(validators, del.GetValidatorAddr()) | ||
return false | ||
}, | ||
) | ||
|
||
return &types.QueryDelegatorValidatorsResponse{Validators: validators}, nil | ||
} | ||
|
||
// DelegatorWithdrawAddress queries Query/delegatorWithdrawAddress | ||
func (k Keeper) DelegatorWithdrawAddress(c context.Context, req *types.QueryDelegatorWithdrawAddressRequest) (*types.QueryDelegatorWithdrawAddressResponse, error) { | ||
if req == nil { | ||
return nil, status.Error(codes.InvalidArgument, "invalid request") | ||
} | ||
|
||
if req.DelegatorAddress.Empty() { | ||
return nil, status.Error(codes.InvalidArgument, "empty delegator address") | ||
} | ||
|
||
ctx := sdk.UnwrapSDKContext(c) | ||
withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, req.DelegatorAddress) | ||
|
||
return &types.QueryDelegatorWithdrawAddressResponse{WithdrawAddress: withdrawAddr}, nil | ||
} | ||
|
||
// CommunityPool queries the community pool coins | ||
func (k Keeper) CommunityPool(c context.Context, req *types.QueryCommunityPoolRequest) (*types.QueryCommunityPoolResponse, error) { | ||
ctx := sdk.UnwrapSDKContext(c) | ||
pool := k.GetFeePoolCommunityCoins(ctx) | ||
|
||
return &types.QueryCommunityPoolResponse{Pool: pool}, nil | ||
} |
Oops, something went wrong.