Skip to content

Commit

Permalink
Merge PR cosmos#4292: Fix Signing Infos Endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored May 9, 2019
1 parent 85ffce5 commit 925070a
Show file tree
Hide file tree
Showing 14 changed files with 178 additions and 156 deletions.
1 change: 1 addition & 0 deletions .pending/bugfixes/sdk/4194-Fix-pagination-
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#4194 Fix pagination and results returned from /slashing/signing_infos
1 change: 1 addition & 0 deletions .pending/improvements/sdk/4194-ValidatorSignin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#4194 ValidatorSigningInfo now includes the validator's consensus address.
15 changes: 11 additions & 4 deletions types/rest/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,10 @@ func PostProcessResponse(w http.ResponseWriter, cdc *codec.Codec, response inter
_, _ = 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) {
// ParseHTTPArgsWithLimit parses the request's URL and returns a slice containing
// all arguments pairs. It separates page and limit used for pagination where a
// default limit can be provided.
func ParseHTTPArgsWithLimit(r *http.Request, defaultLimit int) (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" {
Expand Down Expand Up @@ -258,7 +259,7 @@ func ParseHTTPArgs(r *http.Request) (tags []string, page, limit int, err error)

limitStr := r.FormValue("limit")
if limitStr == "" {
limit = DefaultLimit
limit = defaultLimit
} else {
limit, err = strconv.Atoi(limitStr)
if err != nil {
Expand All @@ -270,3 +271,9 @@ func ParseHTTPArgs(r *http.Request) (tags []string, page, limit int, err error)

return tags, page, limit, nil
}

// 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) {
return ParseHTTPArgsWithLimit(r, DefaultLimit)
}
3 changes: 3 additions & 0 deletions types/staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ type ValidatorSet interface {
// Delegation allows for getting a particular delegation for a given validator
// and delegator outside the scope of the staking module.
Delegation(Context, AccAddress, ValAddress) Delegation

// MaxValidators returns the maximum amount of bonded validators
MaxValidators(Context) uint16
}

//_______________________________________________________________________________
Expand Down
106 changes: 22 additions & 84 deletions x/slashing/client/rest/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/gorilla/mux"

"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"
Expand All @@ -17,13 +16,13 @@ import (
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec) {
r.HandleFunc(
"/slashing/validators/{validatorPubKey}/signing_info",
signingInfoHandlerFn(cliCtx, slashing.StoreKey, cdc),
signingInfoHandlerFn(cliCtx, cdc),
).Methods("GET")

r.HandleFunc(
"/slashing/signing_infos",
signingInfoHandlerListFn(cliCtx, slashing.StoreKey, cdc),
).Methods("GET").Queries("page", "{page}", "limit", "{limit}")
signingInfoHandlerListFn(cliCtx, cdc),
).Methods("GET")

r.HandleFunc(
"/slashing/parameters",
Expand All @@ -32,7 +31,7 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Co
}

// http request handler to query signing info
func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *codec.Codec) http.HandlerFunc {
func signingInfoHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
pk, err := sdk.GetConsPubKeyBech32(vars["validatorPubKey"])
Expand All @@ -41,65 +40,49 @@ func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *code
return
}

signingInfo, code, err := getSigningInfo(cliCtx, storeName, cdc, pk.Address())
params := slashing.NewQuerySigningInfoParams(sdk.ConsAddress(pk.Address()))

bz, err := cdc.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, code, err.Error())
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}

rest.PostProcessResponse(w, cdc, signingInfo, cliCtx.Indent)
route := fmt.Sprintf("custom/%s/%s", slashing.QuerierRoute, slashing.QuerySigningInfo)
res, err := cliCtx.QueryWithData(route, bz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}

rest.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}

// http request handler to query signing info
func signingInfoHandlerListFn(cliCtx context.CLIContext, storeName string, cdc *codec.Codec) http.HandlerFunc {
func signingInfoHandlerListFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var signingInfoList []slashing.ValidatorSigningInfo

_, page, limit, err := rest.ParseHTTPArgs(r)
_, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}

height, err := rpc.GetChainHeight(cliCtx)
params := slashing.NewQuerySigningInfosParams(page, limit)
bz, err := cdc.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}

validators, err := rpc.GetValidators(cliCtx, &height)
route := fmt.Sprintf("custom/%s/%s", slashing.QuerierRoute, slashing.QuerySigningInfos)
res, err := cliCtx.QueryWithData(route, bz)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}

