Skip to content

Commit

Permalink
Add route for querying signing_info for all validators (#3952)
Browse files Browse the repository at this point in the history
Also remove duplicate pagination:
- move function to extract query params into types/rest
- adjust pagination values locally until available in tendermint for validators

Code cleanup:
- helper function in test
- fix pagination description in swagger.yaml
- uint instead of int when possible

Closes: #3226
Closes: #3991
  • Loading branch information
sabau authored and alessio committed Mar 28, 2019
1 parent e5897d8 commit 5bb6090
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 90 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#3949 added /slashing/signing_infos to get signing_info for all validators
2 changes: 2 additions & 0 deletions client/lcd/lcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,8 @@ func TestUnjail(t *testing.T) {
require.Equal(t, true, signingInfo.IndexOffset > 0)
require.Equal(t, time.Unix(0, 0).UTC(), signingInfo.JailedUntil)
require.Equal(t, true, signingInfo.MissedBlocksCounter == 0)
signingInfoList := getSigningInfoList(t, port)
require.NotZero(t, len(signingInfoList))
}

func TestProposalsQuery(t *testing.T) {
Expand Down
60 changes: 47 additions & 13 deletions client/lcd/swagger-ui/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,11 @@ paths:
required: true
- in: query
name: page
description: Pagination page
description: Page number
type: integer
- in: query
name: size
description: Pagination size
name: limit
description: Maximum number of items per page
type: integer
responses:
200:
Expand Down Expand Up @@ -885,22 +885,45 @@ paths:
200:
description: OK
schema:
type: object
properties:
start_height:
type: string
index_offset:
type: string
jailed_until:
type: string
missed_blocks_counter:
type: string
$ref: "#/definitions/SigningInfo"
204:
description: No sign info of this validator
400:
description: Invalid validator public key
500:
description: Internal Server Error
/slashing/signing_infos:
get:
summary: Get sign info of given all validators
description: Get sign info of all validators
produces:
- application/json
tags:
- ICS23
parameters:
- in: query
name: page
description: Page number
type: integer
required: true
- in: query
name: limit
description: Maximum number of items per page
type: integer
required: true
responses:
200:
description: OK
schema:
type: array
items:
$ref: "#/definitions/SigningInfo"
204:
description: No validators with sign info
400:
description: Invalid validator public key for one of the validators
500:
description: Internal Server Error
/slashing/validators/{validatorAddr}/unjail:
post:
summary: Unjail a jailed validator
Expand Down Expand Up @@ -2181,3 +2204,14 @@ definitions:
type: array
items:
$ref: "#/definitions/Coin"
SigningInfo:
type: object
properties:
start_height:
type: string
index_offset:
type: string
jailed_until:
type: string
missed_blocks_counter:
type: string
15 changes: 15 additions & 0 deletions client/lcd/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,21 @@ func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing.
return signingInfo
}

// ----------------------------------------------------------------------
// ICS 23 - SlashingList
// ----------------------------------------------------------------------
// GET /slashing/signing_infos Get sign info of all validators with pagination
func getSigningInfoList(t *testing.T, port string) []slashing.ValidatorSigningInfo {
res, body := Request(t, port, "GET", "/slashing/signing_infos?page=1&limit=1", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)

var signingInfo []slashing.ValidatorSigningInfo
err := cdc.UnmarshalJSON([]byte(body), &signingInfo)
require.Nil(t, err)

return signingInfo
}

// TODO: Test this functionality, it is not currently in any of the tests
// POST /slashing/validators/{validatorAddr}/unjail Unjail a jailed validator
func doUnjail(
Expand Down
8 changes: 4 additions & 4 deletions client/rpc/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func ValidatorCommand(cdc *codec.Codec) *cobra.Command {

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

result, err := getValidators(cliCtx, height)
result, err := GetValidators(cliCtx, height)
if err != nil {
return err
}
Expand Down Expand Up @@ -113,7 +113,7 @@ func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error
}, nil
}

func getValidators(cliCtx context.CLIContext, height *int64) (ResultValidatorsOutput, error) {
func GetValidators(cliCtx context.CLIContext, height *int64) (ResultValidatorsOutput, error) {
// get the node
node, err := cliCtx.GetNode()
if err != nil {
Expand Down Expand Up @@ -170,7 +170,7 @@ func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}

output, err := getValidators(cliCtx, &height)
output, err := GetValidators(cliCtx, &height)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
Expand All @@ -188,7 +188,7 @@ func LatestValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerF
return
}

output, err := getValidators(cliCtx, &height)
output, err := GetValidators(cliCtx, &height)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
Expand Down
68 changes: 8 additions & 60 deletions client/tx/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"
rest "github.com/cosmos/cosmos-sdk/types/rest"

"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand All @@ -22,12 +20,10 @@ import (
)

const (
flagTags = "tags"
flagAny = "any"
flagPage = "page"
flagLimit = "limit"
defaultPage = 1
defaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19
flagTags = "tags"
flagAny = "any"
flagPage = "page"
flagLimit = "limit"
)

// default client command to search through tagged transactions
Expand Down Expand Up @@ -96,8 +92,8 @@ $ gaiacli query txs --tags '<tag1>:<value1>&<tag2>:<value2>' --page 1 --limit 30
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
cmd.Flags().String(flagTags, "", "tag:value list of tags that must match")
cmd.Flags().Int32(flagPage, defaultPage, "Query a specific page of paginated results")
cmd.Flags().Int32(flagLimit, defaultLimit, "Query number of transactions results per page returned")
cmd.Flags().Int32(flagPage, rest.DefaultPage, "Query a specific page of paginated results")
cmd.Flags().Int32(flagLimit, rest.DefaultLimit, "Query number of transactions results per page returned")
cmd.MarkFlagRequired(flagTags)
return cmd
}
Expand Down Expand Up @@ -184,7 +180,7 @@ func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.
return
}

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

