Merge PR #2542: validator outgoing redelegations and unbonding delegations

This commit is contained in:
Christopher Goes 2018-10-21 23:50:04 +02:00 committed by GitHub
commit 5aae4740db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 169 additions and 63 deletions

View File

@ -109,6 +109,7 @@ FEATURES
* [gaia-lite] [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) Add /broadcast endpoint to broadcast transactions signed by the /sign endpoint. * [gaia-lite] [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) Add /broadcast endpoint to broadcast transactions signed by the /sign endpoint.
* [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`, rename `/accounts/{address}` to `/auth/accounts/{address}` * [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`, rename `/accounts/{address}` to `/auth/accounts/{address}`
* [gaia-lite] [\#2478](https://github.com/cosmos/cosmos-sdk/issues/2478) Add query gov proposal's deposits endpoint * [gaia-lite] [\#2478](https://github.com/cosmos/cosmos-sdk/issues/2478) Add query gov proposal's deposits endpoint
* [gaia-lite] [\#2477](https://github.com/cosmos/cosmos-sdk/issues/2477) Add query validator's outgoing redelegations and unbonding delegations endpoints
* Gaia CLI (`gaiacli`) * Gaia CLI (`gaiacli`)
* [cli] Cmds to query staking pool and params * [cli] Cmds to query staking pool and params

View File

@ -11,7 +11,6 @@ import (
"time" "time"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
p2p "github.com/tendermint/tendermint/p2p" p2p "github.com/tendermint/tendermint/p2p"
@ -77,7 +76,7 @@ func TestKeys(t *testing.T) {
// test if created account is the correct account // test if created account is the correct account
expectedInfo, _ := GetKeyBase(t).CreateKey(newName, seed, newPassword) expectedInfo, _ := GetKeyBase(t).CreateKey(newName, seed, newPassword)
expectedAccount := sdk.AccAddress(expectedInfo.GetPubKey().Address().Bytes()) expectedAccount := sdk.AccAddress(expectedInfo.GetPubKey().Address().Bytes())
assert.Equal(t, expectedAccount.String(), addr2Bech32) require.Equal(t, expectedAccount.String(), addr2Bech32)
// existing keys // existing keys
res, body = Request(t, port, "GET", "/keys", nil) res, body = Request(t, port, "GET", "/keys", nil)
@ -511,7 +510,7 @@ func TestValidatorQuery(t *testing.T) {
require.Equal(t, 1, len(operAddrs)) require.Equal(t, 1, len(operAddrs))
validator := getValidator(t, port, operAddrs[0]) validator := getValidator(t, port, operAddrs[0])
assert.Equal(t, validator.OperatorAddr, operAddrs[0], "The returned validator does not hold the correct data") require.Equal(t, validator.OperatorAddr, operAddrs[0], "The returned validator does not hold the correct data")
} }
func TestBonding(t *testing.T) { func TestBonding(t *testing.T) {
@ -557,11 +556,10 @@ func TestBonding(t *testing.T) {
bondedValidator := getDelegatorValidator(t, port, addr, operAddrs[0]) bondedValidator := getDelegatorValidator(t, port, addr, operAddrs[0])
require.Equal(t, operAddrs[0], bondedValidator.OperatorAddr) require.Equal(t, operAddrs[0], bondedValidator.OperatorAddr)
//////////////////////
// testing unbonding // testing unbonding
// create unbond TX // create unbond TX
resultTx = doBeginUnbonding(t, port, seed, name, password, addr, operAddrs[0], 60) resultTx = doBeginUnbonding(t, port, seed, name, password, addr, operAddrs[0], 30)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
require.Equal(t, uint32(0), resultTx.CheckTx.Code) require.Equal(t, uint32(0), resultTx.CheckTx.Code)
@ -573,33 +571,51 @@ func TestBonding(t *testing.T) {
require.Equal(t, int64(40), coins.AmountOf("steak").Int64()) require.Equal(t, int64(40), coins.AmountOf("steak").Int64())
unbonding := getUndelegation(t, port, addr, operAddrs[0]) unbonding := getUndelegation(t, port, addr, operAddrs[0])
require.Equal(t, "60", unbonding.Balance.Amount.String()) require.Equal(t, "30", unbonding.Balance.Amount.String())
// test redelegation
resultTx = doBeginRedelegation(t, port, seed, name, password, addr, operAddrs[0], operAddrs[1], 30)
tests.WaitForHeight(resultTx.Height+1, port)
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
summary = getDelegationSummary(t, port, addr) summary = getDelegationSummary(t, port, addr)
require.Len(t, summary.Delegations, 0, "Delegation summary holds all delegations") require.Len(t, summary.Delegations, 1, "Delegation summary holds all delegations")
require.Len(t, summary.UnbondingDelegations, 1, "Delegation summary holds all unbonding-delegations") require.Len(t, summary.UnbondingDelegations, 1, "Delegation summary holds all unbonding-delegations")
require.Equal(t, "60", summary.UnbondingDelegations[0].Balance.Amount.String()) require.Len(t, summary.Redelegations, 1, "Delegation summary holds all redelegations")
require.Equal(t, "30.0000000000", summary.Delegations[0].GetShares().String())
require.Equal(t, "30", summary.UnbondingDelegations[0].Balance.Amount.String())
require.Equal(t, "30", summary.Redelegations[0].Balance.Amount.String())
validatorUbds := getValidatorUnbondingDelegations(t, port, operAddrs[0])
require.Len(t, validatorUbds, 1)
require.Equal(t, "30", validatorUbds[0].Balance.Amount.String())
validatorReds := getValidatorRedelegations(t, port, operAddrs[0])
require.Len(t, validatorReds, 1)
require.Equal(t, "30", validatorReds[0].Balance.Amount.String())
bondedValidators = getDelegatorValidators(t, port, addr) bondedValidators = getDelegatorValidators(t, port, addr)
require.Len(t, bondedValidators, 0, "There's no delegation as the user withdraw all funds") require.Len(t, bondedValidators, 1, "There's a delegation as the user only withdraw half of the funds")
// TODO Undonding status not currently implemented // TODO Undonding status not currently implemented
// require.Equal(t, sdk.Unbonding, bondedValidators[0].Status) // require.Equal(t, sdk.Unbonding, bondedValidators[0].Status)
// TODO add redelegation, need more complex capabilities such to mock context and
// TODO check summary for redelegation
// assert.Len(t, summary.Redelegations, 1, "Delegation summary holds all redelegations")
// query txs // query txs
txs := getBondingTxs(t, port, addr, "") txs := getBondingTxs(t, port, addr, "")
assert.Len(t, txs, 2, "All Txs found") require.Len(t, txs, 3, "All Txs found")
txs = getBondingTxs(t, port, addr, "bond") txs = getBondingTxs(t, port, addr, "bond")
assert.Len(t, txs, 1, "All bonding txs found") require.Len(t, txs, 1, "All bonding txs found")
txs = getBondingTxs(t, port, addr, "unbond") txs = getBondingTxs(t, port, addr, "unbond")
assert.Len(t, txs, 1, "All unbonding txs found") require.Len(t, txs, 1, "All unbonding txs found")
txs = getBondingTxs(t, port, addr, "redelegate")
require.Len(t, txs, 1, "All redelegation txs found")
} }
func TestSubmitProposal(t *testing.T) { func TestSubmitProposal(t *testing.T) {
@ -974,11 +990,11 @@ func getUndelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, va
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delegatorAddr, validatorAddr), nil) res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delegatorAddr, validatorAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
var unbondings stake.UnbondingDelegation var unbond stake.UnbondingDelegation
err := cdc.UnmarshalJSON([]byte(body), &unbondings) err := cdc.UnmarshalJSON([]byte(body), &unbond)
require.Nil(t, err) require.Nil(t, err)
return unbondings return unbond
} }
func getDelegationSummary(t *testing.T, port string, delegatorAddr sdk.AccAddress) stake.DelegationSummary { func getDelegationSummary(t *testing.T, port string, delegatorAddr sdk.AccAddress) stake.DelegationSummary {
@ -1052,9 +1068,7 @@ func doDelegate(t *testing.T, port, seed, name, password string,
} }
], ],
"begin_unbondings": [], "begin_unbondings": [],
"complete_unbondings": [],
"begin_redelegates": [], "begin_redelegates": [],
"complete_redelegates": [],
"base_req": { "base_req": {
"name": "%s", "name": "%s",
"password": "%s", "password": "%s",
@ -1091,9 +1105,7 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string,
"shares": "%d" "shares": "%d"
} }
], ],
"complete_unbondings": [],
"begin_redelegates": [], "begin_redelegates": [],
"complete_redelegates": [],
"base_req": { "base_req": {
"name": "%s", "name": "%s",
"password": "%s", "password": "%s",
@ -1114,7 +1126,7 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string,
} }
func doBeginRedelegation(t *testing.T, port, seed, name, password string, func doBeginRedelegation(t *testing.T, port, seed, name, password string,
delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) (resultTx ctypes.ResultBroadcastTxCommit) { delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delAddr) acc := getAccount(t, port, delAddr)
accnum := acc.GetAccountNumber() accnum := acc.GetAccountNumber()
@ -1125,16 +1137,14 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string,
jsonStr := []byte(fmt.Sprintf(`{ jsonStr := []byte(fmt.Sprintf(`{
"delegations": [], "delegations": [],
"begin_unbondings": [], "begin_unbondings": [],
"complete_unbondings": [],
"begin_redelegates": [ "begin_redelegates": [
{ {
"delegator_addr": "%s", "delegator_addr": "%s",
"validator_src_addr": "%s", "validator_src_addr": "%s",
"validator_dst_addr": "%s", "validator_dst_addr": "%s",
"shares": "30" "shares": "%d"
} }
], ],
"complete_redelegates": [],
"base_req": { "base_req": {
"name": "%s", "name": "%s",
"password": "%s", "password": "%s",
@ -1142,7 +1152,7 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string,
"account_number":"%d", "account_number":"%d",
"sequence":"%d" "sequence":"%d"
} }
}`, delAddr, valSrcAddr, valDstAddr, name, password, chainID, accnum, sequence)) }`, delAddr, valSrcAddr, valDstAddr, amount, name, password, chainID, accnum, sequence))
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr) res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
@ -1176,6 +1186,28 @@ func getValidator(t *testing.T, port string, validatorAddr sdk.ValAddress) stake
return validator return validator
} }
func getValidatorUnbondingDelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.UnbondingDelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/unbonding_delegations", validatorAddr.String()), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var ubds []stake.UnbondingDelegation
err := cdc.UnmarshalJSON([]byte(body), &ubds)
require.Nil(t, err)
return ubds
}
func getValidatorRedelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.Redelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/redelegations", validatorAddr.String()), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var reds []stake.Redelegation
err := cdc.UnmarshalJSON([]byte(body), &reds)
require.Nil(t, err)
return reds
}
// ============= Governance Module ================ // ============= Governance Module ================
func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal { func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal {

View File

@ -9,7 +9,6 @@ import (
"github.com/cosmos/cosmos-sdk/client/utils" "github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/tags" "github.com/cosmos/cosmos-sdk/x/stake/tags"
"github.com/gorilla/mux" "github.com/gorilla/mux"
@ -67,6 +66,18 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Co
validatorHandlerFn(cliCtx, cdc), validatorHandlerFn(cliCtx, cdc),
).Methods("GET") ).Methods("GET")
// Get all unbonding delegations from a validator
r.HandleFunc(
"/stake/validators/{validatorAddr}/unbonding_delegations",
validatorUnbondingDelegationsHandlerFn(cliCtx, cdc),
).Methods("GET")
// Get all outgoing redelegations from a validator
r.HandleFunc(
"/stake/validators/{validatorAddr}/redelegations",
validatorRedelegationsHandlerFn(cliCtx, cdc),
).Methods("GET")
// Get the current state of the staking pool // Get the current state of the staking pool
r.HandleFunc( r.HandleFunc(
"/stake/pool", "/stake/pool",
@ -191,33 +202,17 @@ func validatorsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.Handl
// HTTP request handler to query the validator information from a given validator address // HTTP request handler to query the validator information from a given validator address
func validatorHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc { func validatorHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return queryValidator(cliCtx, cdc, "custom/stake/validator")
vars := mux.Vars(r) }
bech32validatorAddr := vars["validatorAddr"]
validatorAddr, err := sdk.ValAddressFromBech32(bech32validatorAddr) // HTTP request handler to query all unbonding delegations from a validator
if err != nil { func validatorUnbondingDelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return queryValidator(cliCtx, cdc, "custom/stake/validatorUnbondingDelegations")
return }
}
params := stake.QueryValidatorParams{ // HTTP request handler to query all redelegations from a source validator
ValidatorAddr: validatorAddr, func validatorRedelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
} return queryValidator(cliCtx, cdc, "custom/stake/validatorRedelegations")
bz, err := cdc.MarshalJSON(params)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
res, err := cliCtx.QueryWithData("custom/stake/validator", bz)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
} }
// HTTP request handler to query the pool information // HTTP request handler to query the pool information

