Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: validator outgoing redelegations and unbonding delegations #2542

Merged
merged 5 commits into from
Oct 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,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] [\#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] [\#2477](https://github.com/cosmos/cosmos-sdk/issues/2477) Add query validator's outgoing redelegations and unbonding delegations endpoints

* Gaia CLI (`gaiacli`)
* [cli] Cmds to query staking pool and params
Expand Down
88 changes: 60 additions & 28 deletions client/lcd/lcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"time"

"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

p2p "github.com/tendermint/tendermint/p2p"
Expand Down Expand Up @@ -77,7 +76,7 @@ func TestKeys(t *testing.T) {
// test if created account is the correct account
expectedInfo, _ := GetKeyBase(t).CreateKey(newName, seed, newPassword)
expectedAccount := sdk.AccAddress(expectedInfo.GetPubKey().Address().Bytes())
assert.Equal(t, expectedAccount.String(), addr2Bech32)
require.Equal(t, expectedAccount.String(), addr2Bech32)

// existing keys
res, body = Request(t, port, "GET", "/keys", nil)
Expand Down Expand Up @@ -511,7 +510,7 @@ func TestValidatorQuery(t *testing.T) {
require.Equal(t, 1, len(operAddrs))

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) {
Expand Down Expand Up @@ -557,11 +556,10 @@ func TestBonding(t *testing.T) {
bondedValidator := getDelegatorValidator(t, port, addr, operAddrs[0])
require.Equal(t, operAddrs[0], bondedValidator.OperatorAddr)

//////////////////////
// testing unbonding

// 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)

require.Equal(t, uint32(0), resultTx.CheckTx.Code)
Expand All @@ -573,33 +571,51 @@ func TestBonding(t *testing.T) {
require.Equal(t, int64(40), coins.AmountOf("steak").Int64())

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)

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.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)
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
// 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
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")
assert.Len(t, txs, 1, "All bonding txs found")
require.Len(t, txs, 1, "All bonding txs found")

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) {
Expand Down Expand Up @@ -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)
require.Equal(t, http.StatusOK, res.StatusCode, body)

var unbondings stake.UnbondingDelegation
err := cdc.UnmarshalJSON([]byte(body), &unbondings)
var unbond stake.UnbondingDelegation
err := cdc.UnmarshalJSON([]byte(body), &unbond)
require.Nil(t, err)

return unbondings
return unbond
}

func getDelegationSummary(t *testing.T, port string, delegatorAddr sdk.AccAddress) stake.DelegationSummary {
Expand Down Expand Up @@ -1052,9 +1068,7 @@ func doDelegate(t *testing.T, port, seed, name, password string,
}
],
"begin_unbondings": [],
"complete_unbondings": [],
"begin_redelegates": [],
"complete_redelegates": [],
"base_req": {
"name": "%s",
"password": "%s",
Expand Down Expand Up @@ -1091,9 +1105,7 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string,
"shares": "%d"
}
],
"complete_unbondings": [],
"begin_redelegates": [],
"complete_redelegates": [],
"base_req": {
"name": "%s",
"password": "%s",
Expand All @@ -1114,7 +1126,7 @@ func doBeginUnbonding(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)
accnum := acc.GetAccountNumber()
Expand All @@ -1125,24 +1137,22 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string,
jsonStr := []byte(fmt.Sprintf(`{
"delegations": [],
"begin_unbondings": [],
"complete_unbondings": [],
"begin_redelegates": [
{
"delegator_addr": "%s",
"validator_src_addr": "%s",
"validator_dst_addr": "%s",
"shares": "30"
"shares": "%d"
}
],
"complete_redelegates": [],
"base_req": {
"name": "%s",
"password": "%s",
"chain_id": "%s",
"account_number":"%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)
require.Equal(t, http.StatusOK, res.StatusCode, body)
Expand Down Expand Up @@ -1176,6 +1186,28 @@ func getValidator(t *testing.T, port string, validatorAddr sdk.ValAddress) stake
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 ================

func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal {
Expand Down
47 changes: 21 additions & 26 deletions x/stake/client/rest/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/tags"

"github.com/gorilla/mux"
Expand Down Expand Up @@ -67,6 +66,18 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Co
validatorHandlerFn(cliCtx, cdc),
).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
r.HandleFunc(
"/stake/pool",
Expand Down Expand Up @@ -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
func validatorHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) 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,
}
return queryValidator(cliCtx, cdc, "custom/stake/validator")
}

bz, err := cdc.MarshalJSON(params)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// HTTP request handler to query all unbonding delegations from a validator
func validatorUnbondingDelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
return queryValidator(cliCtx, cdc, "custom/stake/validatorUnbondingDelegations")
}

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 all redelegations from a source validator
func validatorRedelegationsHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
return queryValidator(cliCtx, cdc, "custom/stake/validatorRedelegations")
}

// HTTP request handler to query the pool information
Expand Down
30 changes: 30 additions & 0 deletions x/stake/client/rest/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,33 @@ func queryDelegator(cliCtx context.CLIContext, cdc *codec.Codec, endpoint string
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)
}
}
Loading