if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
Expand All @@ -200,51 +196,3 @@ func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.
rest.PostProcessResponse(w, cdc, txs, cliCtx.Indent)
}
}

func parseHTTPArgs(r *http.Request) (tags []string, page, limit int, err error) {
tags = make([]string, 0, len(r.Form))
for key, values := range r.Form {
if key == "page" || key == "limit" {
continue
}
var value string
value, err = url.QueryUnescape(values[0])
if err != nil {
return tags, page, limit, err
}

var tag string
if key == types.TxHeightKey {
tag = fmt.Sprintf("%s=%s", key, value)
} else {
tag = fmt.Sprintf("%s='%s'", key, value)
}
tags = append(tags, tag)
}

pageStr := r.FormValue("page")
if pageStr == "" {
page = defaultPage
} else {
page, err = strconv.Atoi(pageStr)
if err != nil {
return tags, page, limit, err
} else if page <= 0 {
return tags, page, limit, errors.New("page must greater than 0")
}
}

limitStr := r.FormValue("limit")
if limitStr == "" {
limit = defaultLimit
} else {
limit, err = strconv.Atoi(limitStr)
if err != nil {
return tags, page, limit, err
} else if limit <= 0 {
return tags, page, limit, errors.New("limit must greater than 0")
}
}

return tags, page, limit, nil
}
58 changes: 58 additions & 0 deletions types/rest/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,24 @@
package rest

import (
"errors"
"fmt"
"github.com/tendermint/tendermint/types"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
)

const (
DefaultPage = 1
DefaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19
)

// GasEstimateResponse defines a response definition for tx gas estimation.
type GasEstimateResponse struct {
GasEstimate uint64 `json:"gas_estimate"`
Expand Down Expand Up @@ -211,3 +219,53 @@ func PostProcessResponse(w http.ResponseWriter, cdc *codec.Codec, response inter
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(output)
}

// ParseHTTPArgs parses the request's URL and returns a slice containing all arguments pairs.
// It separates page and limit used for pagination
func ParseHTTPArgs(r *http.Request) (tags []string, page, limit int, err error) {
tags = make([]string, 0, len(r.Form))
for key, values := range r.Form {
if key == "page" || key == "limit" {
continue
}
var value string
value, err = url.QueryUnescape(values[0])
if err != nil {
return tags, page, limit, err
}

var tag string
if key == types.TxHeightKey {
tag = fmt.Sprintf("%s=%s", key, value)
} else {
tag = fmt.Sprintf("%s='%s'", key, value)
}
tags = append(tags, tag)
}

pageStr := r.FormValue("page")
if pageStr == "" {
page = DefaultPage
} else {
page, err = strconv.Atoi(pageStr)
if err != nil {
return tags, page, limit, err
} else if page <= 0 {
return tags, page, limit, errors.New("page must greater than 0")
}
}

limitStr := r.FormValue("limit")
if limitStr == "" {
limit = DefaultLimit
} else {
limit, err = strconv.Atoi(limitStr)
if err != nil {
return tags, page, limit, err
} else if limit <= 0 {
return tags, page, limit, errors.New("limit must greater than 0")
}
}

return tags, page, limit, nil
}
Loading

0 comments on commit 5bb6090

Please sign in to comment.