Merge PR #4505: Support height queries in REST client

This commit is contained in:
colin axner 2019-06-07 06:02:07 -07:00 committed by Alexander Bezobchuk
parent 3862b74899
commit c777fb9108
12 changed files with 238 additions and 0 deletions

View File

@ -0,0 +1 @@
#4501 Support height queriers in rest client

View File

@ -212,6 +212,12 @@ func (ctx CLIContext) WithNodeURI(nodeURI string) CLIContext {
return ctx
}
// WithHeight returns a copy of the context with an updated height.
func (ctx CLIContext) WithHeight(height int64) CLIContext {
ctx.Height = height
return ctx
}
// WithClient returns a copy of the context with an updated RPC client
// instance.
func (ctx CLIContext) WithClient(client rpcclient.Client) CLIContext {

View File

@ -156,6 +156,11 @@ func QueryTxsByTagsRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
if len(r.Form) == 0 {
rest.PostProcessResponse(w, cliCtx, txs)
return
@ -184,6 +189,11 @@ func QueryTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
vars := mux.Vars(r)
hashHexStr := vars["hash"]
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
output, err := queryTx(cliCtx, hashHexStr)
if err != nil {
if strings.Contains(err.Error(), hashHexStr) {

View File

@ -197,6 +197,25 @@ func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEm
return n, true
}
// ParseQueryHeightOrReturnBadRequest sets the height to execute a query if set by the http request.
// It returns false if there was an error parsing the height.
func ParseQueryHeightOrReturnBadRequest(w http.ResponseWriter, cliCtx context.CLIContext, r *http.Request) (context.CLIContext, bool) {
heightStr := r.FormValue("height")
if heightStr != "" {
height, err := strconv.ParseInt(heightStr, 10, 64)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return cliCtx, false
}
if height > 0 {
cliCtx = cliCtx.WithHeight(height)
}
}
return cliCtx, true
}
// PostProcessResponse performs post processing for a REST response.
func PostProcessResponse(w http.ResponseWriter, cliCtx context.CLIContext, response interface{}) {
var output []byte

View File

@ -8,6 +8,7 @@ import (
"net/http/httptest"
"testing"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/types"
@ -101,6 +102,42 @@ func TestParseHTTPArgs(t *testing.T) {
}
}
func TestParseQueryHeight(t *testing.T) {
var emptyHeight int64
height := int64(1256756)
req0 := mustNewRequest(t, "", "/", nil)
req1 := mustNewRequest(t, "", "/?height=1256756", nil)
req2 := mustNewRequest(t, "", "/?height=456yui4567", nil)
req3 := mustNewRequest(t, "", "/?height=-1", nil)
tests := []struct {
name string
req *http.Request
w http.ResponseWriter
cliCtx context.CLIContext
expectedHeight int64
expectedOk bool
}{
{"no height", req0, httptest.NewRecorder(), context.CLIContext{}, emptyHeight, true},
{"height", req1, httptest.NewRecorder(), context.CLIContext{}, height, true},
{"invalid height", req2, httptest.NewRecorder(), context.CLIContext{}, emptyHeight, false},
{"negative height", req3, httptest.NewRecorder(), context.CLIContext{}, emptyHeight, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cliCtx, ok := ParseQueryHeightOrReturnBadRequest(tt.w, tt.cliCtx, tt.req)
if tt.expectedOk {
require.True(t, ok)
require.Equal(t, tt.expectedHeight, cliCtx.Height)
} else {
require.False(t, ok)
require.Empty(t, tt.expectedHeight, cliCtx.Height)
}
})
}
}
func mustNewRequest(t *testing.T, method, url string, body io.Reader) *http.Request {
req, err := http.NewRequest(method, url, body)
require.NoError(t, err)

View File

@ -40,6 +40,11 @@ func QueryAccountRequestHandlerFn(
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
res, err := cliCtx.QueryStore(types.AddressStoreKey(addr), storeName)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
@ -79,6 +84,11 @@ func QueryBalancesRequestHandlerFn(
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
res, err := cliCtx.QueryStore(types.AddressStoreKey(addr), storeName)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())

View File

@ -68,6 +68,11 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute st
// HTTP request handler to query the total rewards balance from all delegations
func delegatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
// query for rewards from a particular delegator
res, ok := checkResponseQueryDelegatorTotalRewards(w, cliCtx, queryRoute, mux.Vars(r)["delegatorAddr"])
if !ok {
@ -81,6 +86,11 @@ func delegatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) htt
// HTTP request handler to query a delegation rewards
func delegationRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
// query for rewards from a particular delegation
res, ok := checkResponseQueryDelegationRewards(w, cliCtx, queryRoute, mux.Vars(r)["delegatorAddr"], mux.Vars(r)["validatorAddr"])
if !ok {
@ -99,6 +109,11 @@ func delegatorWithdrawalAddrHandlerFn(cliCtx context.CLIContext, queryRoute stri
return
}
cliCtx, ok = rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
bz := cliCtx.Codec.MustMarshalJSON(types.NewQueryDelegatorWithdrawAddrParams(delegatorAddr))
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/withdraw_addr", queryRoute), bz)
if err != nil {
@ -137,6 +152,11 @@ func validatorInfoHandlerFn(cliCtx context.CLIContext, queryRoute string) http.H
return
}
cliCtx, ok = rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
// query commission
commissionRes, err := common.QueryValidatorCommission(cliCtx, queryRoute, validatorAddr)
if err != nil {
@ -172,6 +192,11 @@ func validatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) htt
return
}
cliCtx, ok = rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
delAddr := sdk.AccAddress(validatorAddr).String()
res, ok := checkResponseQueryDelegationRewards(w, cliCtx, queryRoute, delAddr, valAddr)
if !ok {
@ -185,6 +210,11 @@ func validatorRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) htt
// HTTP request handler to query the distribution params values
func paramsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params, err := common.QueryParams(cliCtx, queryRoute)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
@ -197,6 +227,11 @@ func paramsHandlerFn(cliCtx context.CLIContext, queryRoute string) http.HandlerF
func communityPoolHandler(cliCtx context.CLIContext, queryRoute string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/community_pool", queryRoute), nil)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
@ -221,6 +256,11 @@ func outstandingRewardsHandlerFn(cliCtx context.CLIContext, queryRoute string) h
return
}
cliCtx, ok = rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
bin := cliCtx.Codec.MustMarshalJSON(types.NewQueryValidatorOutstandingRewardsParams(validatorAddr))
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/validator_outstanding_rewards", queryRoute), bin)
if err != nil {

View File

@ -196,6 +196,11 @@ func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
vars := mux.Vars(r)
paramType := vars[RestParamsType]
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/gov/%s/%s", types.QueryParams, paramType), nil)
if err != nil {
rest.WriteErrorResponse(w, http.StatusNotFound, err.Error())
@ -222,6 +227,11 @@ func queryProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
cliCtx, ok = rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewQueryProposalParams(proposalID)
bz, err := cliCtx.Codec.MarshalJSON(params)
@ -250,6 +260,11 @@ func queryDepositsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
cliCtx, ok = rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewQueryProposalParams(proposalID)
bz, err := cliCtx.Codec.MarshalJSON(params)
@ -298,6 +313,11 @@ func queryProposerHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
cliCtx, ok = rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
res, err := gcutils.QueryProposerByTxQuery(cliCtx, proposalID)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
@ -337,6 +357,11 @@ func queryDepositHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
cliCtx, ok = rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewQueryDepositParams(proposalID, depositorAddr)
bz, err := cliCtx.Codec.MarshalJSON(params)
@ -414,6 +439,11 @@ func queryVoteHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
cliCtx, ok = rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewQueryVoteParams(proposalID, voterAddr)
bz, err := cliCtx.Codec.MarshalJSON(params)
@ -479,6 +509,11 @@ func queryVotesOnProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
cliCtx, ok = rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewQueryProposalParams(proposalID)
bz, err := cliCtx.Codec.MarshalJSON(params)
@ -561,6 +596,11 @@ func queryProposalsWithParameterFn(cliCtx context.CLIContext) http.HandlerFunc {
params.Limit = numLimit
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
@ -594,6 +634,11 @@ func queryTallyOnProposalHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
cliCtx, ok = rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewQueryProposalParams(proposalID)
bz, err := cliCtx.Codec.MarshalJSON(params)

View File

@ -32,6 +32,11 @@ func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParameters)
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
res, err := cliCtx.QueryWithData(route, nil)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
@ -46,6 +51,11 @@ func queryInflationHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryInflation)
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
res, err := cliCtx.QueryWithData(route, nil)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
@ -60,6 +70,11 @@ func queryAnnualProvisionsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc
return func(w http.ResponseWriter, r *http.Request) {
route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAnnualProvisions)
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
res, err := cliCtx.QueryWithData(route, nil)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())

View File

@ -39,6 +39,11 @@ func signingInfoHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewQuerySigningInfoParams(sdk.ConsAddress(pk.Address()))
bz, err := cliCtx.Codec.MarshalJSON(params)
@ -67,6 +72,11 @@ func signingInfoHandlerListFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewQuerySigningInfosParams(page, limit)
bz, err := cliCtx.Codec.MarshalJSON(params)
if err != nil {
@ -87,6 +97,11 @@ func signingInfoHandlerListFn(cliCtx context.CLIContext) http.HandlerFunc {
func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
route := fmt.Sprintf("custom/%s/parameters", types.QuerierRoute)
res, err := cliCtx.QueryWithData(route, nil)

View File

@ -123,6 +123,11 @@ func delegatorTxsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
typesQuery := r.URL.Query().Get("type")
trimmedQuery := strings.TrimSpace(typesQuery)
if len(trimmedQuery) != 0 {
@ -180,6 +185,11 @@ func redelegationsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var params types.QueryRedelegationParams
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
bechDelegatorAddr := r.URL.Query().Get("delegator")
bechSrcValidatorAddr := r.URL.Query().Get("validator_from")
bechDstValidatorAddr := r.URL.Query().Get("validator_to")
@ -251,6 +261,11 @@ func validatorsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
status := r.FormValue("status")
if status == "" {
status = sdk.BondStatusBonded
@ -291,6 +306,11 @@ func validatorUnbondingDelegationsHandlerFn(cliCtx context.CLIContext) http.Hand
// HTTP request handler to query the pool information
func poolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
res, err := cliCtx.QueryWithData("custom/staking/pool", nil)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
@ -304,6 +324,11 @@ func poolHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
// HTTP request handler to query the staking params values
func paramsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
res, err := cliCtx.QueryWithData("custom/staking/parameters", nil)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())

View File

@ -49,6 +49,11 @@ func queryBonds(cliCtx context.CLIContext, endpoint string) http.HandlerFunc {
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewQueryBondsParams(delegatorAddr, validatorAddr)
bz, err := cliCtx.Codec.MarshalJSON(params)
@ -77,6 +82,11 @@ func queryDelegator(cliCtx context.CLIContext, endpoint string) http.HandlerFunc
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewQueryDelegatorParams(delegatorAddr)
bz, err := cliCtx.Codec.MarshalJSON(params)
@ -105,6 +115,11 @@ func queryValidator(cliCtx context.CLIContext, endpoint string) http.HandlerFunc
return
}
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}
params := types.NewQueryValidatorParams(validatorAddr)
bz, err := cliCtx.Codec.MarshalJSON(params)