Skip to content

Commit

Permalink
R4R: Querier - Get all delegations to validator (#2565)
Browse files Browse the repository at this point in the history
* added querier redelegation and CLI/LCD calls
  • Loading branch information
jackzampolin authored Nov 13, 2018
2 parents 12ad39e + f38f57d commit 23e8415
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 45 deletions.
3 changes: 2 additions & 1 deletion PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ FEATURES
* Gaia REST API (`gaiacli advanced rest-server`)

* Gaia CLI (`gaiacli`)

* [stake][cli] [\#2027] Add CLI query command for getting all delegations to a specific validator.

* Gaia

* SDK
Expand Down
17 changes: 16 additions & 1 deletion client/lcd/lcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,14 +539,18 @@ func TestBonding(t *testing.T) {

require.Equal(t, int64(40), coins.AmountOf(denom).Int64())

// query validator
// query delegation
bond := getDelegation(t, port, addr, operAddrs[0])
require.Equal(t, amt, bond.Shares)

delegatorDels := getDelegatorDelegations(t, port, addr)
require.Len(t, delegatorDels, 1)
require.Equal(t, amt, delegatorDels[0].Shares)

// query all delegations to validator
bonds := getValidatorDelegations(t, port, operAddrs[0])
require.Len(t, bonds, 2)

bondedValidators := getDelegatorValidators(t, port, addr)
require.Len(t, bondedValidators, 1)
require.Equal(t, operAddrs[0], bondedValidators[0].OperatorAddr)
Expand Down Expand Up @@ -1207,6 +1211,17 @@ func getValidator(t *testing.T, port string, validatorAddr sdk.ValAddress) stake
return validator
}

func getValidatorDelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.Delegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/delegations", validatorAddr.String()), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)

var delegations []stake.Delegation
err := cdc.UnmarshalJSON([]byte(body), &delegations)
require.Nil(t, err)

return delegations
}

func getValidatorUnbondingDelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.UnbondingDelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/unbonding_delegations", validatorAddr.String()), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
Expand Down
24 changes: 24 additions & 0 deletions client/lcd/swagger-ui/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,30 @@ paths:
description: Invalid validator address
500:
description: Internal Server Error
/stake/validators/{validatorAddr}/delegations:
parameters:
- in: path
name: validatorAddr
description: Bech32 OperatorAddress of validator
required: true
type: string
get:
summary: Get all delegations from a validator
tags:
- ICS21
produces:
- application/json
responses:
200:
description: OK
schema:
type: array
items:
$ref: "#/definitions/Delegation"
400:
description: Invalid validator address
500:
description: Internal Server Error
/stake/validators/{validatorAddr}/unbonding_delegations:
parameters:
- in: path
Expand Down
13 changes: 13 additions & 0 deletions cmd/gaia/cli_test/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ func TestGaiaCLICreateValidator(t *testing.T) {
require.Equal(t, validator.OperatorAddr, sdk.ValAddress(barAddr))
require.True(sdk.DecEq(t, sdk.NewDec(2), validator.Tokens))

validatorDelegations := executeGetValidatorDelegations(t, fmt.Sprintf("gaiacli query stake delegations-to %s --output=json %v", sdk.ValAddress(barAddr), flags))
require.Len(t, validatorDelegations, 1)
require.NotZero(t, validatorDelegations[0].Shares)

// unbond a single share
unbondStr := fmt.Sprintf("gaiacli tx stake unbond begin %v", flags)
unbondStr += fmt.Sprintf(" --from=%s", "bar")
Expand Down Expand Up @@ -750,6 +754,15 @@ func executeGetValidatorRedelegations(t *testing.T, cmdStr string) []stake.Redel
return reds
}

func executeGetValidatorDelegations(t *testing.T, cmdStr string) []stake.Delegation {
out, _ := tests.ExecuteT(t, cmdStr, "")
var delegations []stake.Delegation
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &delegations)
require.NoError(t, err, "out %v\n, err %v", out, err)
return delegations
}