if len(validators.Validators) == 0 {
rest.PostProcessResponse(w, cdc, signingInfoList, cliCtx.Indent)
return
}

// TODO: this should happen when querying Validators from RPC,
// as soon as it's available this is not needed anymore
// parameter page is (page-1) because ParseHTTPArgs starts with page 1, where our array start with 0
start, end := adjustPagination(uint(len(validators.Validators)), uint(page)-1, uint(limit))
for _, validator := range validators.Validators[start:end] {
address := validator.Address
signingInfo, code, err := getSigningInfo(cliCtx, storeName, cdc, address)
if err != nil {
rest.WriteErrorResponse(w, code, err.Error())
return
}
signingInfoList = append(signingInfoList, signingInfo)
}

if len(signingInfoList) == 0 {
rest.PostProcessResponse(w, cdc, signingInfoList, cliCtx.Indent)
return
}

rest.PostProcessResponse(w, cdc, signingInfoList, cliCtx.Indent)
rest.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}

Expand All @@ -116,48 +99,3 @@ func queryParamsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Hand
rest.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}

func getSigningInfo(cliCtx context.CLIContext, storeName string, cdc *codec.Codec, address []byte) (signingInfo slashing.ValidatorSigningInfo, code int, err error) {
key := slashing.GetValidatorSigningInfoKey(sdk.ConsAddress(address))

res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
code = http.StatusInternalServerError
return
}

if len(res) == 0 {
code = http.StatusOK
return
}

err = cdc.UnmarshalBinaryLengthPrefixed(res, &signingInfo)
if err != nil {
code = http.StatusInternalServerError
return
}

return
}

// Adjust pagination with page starting from 0
func adjustPagination(size, page, limit uint) (start uint, end uint) {
// If someone asks for pages bigger than our dataset, just return everything
if limit > size {
return 0, size
}

// Do pagination when healthy, fallback to 0
start = 0
if page*limit < size {
start = page * limit
}

// Do pagination only when healthy, fallback to len(dataset)
end = size
if start+limit <= size {
end = start + limit
}

return start, end
}
32 changes: 0 additions & 32 deletions x/slashing/client/rest/query_test.go

This file was deleted.

7 changes: 7 additions & 0 deletions x/slashing/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
package slashing

import (
"fmt"

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

Expand All @@ -17,6 +19,7 @@ const (
CodeValidatorNotJailed CodeType = 103
CodeMissingSelfDelegation CodeType = 104
CodeSelfDelegationTooLow CodeType = 105
CodeMissingSigningInfo CodeType = 106
)

func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error {
Expand All @@ -42,3 +45,7 @@ func ErrMissingSelfDelegation(codespace sdk.CodespaceType) sdk.Error {
func ErrSelfDelegationTooLowToUnjail(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeValidatorNotJailed, "validator's self delegation less than MinSelfDelegation, cannot be unjailed")
}

func ErrNoSigningInfoFound(codespace sdk.CodespaceType, consAddr sdk.ConsAddress) sdk.Error {
return sdk.NewError(codespace, CodeMissingSigningInfo, fmt.Sprintf("no signing info found for address: %s", consAddr))
}
2 changes: 1 addition & 1 deletion x/slashing/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func TestJailedValidatorDelegations(t *testing.T) {
staking.EndBlocker(ctx, stakingKeeper)

// set dummy signing info
newInfo := NewValidatorSigningInfo(0, 0, time.Unix(0, 0), false, 0)
newInfo := NewValidatorSigningInfo(consAddr, 0, 0, time.Unix(0, 0), false, 0)
slashingKeeper.SetValidatorSigningInfo(ctx, consAddr, newInfo)

// delegate tokens to the validator
Expand Down
15 changes: 8 additions & 7 deletions x/slashing/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ func (k Keeper) AfterValidatorBonded(ctx sdk.Context, address sdk.ConsAddress, _
// Update the signing info start height or create a new signing info
_, found := k.getValidatorSigningInfo(ctx, address)
if !found {
signingInfo := ValidatorSigningInfo{
StartHeight: ctx.BlockHeight(),
IndexOffset: 0,
JailedUntil: time.Unix(0, 0),
Tombstoned: false,
MissedBlocksCounter: 0,
}
signingInfo := NewValidatorSigningInfo(
address,
ctx.BlockHeight(),
0,
time.Unix(0, 0),
false,
0,
)
k.SetValidatorSigningInfo(ctx, address, signingInfo)
}
}
Expand Down
Loading

0 comments on commit 925070a

Please sign in to comment.