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

R4R: Querier - Get all delegations to validator #2565

Merged
merged 19 commits into from
Nov 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like there should be a helper function like StakeValidatorsDelegationsPath(validatorAddr.String())

https://guides.rubyonrails.org/routing.html#path-and-url-helpers

In Ruby, you can use magic to create such functions on the fly. In Go, we'd need to write them ourselves. Still, there may be a benefit in having them.

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]",
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
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()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because this is such a simple function, we should probably just close the iterator after the for loop and avoid using a defer call


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)
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
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()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

split this line up?

}
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