Merge PR #4101: Return per-validator rewards when querying delegator rewards
This commit is contained in:
parent
9cdd1d3e9e
commit
769370801d
|
@ -0,0 +1,2 @@
|
|||
#3715 query distr rewards returns per-validator
|
||||
rewards along with rewards total amount.
|
|
@ -0,0 +1,3 @@
|
|||
#3715 Update /distribution/delegators/{delegatorAddr}/rewards GET endpoint
|
||||
as per new specs. For a given delegation, the endpoint now returns the
|
||||
comprehensive list of validator-reward tuples along with the grand total.
|
|
@ -3,6 +3,7 @@ package lcd
|
|||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
@ -27,6 +28,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
dclcommon "github.com/cosmos/cosmos-sdk/x/distribution/client/common"
|
||||
distrrest "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
|
||||
disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
|
@ -1003,9 +1005,10 @@ func TestDistributionFlow(t *testing.T) {
|
|||
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
|
||||
|
||||
// Query delegator's rewards total
|
||||
var delRewards disttypes.QueryDelegatorTotalRewardsResponse
|
||||
res, body = Request(t, port, "GET", fmt.Sprintf("/distribution/delegators/%s/rewards", operAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &rewards))
|
||||
require.NoError(t, json.Unmarshal([]byte(body), &delRewards))
|
||||
|
||||
// Query delegator's withdrawal address
|
||||
var withdrawAddr string
|
||||
|
|
|
@ -1470,9 +1470,7 @@ paths:
|
|||
200:
|
||||
description: OK
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Coin"
|
||||
$ref: "#/definitions/DelegatorTotalRewards"
|
||||
400:
|
||||
description: Invalid delegator address
|
||||
500:
|
||||
|
@ -2096,6 +2094,26 @@ definitions:
|
|||
$ref: "#/definitions/BlockID"
|
||||
block:
|
||||
$ref: "#/definitions/Block"
|
||||
DelegationDelegatorReward:
|
||||
type: object
|
||||
properties:
|
||||
validator_address:
|
||||
$ref: "#/definitions/ValidatorAddress"
|
||||
reward:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Coin"
|
||||
DelegatorTotalRewards:
|
||||
type: object
|
||||
properties:
|
||||
rewards:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/DelegationDelegatorReward"
|
||||
total:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Coin"
|
||||
BaseReq:
|
||||
type: object
|
||||
properties:
|
||||
|
|
|
@ -427,6 +427,33 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
f.Cleanup()
|
||||
}
|
||||
|
||||
func TestGaiaCLIQueryRewards(t *testing.T) {
|
||||
t.Parallel()
|
||||
f := InitFixtures(t)
|
||||
|
||||
genesisState := f.GenesisState()
|
||||
inflationMin := sdk.MustNewDecFromStr("10000.0")
|
||||
genesisState.MintData.Minter.Inflation = inflationMin
|
||||
genesisState.MintData.Params.InflationMin = inflationMin
|
||||
genesisState.MintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0")
|
||||
genFile := filepath.Join(f.GaiadHome, "config", "genesis.json")
|
||||
genDoc, err := tmtypes.GenesisDocFromFile(genFile)
|
||||
require.NoError(t, err)
|
||||
cdc := app.MakeCodec()
|
||||
genDoc.AppState, err = cdc.MarshalJSON(genesisState)
|
||||
require.NoError(t, genDoc.SaveAs(genFile))
|
||||
|
||||
// start gaiad server
|
||||
proc := f.GDStart()
|
||||
defer proc.Stop(false)
|
||||
|
||||
fooAddr := f.KeyAddress(keyFoo)
|
||||
rewards := f.QueryRewards(fooAddr)
|
||||
require.Equal(t, 1, len(rewards.Rewards))
|
||||
|
||||
f.Cleanup()
|
||||
}
|
||||
|
||||
func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||
t.Parallel()
|
||||
f := InitFixtures(t)
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
|
@ -617,6 +618,21 @@ func (f *Fixtures) QuerySlashingParams() slashing.Params {
|
|||
return params
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// query distribution
|
||||
|
||||
// QuerySigningInfo returns the signing info for a validator
|
||||
func (f *Fixtures) QueryRewards(delAddr sdk.AccAddress, flags ...string) distribution.QueryDelegatorTotalRewardsResponse {
|
||||
cmd := fmt.Sprintf("%s query distr rewards %s %s", f.GaiacliBinary, delAddr, f.Flags())
|
||||
res, errStr := tests.ExecuteT(f.T, cmd, "")
|
||||
require.Empty(f.T, errStr)
|
||||
cdc := app.MakeCodec()
|
||||
var rewards distribution.QueryDelegatorTotalRewardsResponse
|
||||
err := cdc.UnmarshalJSON([]byte(res), &rewards)
|
||||
require.NoError(f.T, err)
|
||||
return rewards
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// executors
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@ type (
|
|||
QueryValidatorSlashesParams = keeper.QueryValidatorSlashesParams
|
||||
QueryDelegationRewardsParams = keeper.QueryDelegationRewardsParams
|
||||
QueryDelegatorWithdrawAddrParams = keeper.QueryDelegatorWithdrawAddrParams
|
||||
|
||||
// querier response types
|
||||
QueryDelegatorTotalRewardsResponse = types.QueryDelegatorTotalRewardsResponse
|
||||
DelegationDelegatorReward = types.DelegationDelegatorReward
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -144,20 +144,25 @@ $ gaiacli query distr rewards cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosm
|
|||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
var resp []byte
|
||||
var err error
|
||||
if len(args) == 2 {
|
||||
// query for rewards from a particular delegation
|
||||
resp, err = common.QueryDelegationRewards(cliCtx, cdc, queryRoute, args[0], args[1])
|
||||
} else {
|
||||
// query for delegator total rewards
|
||||
resp, err = common.QueryDelegatorTotalRewards(cliCtx, cdc, queryRoute, args[0])
|
||||
resp, err := common.QueryDelegationRewards(cliCtx, cdc, queryRoute, args[0], args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var result sdk.DecCoins
|
||||
cdc.MustUnmarshalJSON(resp, &result)
|
||||
return cliCtx.PrintOutput(result)
|
||||
}
|
||||
|
||||
// query for delegator total rewards
|
||||
resp, err := common.QueryDelegatorTotalRewards(cliCtx, cdc, queryRoute, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var result sdk.DecCoins
|
||||
var result distr.QueryDelegatorTotalRewardsResponse
|
||||
cdc.MustUnmarshalJSON(resp, &result)
|
||||
return cliCtx.PrintOutput(result)
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package keeper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
@ -251,21 +252,25 @@ func queryDelegatorTotalRewards(ctx sdk.Context, _ []string, req abci.RequestQue
|
|||
// cache-wrap context as to not persist state changes during querying
|
||||
ctx, _ = ctx.CacheContext()
|
||||
|
||||
totalRewards := sdk.DecCoins{}
|
||||
total := sdk.DecCoins{}
|
||||
var delRewards []types.DelegationDelegatorReward
|
||||
|
||||
k.stakingKeeper.IterateDelegations(
|
||||
ctx, params.DelegatorAddress,
|
||||
func(_ int64, del sdk.Delegation) (stop bool) {
|
||||
val := k.stakingKeeper.Validator(ctx, del.GetValidatorAddr())
|
||||
valAddr := del.GetValidatorAddr()
|
||||
val := k.stakingKeeper.Validator(ctx, valAddr)
|
||||
endingPeriod := k.incrementValidatorPeriod(ctx, val)
|
||||
rewards := k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
||||
delReward := k.calculateDelegationRewards(ctx, val, del, endingPeriod)
|
||||
|
||||
totalRewards = totalRewards.Add(rewards)
|
||||
delRewards = append(delRewards, types.NewDelegationDelegatorReward(valAddr, delReward))
|
||||
total = total.Add(delReward)
|
||||
return false
|
||||
},
|
||||
)
|
||||
|
||||
bz, err := codec.MarshalJSONIndent(k.cdc, totalRewards)
|
||||
totalRewards := types.NewQueryDelegatorTotalRewardsResponse(delRewards, total)
|
||||
bz, err := json.Marshal(totalRewards)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error()))
|
||||
}
|
||||
|
|
|
@ -109,6 +109,19 @@ func getQueriedDelegationRewards(t *testing.T, ctx sdk.Context, cdc *codec.Codec
|
|||
return
|
||||
}
|
||||
|
||||
func getQueriedDelegatorTotalRewards(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier, delegatorAddr sdk.AccAddress) (response types.QueryDelegatorTotalRewardsResponse) {
|
||||
query := abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, QueryDelegatorTotalRewards}, "/"),
|
||||
Data: cdc.MustMarshalJSON(NewQueryDelegatorParams(delegatorAddr)),
|
||||
}
|
||||
|
||||
bz, err := querier(ctx, []string{QueryDelegatorTotalRewards}, query)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, cdc.UnmarshalJSON(bz, &response))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getQueriedCommunityPool(t *testing.T, ctx sdk.Context, cdc *codec.Codec, querier sdk.Querier) (ptr []byte) {
|
||||
query := abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, QueryCommunityPool}, ""),
|
||||
|
@ -124,6 +137,7 @@ func getQueriedCommunityPool(t *testing.T, ctx sdk.Context, cdc *codec.Codec, qu
|
|||
|
||||
func TestQueries(t *testing.T) {
|
||||
cdc := codec.New()
|
||||
types.RegisterCodec(cdc)
|
||||
ctx, _, keeper, sk, _ := CreateTestInputDefault(t, false, 100)
|
||||
querier := NewQuerier(keeper)
|
||||
|
||||
|
@ -154,6 +168,10 @@ func TestQueries(t *testing.T) {
|
|||
retCommission := getQueriedValidatorCommission(t, ctx, cdc, querier, valOpAddr1)
|
||||
require.Equal(t, commission, retCommission)
|
||||
|
||||
// test delegator's total rewards query
|
||||
delRewards := getQueriedDelegatorTotalRewards(t, ctx, cdc, querier, sdk.AccAddress(valOpAddr1))
|
||||
require.Equal(t, types.QueryDelegatorTotalRewardsResponse{}, delRewards)
|
||||
|
||||
// test validator slashes query with height range
|
||||
slashOne := types.NewValidatorSlashEvent(3, sdk.NewDecWithPrec(5, 1))
|
||||
slashTwo := types.NewValidatorSlashEvent(7, sdk.NewDecWithPrec(6, 1))
|
||||
|
@ -183,6 +201,14 @@ func TestQueries(t *testing.T) {
|
|||
rewards = getQueriedDelegationRewards(t, ctx, cdc, querier, sdk.AccAddress(valOpAddr1), valOpAddr1)
|
||||
require.Equal(t, sdk.DecCoins{{sdk.DefaultBondDenom, sdk.NewDec(initial / 2)}}, rewards)
|
||||
|
||||
// test delegator's total rewards query
|
||||
delRewards = getQueriedDelegatorTotalRewards(t, ctx, cdc, querier, sdk.AccAddress(valOpAddr1))
|
||||
expectedDelReward := types.NewDelegationDelegatorReward(valOpAddr1,
|
||||
sdk.DecCoins{sdk.NewInt64DecCoin("stake", 5)})
|
||||
wantDelRewards := types.NewQueryDelegatorTotalRewardsResponse(
|
||||
[]types.DelegationDelegatorReward{expectedDelReward}, expectedDelReward.Reward)
|
||||
require.Equal(t, wantDelRewards, delRewards)
|
||||
|
||||
// currently community pool hold nothing so we should return null
|
||||
communityPool := getQueriedCommunityPool(t, ctx, cdc, querier)
|
||||
require.Nil(t, communityPool)
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// QueryDelegatorTotalRewardsResponse defines the properties of
|
||||
// QueryDelegatorTotalRewards query's response.
|
||||
type QueryDelegatorTotalRewardsResponse struct {
|
||||
Rewards []DelegationDelegatorReward `json:"rewards"`
|
||||
Total sdk.DecCoins `json:"total"`
|
||||
}
|
||||
|
||||
// NewQueryDelegatorTotalRewardsResponse constructs a QueryDelegatorTotalRewardsResponse
|
||||
func NewQueryDelegatorTotalRewardsResponse(rewards []DelegationDelegatorReward,
|
||||
total sdk.DecCoins) QueryDelegatorTotalRewardsResponse {
|
||||
return QueryDelegatorTotalRewardsResponse{Rewards: rewards, Total: total}
|
||||
}
|
||||
|
||||
func (res QueryDelegatorTotalRewardsResponse) String() string {
|
||||
out := "Delegator Total Rewards:\n"
|
||||
out += " Rewards:"
|
||||
for _, reward := range res.Rewards {
|
||||
out += fmt.Sprintf(`
|
||||
ValidatorAddress: %s
|
||||
Reward: %s`, reward.ValidatorAddress, reward.Reward)
|
||||
}
|
||||
out += fmt.Sprintf("\n Total: %s\n", res.Total)
|
||||
return strings.TrimSpace(out)
|
||||
}
|
||||
|
||||
// DelegationDelegatorReward defines the properties
|
||||
// of a delegator's delegation reward.
|
||||
type DelegationDelegatorReward struct {
|
||||
ValidatorAddress sdk.ValAddress `json:"validator_address"`
|
||||
Reward sdk.DecCoins `json:"reward"`
|
||||
}
|
||||
|
||||
// NewDelegationDelegatorReward constructs a DelegationDelegatorReward.
|
||||
func NewDelegationDelegatorReward(valAddr sdk.ValAddress,
|
||||
reward sdk.DecCoins) DelegationDelegatorReward {
|
||||
return DelegationDelegatorReward{ValidatorAddress: valAddr, Reward: reward}
|
||||
}
|
Loading…
Reference in New Issue