func executeGetPool(t *testing.T, cmdStr string) stake.Pool {
out, _ := tests.ExecuteT(t, cmdStr, "")
var pool stake.Pool
Expand Down
1 change: 1 addition & 0 deletions cmd/gaia/cmd/gaiacli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func queryCmd(cdc *amino.Codec) *cobra.Command {
stakecmd.GetCmdQueryRedelegations(storeStake, cdc),
stakecmd.GetCmdQueryValidator(storeStake, cdc),
stakecmd.GetCmdQueryValidators(storeStake, cdc),
stakecmd.GetCmdQueryValidatorDelegations(storeStake, cdc),
stakecmd.GetCmdQueryValidatorUnbondingDelegations(queryRouteStake, cdc),
stakecmd.GetCmdQueryValidatorRedelegations(queryRouteStake, cdc),
stakecmd.GetCmdQueryParams(storeStake, cdc),
Expand Down
7 changes: 7 additions & 0 deletions docs/sdk/clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,13 @@ Additionally, as you can get all the outgoing redelegations from a particular va

To get previous redelegation(s) status on past blocks, try adding the `--height` flag.

##### Query Delegations To Validator

You can also query all of the delegations to a particular validator:
```bash
gaiacli query delegations-to <account_cosmosval>
```

### Governance

Governance is the process from which users in the Cosmos Hub can come to consensus on software upgrades, parameters of the mainnet or on custom text proposals. This is done through voting on proposals, which will be submitted by `Atom` holders on the mainnet.
Expand Down
43 changes: 37 additions & 6 deletions x/stake/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,7 @@ func GetCmdQueryValidatorUnbondingDelegations(queryRoute string, cdc *codec.Code
}

cliCtx := context.NewCLIContext().WithCodec(cdc)
params := stake.QueryValidatorParams{
ValidatorAddr: valAddr,
}
params := stake.NewQueryValidatorParams(valAddr)

bz, err := cdc.MarshalJSON(params)
if err != nil {
Expand Down Expand Up @@ -164,9 +162,7 @@ func GetCmdQueryValidatorRedelegations(queryRoute string, cdc *codec.Codec) *cob
}

cliCtx := context.NewCLIContext().WithCodec(cdc)
params := stake.QueryValidatorParams{
ValidatorAddr: valAddr,
}
params := stake.NewQueryValidatorParams(valAddr)

bz, err := cdc.MarshalJSON(params)
if err != nil {
Expand Down Expand Up @@ -290,6 +286,41 @@ func GetCmdQueryDelegations(storeName string, cdc *codec.Codec) *cobra.Command {
return cmd
}

// GetCmdQueryValidatorDelegations implements the command to query all the
// delegations to a specific validator.
func GetCmdQueryValidatorDelegations(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "delegations-to [validator-addr]",
Short: "Query all delegations made to one validator",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
validatorAddr, err := sdk.ValAddressFromBech32(args[0])
if err != nil {
return err
}

params := stake.NewQueryValidatorParams(validatorAddr)

bz, err := cdc.MarshalJSON(params)
if err != nil {
return err
}

cliCtx := context.NewCLIContext().WithCodec(cdc)

res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/validatorDelegations", queryRoute), bz)
if err != nil {
return err
}

fmt.Println(string(res))
return nil
},
}

return cmd
}

// GetCmdQueryUnbondingDelegation implements the command to query a single
// unbonding-delegation record.
func GetCmdQueryUnbondingDelegation(storeName string, cdc *codec.Codec) *cobra.Command {
Expand Down
11 changes: 11 additions & 0 deletions x/stake/client/rest/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Co
validatorHandlerFn(cliCtx, cdc),
).Methods("GET")

// Get all delegations to a validator
r.HandleFunc(
"/stake/validators/{validatorAddr}/delegations",
validatorDelegationsHandlerFn(cliCtx, cdc),
).Methods("GET")

// Get all unbonding delegations from a validator
r.HandleFunc(
"/stake/validators/{validatorAddr}/unbonding_delegations",
Expand Down Expand Up @@ -227,6 +233,11 @@ func validatorHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.Handle
return queryValidator(cliCtx, cdc, "custom/stake/validator")
}

// HTTP request handler to query all unbonding delegations from a validator
func validatorDelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
return queryValidator(cliCtx, cdc, "custom/stake/validatorDelegations")
}

// HTTP request handler to query all unbonding delegations from a validator
func validatorUnbondingDelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
return queryValidator(cliCtx, cdc, "custom/stake/validatorUnbondingDelegations")
Expand Down
13 changes: 3 additions & 10 deletions x/stake/client/rest/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,7 @@ func queryBonds(cliCtx context.CLIContext, cdc *codec.Codec, endpoint string) ht
return
}

params := stake.QueryBondsParams{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
}
params := stake.NewQueryBondsParams(delegatorAddr, validatorAddr)

