Skip to content

Commit

Permalink
Merge PR #4183: Cherry pick 4181 into v0.34.2
Browse files Browse the repository at this point in the history
* Support pagination and status query params for /staking/validators

* Rename BondStatusToString to String

* Cherry pick 4181

* Remove pending log
  • Loading branch information
alexanderbez authored and jackzampolin committed Apr 24, 2019
1 parent 66a913c commit 94bc55e
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 36 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ to generate only usage.
* [\#4135](https://github.com/cosmos/cosmos-sdk/pull/4135) Fix `NewResponseFormatBroadcastTxCommit`
* [\#4053](https://github.com/cosmos/cosmos-sdk/issues/4053) Add `--inv-check-period`
flag to gaiad to set period at which invariants checks will run.
* [\#4099](https://github.com/cosmos/cosmos-sdk/issues/4099) Update the /staking/validators endpoint to support
status and pagination query flags.

## 0.34.1

Expand Down
18 changes: 17 additions & 1 deletion client/lcd/swagger-ui/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,23 @@ paths:
description: Internal Server Error
/staking/validators:
get:
summary: Get all validator candidates
summary: Get all validator candidates. By default it returns only the bonded validators.
parameters:
- in: query
name: status
type: string
description: The validator bond status. Must be either 'bonded', 'unbonded', or 'unbonding'.
x-example: bonded
- in: query
name: page
description: The gage number.
type: integer
x-example: 1
- in: query
name: limit
description: The maximum number of items per page.
type: integer
x-example: 1
tags:
- ICS21
produces:
Expand Down
1 change: 0 additions & 1 deletion client/tx/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ func QueryTxsByTagsRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec)
}

tags, page, limit, err = rest.ParseHTTPArgs(r)

if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
Expand Down
16 changes: 10 additions & 6 deletions types/staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,23 @@ const (
// Constant as this should not change without a hard fork.
// TODO: Link to some Tendermint docs, this is very unobvious.
ValidatorUpdateDelay int64 = 1

BondStatusUnbonded = "Unbonded"
BondStatusUnbonding = "Unbonding"
BondStatusBonded = "Bonded"
)

//BondStatusToString for pretty prints of Bond Status
func BondStatusToString(b BondStatus) string {
// String implements the Stringer interface for BondStatus.
func (b BondStatus) String() string {
switch b {
case 0x00:
return "Unbonded"
return BondStatusUnbonded
case 0x01:
return "Unbonding"
return BondStatusUnbonding
case 0x02:
return "Bonded"
return BondStatusBonded
default:
panic("improper use of BondStatusToString")
panic("invalid bond status")
}
}

Expand Down
10 changes: 6 additions & 4 deletions x/staking/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type (
QueryValidatorParams = querier.QueryValidatorParams
QueryBondsParams = querier.QueryBondsParams
QueryRedelegationParams = querier.QueryRedelegationParams
QueryValidatorsParams = querier.QueryValidatorsParams
)

var (
Expand Down Expand Up @@ -97,10 +98,11 @@ var (
NewMsgUndelegate = types.NewMsgUndelegate
NewMsgBeginRedelegate = types.NewMsgBeginRedelegate

NewQuerier = querier.NewQuerier
NewQueryDelegatorParams = querier.NewQueryDelegatorParams
NewQueryValidatorParams = querier.NewQueryValidatorParams
NewQueryBondsParams = querier.NewQueryBondsParams
NewQuerier = querier.NewQuerier
NewQueryDelegatorParams = querier.NewQueryDelegatorParams
NewQueryValidatorParams = querier.NewQueryValidatorParams
NewQueryBondsParams = querier.NewQueryBondsParams
NewQueryValidatorsParams = querier.NewQueryValidatorsParams
)

const (
Expand Down
28 changes: 26 additions & 2 deletions x/staking/client/rest/query.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package rest

import (
"fmt"
"net/http"
"strings"

Expand All @@ -15,7 +16,6 @@ import (
)

func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec) {

// Get all delegations from a delegator
r.HandleFunc(
"/staking/delegators/{delegatorAddr}/delegations",
Expand Down Expand Up @@ -249,7 +249,31 @@ func delegatorValidatorHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) ht
// HTTP request handler to query list of validators
func validatorsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
res, err := cliCtx.QueryWithData("custom/staking/validators", nil)
_, page, limit, err := rest.ParseHTTPArgs(r)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}

// override default limit if it wasn't provided
if l := r.FormValue("limit"); l == "" {
limit = 0
}

status := r.FormValue("status")
if status == "" {
status = sdk.BondStatusBonded
}

params := staking.NewQueryValidatorsParams(page, limit, status)
bz, err := cdc.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}

route := fmt.Sprintf("custom/%s/%s", staking.QuerierRoute, staking.QueryValidators)
res, err := cliCtx.QueryWithData(route, bz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
Expand Down
5 changes: 2 additions & 3 deletions x/staking/keeper/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,8 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) {

assert.Equal(
t, status, val.GetStatus(),
fmt.Sprintf("expected validator at index %v to have status: %s",
valIdx,
sdk.BondStatusToString(status)))
fmt.Sprintf("expected validator at index %v to have status: %s", valIdx, status),
)
}
}

Expand Down
55 changes: 50 additions & 5 deletions x/staking/querier/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package querier

import (
"fmt"
"strings"

abci "github.com/tendermint/tendermint/abci/types"

Expand Down Expand Up @@ -35,7 +36,7 @@ func NewQuerier(k keep.Keeper, cdc *codec.Codec) sdk.Querier {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) {
switch path[0] {
case QueryValidators:
return queryValidators(ctx, cdc, k)
return queryValidators(ctx, cdc, req, k)
case QueryValidator:
return queryValidator(ctx, cdc, req, k)
case QueryValidatorDelegations:
Expand Down Expand Up @@ -128,14 +129,47 @@ func NewQueryRedelegationParams(delegatorAddr sdk.AccAddress, srcValidatorAddr s
}
}

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

err := cdc.UnmarshalJSON(req.Data, &params)
if err != nil {
return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err))
}

stakingParams := k.GetParams(ctx)
validators := k.GetValidators(ctx, stakingParams.MaxValidators)
if params.Limit == 0 {
params.Limit = int(stakingParams.MaxValidators)
}

validators := k.GetAllValidators(ctx)
filteredVals := make([]types.Validator, 0, len(validators))

for _, val := range validators {
if strings.ToLower(val.GetStatus().String()) == strings.ToLower(params.Status) {
filteredVals = append(filteredVals, val)
}
}

// get pagination bounds
start := (params.Page - 1) * params.Limit
end := params.Limit + start
if end >= len(filteredVals) {
end = len(filteredVals)
}

res, errRes := codec.MarshalJSONIndent(cdc, validators)
if start >= len(filteredVals) {
// page is out of bounds
filteredVals = []types.Validator{}
} else {
filteredVals = filteredVals[start:end]
}

res, err := codec.MarshalJSONIndent(cdc, filteredVals)
if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error()))
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error()))
}

