diff --git a/PENDING.md b/PENDING.md index 266b15a37c..d84b7ddb9f 100644 --- a/PENDING.md +++ b/PENDING.md @@ -22,6 +22,8 @@ FEATURES * Gaia REST API * Gaia CLI (`gaiacli`) + * [\#3429](https://github.com/cosmos/cosmos-sdk/issues/3429) Support querying + for all delegator distribution rewards. * Gaia - [\#3397](https://github.com/cosmos/cosmos-sdk/pull/3397) Implement genesis file sanitization to avoid failures at chain init. diff --git a/docs/gaia/gaiacli.md b/docs/gaia/gaiacli.md index 0b1bafd269..4886167e2c 100644 --- a/docs/gaia/gaiacli.md +++ b/docs/gaia/gaiacli.md @@ -685,6 +685,14 @@ To check current rewards for a delegation (were they to be withdrawn), run: gaiacli query distr rewards ``` +#### Query all delegator rewards + +To check all current rewards for a delegation (were they to be withdrawn), run: + +```bash +gaiacli query distr rewards +``` + ### Multisig transactions Multisig transactions require signatures of multiple private keys. Thus, generating and signing diff --git a/x/distribution/client/cli/query.go b/x/distribution/client/cli/query.go index 09b372278f..4f4eb93908 100644 --- a/x/distribution/client/cli/query.go +++ b/x/distribution/client/cli/query.go @@ -154,8 +154,8 @@ func GetCmdQueryValidatorSlashes(queryRoute string, cdc *codec.Codec) *cobra.Com func GetCmdQueryDelegatorRewards(queryRoute string, cdc *codec.Codec) *cobra.Command { return &cobra.Command{ Use: "rewards [delegator] [validator]", - Args: cobra.ExactArgs(2), - Short: "Query distribution delegator rewards", + Args: cobra.RangeArgs(1, 2), + Short: "Query all distribution delegator rewards or rewards from a particular validator", RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) @@ -164,26 +164,39 @@ func GetCmdQueryDelegatorRewards(queryRoute string, cdc *codec.Codec) *cobra.Com return err } - validatorAddr, err := sdk.ValAddressFromBech32(args[1]) - if err != nil { - return err + var ( + route string + params distr.QueryDelegationRewardsParams + result sdk.DecCoins + ) + + if len(args) == 1 { + // query for all rewards + params = distr.NewQueryDelegationRewardsParams(delegatorAddr, nil) + route = fmt.Sprintf("custom/%s/all_delegation_rewards", queryRoute) + } else { + // query for rewards from a particular validator + validatorAddr, err := sdk.ValAddressFromBech32(args[1]) + if err != nil { + return err + } + + params = distr.NewQueryDelegationRewardsParams(delegatorAddr, validatorAddr) + route = fmt.Sprintf("custom/%s/delegation_rewards", queryRoute) } - params := distr.NewQueryDelegationRewardsParams(delegatorAddr, validatorAddr) bz, err := cdc.MarshalJSON(params) if err != nil { return err } - route := fmt.Sprintf("custom/%s/delegation_rewards", queryRoute) - res, err := cliCtx.QueryWithData(route, bz) + resp, err := cliCtx.QueryWithData(route, bz) if err != nil { return err } - var coins sdk.DecCoins - cdc.MustUnmarshalJSON(res, &coins) - return cliCtx.PrintOutput(coins) + cdc.MustUnmarshalJSON(resp, &result) + return cliCtx.PrintOutput(result) }, } } diff --git a/x/distribution/keeper/querier.go b/x/distribution/keeper/querier.go index e1323aa343..619f2c39ea 100644 --- a/x/distribution/keeper/querier.go +++ b/x/distribution/keeper/querier.go @@ -12,11 +12,12 @@ import ( // nolint const ( - QueryParams = "params" - QueryOutstandingRewards = "outstanding_rewards" - QueryValidatorCommission = "validator_commission" - QueryValidatorSlashes = "validator_slashes" - QueryDelegationRewards = "delegation_rewards" + QueryParams = "params" + QueryOutstandingRewards = "outstanding_rewards" + QueryValidatorCommission = "validator_commission" + QueryValidatorSlashes = "validator_slashes" + QueryDelegationRewards = "delegation_rewards" + QueryAllDelegationRewards = "all_delegation_rewards" ParamCommunityTax = "community_tax" ParamBaseProposerReward = "base_proposer_reward" @@ -29,14 +30,22 @@ func NewQuerier(k Keeper) sdk.Querier { switch path[0] { case QueryParams: return queryParams(ctx, path[1:], req, k) + case QueryOutstandingRewards: return queryOutstandingRewards(ctx, path[1:], req, k) + case QueryValidatorCommission: return queryValidatorCommission(ctx, path[1:], req, k) + case QueryValidatorSlashes: return queryValidatorSlashes(ctx, path[1:], req, k) + case QueryDelegationRewards: return queryDelegationRewards(ctx, path[1:], req, k) + + case QueryAllDelegationRewards: + return queryAllDelegationRewards(ctx, path[1:], req, k) + default: return nil, sdk.ErrUnknownRequest("unknown distr query endpoint") } @@ -158,20 +167,57 @@ func NewQueryDelegationRewardsParams(delegatorAddr sdk.AccAddress, validatorAddr } } -func queryDelegationRewards(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { var params QueryDelegationRewardsParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) } + + // cache-wrap context as to not persist state changes during querying ctx, _ = ctx.CacheContext() + val := k.stakingKeeper.Validator(ctx, params.ValidatorAddr) del := k.stakingKeeper.Delegation(ctx, params.DelegatorAddr, params.ValidatorAddr) endingPeriod := k.incrementValidatorPeriod(ctx, val) rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod) + bz, err := codec.MarshalJSONIndent(k.cdc, rewards) if err != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) } + + return bz, nil +} + +func queryAllDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { + var params QueryDelegationRewardsParams + err := k.cdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + } + + // cache-wrap context as to not persist state changes during querying + ctx, _ = ctx.CacheContext() + + var totalRewards sdk.DecCoins + + k.stakingKeeper.IterateDelegations( + ctx, params.DelegatorAddr, + func(_ int64, del sdk.Delegation) (stop bool) { + val := k.stakingKeeper.Validator(ctx, del.GetValidatorAddr()) + endingPeriod := k.incrementValidatorPeriod(ctx, val) + rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod) + + totalRewards = totalRewards.Plus(rewards) + return false + }, + ) + + bz, err := codec.MarshalJSONIndent(k.cdc, totalRewards) + if err != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + } + return bz, nil }