View File

@ -111,3 +111,33 @@ func queryDelegator(cliCtx context.CLIContext, cdc *codec.Codec, endpoint string
utils.PostProcessResponse(w, cdc, res, cliCtx.Indent) utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
} }
} }
func queryValidator(cliCtx context.CLIContext, cdc *codec.Codec, endpoint string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
bech32validatorAddr := vars["validatorAddr"]
validatorAddr, err := sdk.ValAddressFromBech32(bech32validatorAddr)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
params := stake.QueryValidatorParams{
ValidatorAddr: validatorAddr,
}
bz, err := cdc.MarshalJSON(params)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
res, err := cliCtx.QueryWithData(endpoint, bz)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
utils.PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
}

View File

@ -10,15 +10,17 @@ import (
// query endpoints supported by the staking Querier // query endpoints supported by the staking Querier
const ( const (
QueryValidators = "validators" QueryValidators = "validators"
QueryValidator = "validator" QueryValidator = "validator"
QueryDelegator = "delegator" QueryValidatorUnbondingDelegations = "validatorUnbondingDelegations"
QueryDelegation = "delegation" QueryValidatorRedelegations = "validatorRedelegations"
QueryUnbondingDelegation = "unbondingDelegation" QueryDelegator = "delegator"
QueryDelegatorValidators = "delegatorValidators" QueryDelegation = "delegation"
QueryDelegatorValidator = "delegatorValidator" QueryUnbondingDelegation = "unbondingDelegation"
QueryPool = "pool" QueryDelegatorValidators = "delegatorValidators"
QueryParameters = "parameters" QueryDelegatorValidator = "delegatorValidator"
QueryPool = "pool"
QueryParameters = "parameters"
) )
// creates a querier for staking REST endpoints // creates a querier for staking REST endpoints
@ -29,6 +31,10 @@ func NewQuerier(k keep.Keeper, cdc *codec.Codec) sdk.Querier {
return queryValidators(ctx, cdc, k) return queryValidators(ctx, cdc, k)
case QueryValidator: case QueryValidator:
return queryValidator(ctx, cdc, req, k) return queryValidator(ctx, cdc, req, k)
case QueryValidatorUnbondingDelegations:
return queryValidatorUnbondingDelegations(ctx, cdc, req, k)
case QueryValidatorRedelegations:
return queryValidatorRedelegations(ctx, cdc, req, k)
case QueryDelegator: case QueryDelegator:
return queryDelegator(ctx, cdc, req, k) return queryDelegator(ctx, cdc, req, k)
case QueryDelegation: case QueryDelegation:
@ -58,6 +64,8 @@ type QueryDelegatorParams struct {
// defines the params for the following queries: // defines the params for the following queries:
// - 'custom/stake/validator' // - 'custom/stake/validator'
// - 'custom/stake/validatorUnbondingDelegations'
// - 'custom/stake/validatorRedelegations'
type QueryValidatorParams struct { type QueryValidatorParams struct {
ValidatorAddr sdk.ValAddress ValidatorAddr sdk.ValAddress
} }
@ -102,6 +110,40 @@ func queryValidator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k
return res, nil return res, nil
} }
func queryValidatorUnbondingDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) {
var params QueryValidatorParams
errRes := cdc.UnmarshalJSON(req.Data, &params)
if errRes != nil {
return []byte{}, sdk.ErrUnknownAddress("")
}
unbonds := k.GetUnbondingDelegationsFromValidator(ctx, params.ValidatorAddr)
res, errRes = codec.MarshalJSONIndent(cdc, unbonds)
if errRes != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error()))
}
return res, nil
}
func queryValidatorRedelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) {
var params QueryValidatorParams
errRes := cdc.UnmarshalJSON(req.Data, &params)
if errRes != nil {
return []byte{}, sdk.ErrUnknownAddress("")
}
redelegations := k.GetRedelegationsFromValidator(ctx, params.ValidatorAddr)
res, errRes = codec.MarshalJSONIndent(cdc, redelegations)
if errRes != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error()))
}
return res, nil
}
func queryDelegator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { func queryDelegator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) {
var params QueryDelegatorParams var params QueryDelegatorParams
errRes := cdc.UnmarshalJSON(req.Data, &params) errRes := cdc.UnmarshalJSON(req.Data, &params)

View File

@ -81,6 +81,12 @@ func TestNewQuerier(t *testing.T) {
_, err = querier(ctx, []string{"validator"}, query) _, err = querier(ctx, []string{"validator"}, query)
require.Nil(t, err) require.Nil(t, err)
_, err = querier(ctx, []string{"validatorUnbondingDelegations"}, query)
require.Nil(t, err)
_, err = querier(ctx, []string{"validatorRedelegations"}, query)
require.Nil(t, err)
} }
func TestQueryParametersPool(t *testing.T) { func TestQueryParametersPool(t *testing.T) {