bz, err := cdc.MarshalJSON(params)
if err != nil {
Expand Down Expand Up @@ -93,9 +90,7 @@ func queryDelegator(cliCtx context.CLIContext, cdc *codec.Codec, endpoint string
return
}

params := stake.QueryDelegatorParams{
DelegatorAddr: delegatorAddr,
}
params := stake.NewQueryDelegatorParams(delegatorAddr)

bz, err := cdc.MarshalJSON(params)
if err != nil {
Expand Down Expand Up @@ -123,9 +118,7 @@ func queryValidator(cliCtx context.CLIContext, cdc *codec.Codec, endpoint string
return
}

params := stake.QueryValidatorParams{
ValidatorAddr: validatorAddr,
}
params := stake.NewQueryValidatorParams(validatorAddr)

bz, err := cdc.MarshalJSON(params)
if err != nil {
Expand Down
15 changes: 15 additions & 0 deletions x/stake/keeper/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@ func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegati
return delegations
}

// return all delegations to a specific validator. Useful for querier.
func (k Keeper) GetValidatorDelegations(ctx sdk.Context, valAddr sdk.ValAddress) (delegations []types.Delegation) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, DelegationKey)
defer iterator.Close()

for ; iterator.Valid(); iterator.Next() {
delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
if delegation.GetValidatorAddr().Equals(valAddr) {
delegations = append(delegations, delegation)
}
}
return delegations
}

// return a given amount of all the delegations from a delegator
func (k Keeper) GetDelegatorDelegations(ctx sdk.Context, delegator sdk.AccAddress,
maxRetrieve uint16) (delegations []types.Delegation) {
Expand Down
3 changes: 3 additions & 0 deletions x/stake/keeper/delegation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ func TestDelegation(t *testing.T) {
resVal, err = keeper.GetDelegatorValidator(ctx, addrDels[1], addrVals[i])
require.Nil(t, err)
require.Equal(t, addrVals[i], resVal.GetOperator())

resDels := keeper.GetValidatorDelegations(ctx, addrVals[i])
require.Len(t, resDels, 2)
}

// delete a record
Expand Down
43 changes: 43 additions & 0 deletions x/stake/querier/queryable.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const (
QueryDelegatorDelegations = "delegatorDelegations"
QueryDelegatorUnbondingDelegations = "delegatorUnbondingDelegations"
QueryDelegatorRedelegations = "delegatorRedelegations"
QueryValidatorDelegations = "validatorDelegations"
QueryValidatorUnbondingDelegations = "validatorUnbondingDelegations"
QueryValidatorRedelegations = "validatorRedelegations"
QueryDelegator = "delegator"
Expand All @@ -34,6 +35,8 @@ func NewQuerier(k keep.Keeper, cdc *codec.Codec) sdk.Querier {
return queryValidators(ctx, cdc, k)
case QueryValidator:
return queryValidator(ctx, cdc, req, k)
case QueryValidatorDelegations:
return queryValidatorDelegations(ctx, cdc, req, k)
case QueryValidatorUnbondingDelegations:
return queryValidatorUnbondingDelegations(ctx, cdc, req, k)
case QueryValidatorRedelegations:
Expand Down Expand Up @@ -73,6 +76,7 @@ type QueryDelegatorParams struct {

// defines the params for the following queries:
// - 'custom/stake/validator'
// - 'custom/stake/validatorDelegations'
// - 'custom/stake/validatorUnbondingDelegations'
// - 'custom/stake/validatorRedelegations'
type QueryValidatorParams struct {
Expand All @@ -88,6 +92,28 @@ type QueryBondsParams struct {
ValidatorAddr sdk.ValAddress
}

// creates a new QueryDelegatorParams
func NewQueryDelegatorParams(delegatorAddr sdk.AccAddress) QueryDelegatorParams {
return QueryDelegatorParams{
DelegatorAddr: delegatorAddr,
}
}

// creates a new QueryValidatorParams
func NewQueryValidatorParams(validatorAddr sdk.ValAddress) QueryValidatorParams {
return QueryValidatorParams{
ValidatorAddr: validatorAddr,
}
}

// creates a new QueryBondsParams
func NewQueryBondsParams(delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) QueryBondsParams {
return QueryBondsParams{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
}
}

func queryValidators(ctx sdk.Context, cdc *codec.Codec, k keep.Keeper) (res []byte, err sdk.Error) {
stakeParams := k.GetParams(ctx)
validators := k.GetValidators(ctx, stakeParams.MaxValidators)
Expand Down Expand Up @@ -119,6 +145,23 @@ func queryValidator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k
return res, nil
}

func queryValidatorDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) {
var params QueryValidatorParams

errRes := cdc.UnmarshalJSON(req.Data, &params)
if errRes != nil {
return []byte{}, sdk.ErrUnknownAddress("")
}

delegations := k.GetValidatorDelegations(ctx, params.ValidatorAddr)

res, errRes = codec.MarshalJSONIndent(cdc, delegations)
if errRes != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error()))
}
return res, nil
}

func queryValidatorUnbondingDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) {
var params QueryValidatorParams

Expand Down
Loading

0 comments on commit 23e8415

Please sign in to comment.