cosmos-sdk/x/stake/client/rest/query.go
Rigel 6f140d7296 Merge PR #1119: Unbonding, Redelegation
* stake/fees spec updates
* staking overview.md revisions, moving files
* docs reorganization
* staking spec state revisions
* transaction stake updates
* complete staking spec update
* WIP adding unbonding/redelegation commands
* added msg types for unbonding, redelegation
* stake sub-package reorg
* working stake reorg
* modify lcd tests to not use hardcoded json strings
* add description update
* index keys
* key managment for unbonding redelegation complete
* update stake errors
* completed handleMsgCompleteUnbonding fn
* updated to use begin/complete unbonding/redelegation
* fix token shares bug
* develop docs into unbonding
* got non-tests compiling after merge develop
* working fixing tests
* PrivlegedKeeper -> PrivilegedKeeper
* tests compile
* fix some tests
* fixing tests
* remove PrivilegedKeeper
* get unbonding bug
* only rpc sig verification failed tests now
* move percent unbonding/redelegation to the CLI and out of handler logic
* remove min unbonding height
* add lcd txs
* add pool sanity checks, fix a buncha tests
* fix ante. set lcd log to debug (#1322)
* redelegation tests, adding query functionality for bonds
* add self-delegations at genesis ref #1165
* PR comments (mostly) addressed
* cleanup, added Query LCD functionality
* test cleanup/fixes
* fix governance test
* SlashValidatorSet -> ValidatorSet
* changelog
* stake lcd fix
* x/auth: fix chainID in ante
* fix lcd test
* fix lint, update lint make command for spelling
* lowercase error string
* don't expose coinkeeper in staking
* remove a few duplicate lines in changelog
* chain_id in stake lcd tests
* added transient redelegation
* 'transient' => 'transitive'
* Re-add nolint instruction
* Fix tiny linter error
2018-06-27 04:00:12 +02:00

316 lines
9.2 KiB
Go

package rest
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/stake"
)
func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) {
r.HandleFunc(
"/stake/{delegator}/delegation/{validator}",
delegationHandlerFn(ctx, "stake", cdc),
).Methods("GET")
r.HandleFunc(
"/stake/{delegator}/ubd/{validator}",
ubdHandlerFn(ctx, "stake", cdc),
).Methods("GET")
r.HandleFunc(
"/stake/{delegator}/red/{validator_src}/{validator_dst}",
redHandlerFn(ctx, "stake", cdc),
).Methods("GET")
r.HandleFunc(
"/stake/validators",
validatorsHandlerFn(ctx, "stake", cdc),
).Methods("GET")
}
// http request handler to query a delegation
func delegationHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// read parameters
vars := mux.Vars(r)
bech32delegator := vars["delegator"]
bech32validator := vars["validator"]
delegatorAddr, err := sdk.GetAccAddressBech32(bech32delegator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
validatorAddr, err := sdk.GetValAddressBech32(bech32validator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc)
res, err := ctx.QueryStore(key, storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't query delegation. Error: %s", err.Error())))
return
}
// the query will return empty if there is no data for this record
if len(res) == 0 {
w.WriteHeader(http.StatusNoContent)
return
}
var delegation stake.Delegation
err = cdc.UnmarshalBinary(res, &delegation)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't decode delegation. Error: %s", err.Error())))
return
}
output, err := cdc.MarshalJSON(delegation)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}
// http request handler to query an unbonding-delegation
func ubdHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// read parameters
vars := mux.Vars(r)
bech32delegator := vars["delegator"]
bech32validator := vars["validator"]
delegatorAddr, err := sdk.GetAccAddressBech32(bech32delegator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
validatorAddr, err := sdk.GetValAddressBech32(bech32validator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
key := stake.GetUBDKey(delegatorAddr, validatorAddr, cdc)
res, err := ctx.QueryStore(key, storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error())))
return
}
// the query will return empty if there is no data for this record
if len(res) == 0 {
w.WriteHeader(http.StatusNoContent)
return
}
var ubd stake.UnbondingDelegation
err = cdc.UnmarshalBinary(res, &ubd)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't decode unbonding-delegation. Error: %s", err.Error())))
return
}
output, err := cdc.MarshalJSON(ubd)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}
// http request handler to query an redelegation
func redHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// read parameters
vars := mux.Vars(r)
bech32delegator := vars["delegator"]
bech32validatorSrc := vars["validator_src"]
bech32validatorDst := vars["validator_dst"]
delegatorAddr, err := sdk.GetAccAddressBech32(bech32delegator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
validatorSrcAddr, err := sdk.GetValAddressBech32(bech32validatorSrc)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
validatorDstAddr, err := sdk.GetValAddressBech32(bech32validatorDst)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr, cdc)
res, err := ctx.QueryStore(key, storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't query redelegation. Error: %s", err.Error())))
return
}
// the query will return empty if there is no data for this record
if len(res) == 0 {
w.WriteHeader(http.StatusNoContent)
return
}
var red stake.Redelegation
err = cdc.UnmarshalBinary(res, &red)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't decode redelegation. Error: %s", err.Error())))
return
}
output, err := cdc.MarshalJSON(red)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}
// TODO move exist next to validator struct for maintainability
type StakeValidatorOutput struct {
Owner string `json:"owner"` // in bech32
PubKey string `json:"pub_key"` // in bech32
Revoked bool `json:"revoked"` // has the validator been revoked from bonded status?
PoolShares stake.PoolShares `json:"pool_shares"` // total shares for tokens held in the pool
DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators
Description stake.Description `json:"description"` // description terms for the validator
BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator
BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change
ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer
Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators
CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge
CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission
CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time)
// fee related
PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools
}
func bech32StakeValidatorOutput(validator stake.Validator) (StakeValidatorOutput, error) {
bechOwner, err := sdk.Bech32ifyVal(validator.Owner)
if err != nil {
return StakeValidatorOutput{}, err
}
bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey)
if err != nil {
return StakeValidatorOutput{}, err
}
return StakeValidatorOutput{
Owner: bechOwner,
PubKey: bechValPubkey,
Revoked: validator.Revoked,
PoolShares: validator.PoolShares,
DelegatorShares: validator.DelegatorShares,
Description: validator.Description,
BondHeight: validator.BondHeight,
BondIntraTxCounter: validator.BondIntraTxCounter,
ProposerRewardPool: validator.ProposerRewardPool,
Commission: validator.Commission,
CommissionMax: validator.CommissionMax,
CommissionChangeRate: validator.CommissionChangeRate,
CommissionChangeToday: validator.CommissionChangeToday,
PrevBondedShares: validator.PrevBondedShares,
}, nil
}
// TODO bech32
// http request handler to query list of validators
func validatorsHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
kvs, err := ctx.QuerySubspace(cdc, stake.ValidatorsKey, storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't query validators. Error: %s", err.Error())))
return
}
// the query will return empty if there are no validators
if len(kvs) == 0 {
w.WriteHeader(http.StatusNoContent)
return
}
// parse out the validators
validators := make([]StakeValidatorOutput, len(kvs))
for i, kv := range kvs {
var validator stake.Validator
var bech32Validator StakeValidatorOutput
err = cdc.UnmarshalBinary(kv.Value, &validator)
if err == nil {
bech32Validator, err = bech32StakeValidatorOutput(validator)
}
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't decode validator. Error: %s", err.Error())))
return
}
validators[i] = bech32Validator
}
output, err := cdc.MarshalJSON(validators)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}