return res, nil
}

Expand Down Expand Up @@ -354,3 +388,14 @@ func queryParameters(ctx sdk.Context, cdc *codec.Codec, k keep.Keeper) (res []by
}
return res, nil
}

// QueryValidatorsParams defines the params for the following queries:
// - 'custom/staking/validators'
type QueryValidatorsParams struct {
Page, Limit int
Status string
}

func NewQueryValidatorsParams(page, limit int, status string) QueryValidatorsParams {
return QueryValidatorsParams{page, limit, status}
}
40 changes: 27 additions & 13 deletions x/staking/querier/querier_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package querier

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -44,9 +45,6 @@ func TestNewQuerier(t *testing.T) {
require.NotNil(t, err)
require.Nil(t, bz)

_, err = querier(ctx, []string{"validators"}, query)
require.Nil(t, err)

_, err = querier(ctx, []string{"pool"}, query)
require.Nil(t, err)

Expand Down Expand Up @@ -121,28 +119,44 @@ func TestQueryValidators(t *testing.T) {
params := keeper.GetParams(ctx)

// Create Validators
amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8)}
var validators [2]types.Validator
amts := []sdk.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)}
status := []sdk.BondStatus{sdk.Bonded, sdk.Unbonded, sdk.Unbonding}
var validators [3]types.Validator
for i, amt := range amts {
validators[i] = types.NewValidator(sdk.ValAddress(keep.Addrs[i]), keep.PKs[i], types.Description{})
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt)
validators[i], pool = validators[i].UpdateStatus(pool, status[i])
}

keeper.SetPool(ctx, pool)
keeper.SetValidator(ctx, validators[0])
keeper.SetValidator(ctx, validators[1])
keeper.SetValidator(ctx, validators[2])

// Query Validators
queriedValidators := keeper.GetValidators(ctx, params.MaxValidators)

res, err := queryValidators(ctx, cdc, keeper)
require.Nil(t, err)
for i, s := range status {
queryValsParams := NewQueryValidatorsParams(1, int(params.MaxValidators), s.String())
bz, errRes := cdc.MarshalJSON(queryValsParams)
require.Nil(t, errRes)

var validatorsResp []types.Validator
errRes := cdc.UnmarshalJSON(res, &validatorsResp)
require.Nil(t, errRes)
req := abci.RequestQuery{
Path: fmt.Sprintf("/custom/%s/%s", types.QuerierRoute, QueryValidators),
Data: bz,
}

res, err := queryValidators(ctx, cdc, req, keeper)
require.Nil(t, err)

require.Equal(t, len(queriedValidators), len(validatorsResp))
require.ElementsMatch(t, queriedValidators, validatorsResp)
var validatorsResp []types.Validator
errRes = cdc.UnmarshalJSON(res, &validatorsResp)
require.Nil(t, errRes)

require.Equal(t, 1, len(validatorsResp))
require.ElementsMatch(t, validators[i].OperatorAddress, validatorsResp[0].OperatorAddress)

}

// Query each validator
queryParams := NewQueryValidatorParams(addrVal1)
Expand All @@ -153,7 +167,7 @@ func TestQueryValidators(t *testing.T) {
Path: "/custom/staking/validator",
Data: bz,
}
res, err = queryValidator(ctx, cdc, query, keeper)
res, err := queryValidator(ctx, cdc, query, keeper)
require.Nil(t, err)

var validator types.Validator
Expand Down
2 changes: 1 addition & 1 deletion x/staking/types/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (v Validator) String() string {
Unbonding Completion Time: %v
Minimum Self Delegation: %v
Commission: %s`, v.OperatorAddress, bechConsPubKey,
v.Jailed, sdk.BondStatusToString(v.Status), v.Tokens,
v.Jailed, v.Status, v.Tokens,
v.DelegatorShares, v.Description,
v.UnbondingHeight, v.UnbondingCompletionTime, v.MinSelfDelegation, v.Commission)
}
Expand Down

0 comments on commit 94bc55e

Please sign in to comment.