From e82cad8413951e99b24e9fa3377b6764a6835589 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Tue, 14 Aug 2018 00:06:48 +0200 Subject: [PATCH] Merge pull request #2000: tests for staking lcd * Added tests for Delegator Validators routes * Updated tests for undelegations * Updated Gaia-lite docs * Updated PENDING.md * Updated comments * Deleted more comments * Add spacing --- PENDING.md | 19 +++-- client/lcd/lcd_test.go | 131 ++++++++++++++++++++------------- docs/clients/lcd-rest-api.yaml | 43 +++++++++++ docs/light/api.md | 56 ++++++++++++++ docs/light/specification.md | 8 ++ x/stake/client/rest/query.go | 25 +++++-- x/stake/client/rest/utils.go | 4 - 7 files changed, 214 insertions(+), 72 deletions(-) diff --git a/PENDING.md b/PENDING.md index 9f0b86a994eb..9ade31c8b3fc 100644 --- a/PENDING.md +++ b/PENDING.md @@ -8,10 +8,10 @@ BREAKING CHANGES * Gaia * Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013) - -* SDK -* Tendermint +* SDK + +* Tendermint FEATURES @@ -22,9 +22,9 @@ FEATURES * Gaia -* SDK +* SDK -* Tendermint +* Tendermint IMPROVEMENTS @@ -35,9 +35,9 @@ IMPROVEMENTS * Gaia -* SDK +* SDK -* Tendermint +* Tendermint BUG FIXES @@ -48,7 +48,6 @@ BUG FIXES * Gaia -* SDK - -* Tendermint +* SDK +* Tendermint diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index cbc1a2c20d7c..9b8c5e439719 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -385,64 +385,70 @@ func TestValidatorQuery(t *testing.T) { func TestBonding(t *testing.T) { name, password, denom := "test", "1234567890", "steak" - addr, seed := CreateAddr(t, "test", password, GetKeyBase(t)) + addr, seed := CreateAddr(t, name, password, GetKeyBase(t)) cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}) defer cleanup() validator1Owner := sdk.AccAddress(pks[0].Address()) + validator := getValidator(t, port, validator1Owner) - // create bond TX - resultTx := doDelegate(t, port, seed, name, password, addr, validator1Owner) + resultTx := doDelegate(t, port, seed, name, password, addr, validator1Owner, 60) tests.WaitForHeight(resultTx.Height+1, port) - // check if tx was committed require.Equal(t, uint32(0), resultTx.CheckTx.Code) require.Equal(t, uint32(0), resultTx.DeliverTx.Code) - // query sender acc := getAccount(t, port, addr) coins := acc.GetCoins() require.Equal(t, int64(40), coins.AmountOf(denom).Int64()) - // query validator bond := getDelegation(t, port, addr, validator1Owner) require.Equal(t, "60.0000000000", bond.Shares) + summary := getDelegationSummary(t, port, addr) + + require.Len(t, summary.Delegations, 1, "Delegation summary holds all delegations") + require.Equal(t, "60.0000000000", summary.Delegations[0].Shares) + require.Len(t, summary.UnbondingDelegations, 0, "Delegation summary holds all unbonding-delegations") + + bondedValidators := getDelegatorValidators(t, port, addr) + require.Len(t, bondedValidators, 1) + require.Equal(t, validator1Owner, bondedValidators[0].Owner) + require.Equal(t, validator.DelegatorShares.Add(sdk.NewRat(60)).FloatString(), bondedValidators[0].DelegatorShares.FloatString()) + + bondedValidator := getDelegatorValidator(t, port, addr, validator1Owner) + require.Equal(t, validator1Owner, bondedValidator.Owner) + ////////////////////// // testing unbonding - // create unbond TX - resultTx = doBeginUnbonding(t, port, seed, name, password, addr, validator1Owner) + resultTx = doBeginUnbonding(t, port, seed, name, password, addr, validator1Owner, 60) tests.WaitForHeight(resultTx.Height+1, port) - // query validator - bond = getDelegation(t, port, addr, validator1Owner) - require.Equal(t, "30.0000000000", bond.Shares) - - // check if tx was committed require.Equal(t, uint32(0), resultTx.CheckTx.Code) require.Equal(t, uint32(0), resultTx.DeliverTx.Code) - // should the sender should have not received any coins as the unbonding has only just begun - // query sender + // sender should have not received any coins as the unbonding has only just begun acc = getAccount(t, port, addr) coins = acc.GetCoins() require.Equal(t, int64(40), coins.AmountOf("steak").Int64()) - // query unbonding delegation - validatorAddr := sdk.AccAddress(pks[0].Address()) - unbondings := getUndelegations(t, port, addr, validatorAddr) - assert.Len(t, unbondings, 1, "Unbondings holds all unbonding-delegations") - assert.Equal(t, "30", unbondings[0].Balance.Amount.String()) + unbondings := getUndelegations(t, port, addr, validator1Owner) + require.Len(t, unbondings, 1, "Unbondings holds all unbonding-delegations") + require.Equal(t, "60", unbondings[0].Balance.Amount.String()) - // query summary - summary := getDelegationSummary(t, port, addr) + summary = getDelegationSummary(t, port, addr) - assert.Len(t, summary.Delegations, 1, "Delegation summary holds all delegations") - assert.Equal(t, "30.0000000000", summary.Delegations[0].Shares) - assert.Len(t, summary.UnbondingDelegations, 1, "Delegation summary holds all unbonding-delegations") - assert.Equal(t, "30", summary.UnbondingDelegations[0].Balance.Amount.String()) + require.Len(t, summary.Delegations, 0, "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()) + + bondedValidators = getDelegatorValidators(t, port, addr) + require.Len(t, bondedValidators, 0, "There's no delegation as the user withdraw all 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 @@ -757,64 +763,89 @@ func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing. // ============= Stake Module ================ func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.AccAddress) rest.DelegationWithoutRat { - - // get the account to get the sequence res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delegatorAddr, validatorAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) + var bond rest.DelegationWithoutRat + err := cdc.UnmarshalJSON([]byte(body), &bond) require.Nil(t, err) + return bond } func getUndelegations(t *testing.T, port string, delegatorAddr, validatorAddr sdk.AccAddress) []stake.UnbondingDelegation { - - // get the account to get the sequence 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) require.Nil(t, err) + return unbondings } func getDelegationSummary(t *testing.T, port string, delegatorAddr sdk.AccAddress) rest.DelegationSummary { - - // get the account to get the sequence res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s", delegatorAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) + var summary rest.DelegationSummary + err := cdc.UnmarshalJSON([]byte(body), &summary) require.Nil(t, err) + return summary } func getBondingTxs(t *testing.T, port string, delegatorAddr sdk.AccAddress, query string) []tx.Info { - - // get the account to get the sequence var res *http.Response var body string + if len(query) > 0 { res, body = Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/txs?type=%s", delegatorAddr, query), nil) } else { res, body = Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/txs", delegatorAddr), nil) } require.Equal(t, http.StatusOK, res.StatusCode, body) + var txs []tx.Info + err := cdc.UnmarshalJSON([]byte(body), &txs) require.Nil(t, err) + return txs } -func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.AccAddress) (resultTx ctypes.ResultBroadcastTxCommit) { - // get the account to get the sequence +func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddress) []stake.BechValidator { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators", delegatorAddr), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + var bondedValidators []stake.BechValidator + + err := cdc.UnmarshalJSON([]byte(body), &bondedValidators) + require.Nil(t, err) + + return bondedValidators +} + +func getDelegatorValidator(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) stake.BechValidator { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delegatorAddr, validatorAddr), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + var bondedValidator stake.BechValidator + err := cdc.UnmarshalJSON([]byte(body), &bondedValidator) + require.Nil(t, err) + + return bondedValidator +} + +func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.AccAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) { acc := getAccount(t, port, delegatorAddr) accnum := acc.GetAccountNumber() sequence := acc.GetSequence() - chainID := viper.GetString(client.FlagChainID) - // send jsonStr := []byte(fmt.Sprintf(`{ "name": "%s", "password": "%s", @@ -826,14 +857,15 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, { "delegator_addr": "%s", "validator_addr": "%s", - "delegation": { "denom": "%s", "amount": "60" } + "delegation": { "denom": "%s", "amount": "%d" } } ], "begin_unbondings": [], "complete_unbondings": [], "begin_redelegates": [], "complete_redelegates": [] - }`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr, "steak")) + }`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr, "steak", amount)) + res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -845,16 +877,13 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, } func doBeginUnbonding(t *testing.T, port, seed, name, password string, - delegatorAddr, validatorAddr sdk.AccAddress) (resultTx ctypes.ResultBroadcastTxCommit) { + delegatorAddr, validatorAddr sdk.AccAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) { - // get the account to get the sequence acc := getAccount(t, port, delegatorAddr) accnum := acc.GetAccountNumber() sequence := acc.GetSequence() - chainID := viper.GetString(client.FlagChainID) - // send jsonStr := []byte(fmt.Sprintf(`{ "name": "%s", "password": "%s", @@ -867,13 +896,14 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string, { "delegator_addr": "%s", "validator_addr": "%s", - "shares": "30" + "shares": "%d" } ], "complete_unbondings": [], "begin_redelegates": [], "complete_redelegates": [] - }`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr)) + }`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr, amount)) + res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -887,14 +917,12 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string, func doBeginRedelegation(t *testing.T, port, seed, name, password string, delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) (resultTx ctypes.ResultBroadcastTxCommit) { - // get the account to get the sequence acc := getAccount(t, port, delegatorAddr) accnum := acc.GetAccountNumber() sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) - // send jsonStr := []byte(fmt.Sprintf(`{ "name": "%s", "password": "%s", @@ -915,6 +943,7 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, ], "complete_redelegates": [] }`, name, password, accnum, sequence, chainID, delegatorAddr, validatorSrcAddr, validatorDstAddr)) + res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -926,7 +955,6 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, } func getValidators(t *testing.T, port string) []stake.BechValidator { - // get the account to get the sequence res, body := Request(t, port, "GET", "/stake/validators", nil) require.Equal(t, http.StatusOK, res.StatusCode, body) var validators []stake.BechValidator @@ -936,7 +964,6 @@ func getValidators(t *testing.T, port string) []stake.BechValidator { } func getValidator(t *testing.T, port string, validatorAddr sdk.AccAddress) stake.BechValidator { - // get the account to get the sequence res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", validatorAddr.String()), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) var validator stake.BechValidator @@ -1034,7 +1061,7 @@ func getProposalsFilterStatus(t *testing.T, port string, status gov.ProposalStat } func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress) (resultTx ctypes.ResultBroadcastTxCommit) { - // get the account to get the sequence + acc := getAccount(t, port, proposerAddr) accnum := acc.GetAccountNumber() sequence := acc.GetSequence() @@ -1068,7 +1095,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA } func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID int64) (resultTx ctypes.ResultBroadcastTxCommit) { - // get the account to get the sequence + acc := getAccount(t, port, proposerAddr) accnum := acc.GetAccountNumber() sequence := acc.GetSequence() diff --git a/docs/clients/lcd-rest-api.yaml b/docs/clients/lcd-rest-api.yaml index 063e3a55b857..3b8349f4bd59 100644 --- a/docs/clients/lcd-rest-api.yaml +++ b/docs/clients/lcd-rest-api.yaml @@ -493,6 +493,49 @@ paths: 500: description: Internal Server Error + /stake/delegators/{delegatorAddr}/validators: + parameters: + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + get: + summary: Query all validators that a delegator is bonded to + tags: + - stake + produces: + - application/json + responses: + 200: + description: OK + 404: + description: Not Found + + /stake/delegators/{delegatorAddr}/validators/{validatorAddr}: + parameters: + - in: path + name: delegatorAddr + description: Bech32 AccAddress of Delegator + required: true + type: string + - in: path + name: validatorAddr + description: Bech32 ValAddress of Delegator + required: true + type: string + get: + summary: Query a validator that a delegator is bonded to + tags: + - stake + produces: + - application/json + responses: + 200: + description: OK + 404: + description: Not Found + /stake/delegators/{delegatorAddr}/txs: parameters: - in: path diff --git a/docs/light/api.md b/docs/light/api.md index 41abed5da6ef..d4e66eaf152e 100644 --- a/docs/light/api.md +++ b/docs/light/api.md @@ -479,6 +479,62 @@ Returns on error: } ``` +### /stake/delegators/{delegatorAddr}/validators - GET + +url: /stake/delegators/{delegatorAddr}/validators + +Functionality: Query all validators that a delegator is bonded to. + +Returns on success: + +```json +{ + "rest api":"2.0", + "code":200, + "error":"", + "result":{} +} +``` + +Returns on failure: + +```json +{ + "rest api":"2.0", + "code":500, + "error":"TODO", + "result":{} +} +``` + +### /stake/delegators/{delegatorAddr}/validators/{validatorAddr} - GET + +url: /stake/delegators/{delegatorAddr}/validators/{validatorAddr} + +Functionality: Query a validator that a delegator is bonded to + +Returns on success: + +```json +{ + "rest api":"2.0", + "code":200, + "error":"", + "result":{} +} +``` + +Returns on failure: + +```json +{ + "rest api":"2.0", + "code":500, + "error":"TODO", + "result":{} +} +``` + ### /stake/delegators/{delegatorAddr}/txs - GET url: /stake/delegators/{delegatorAddr}/txs diff --git a/docs/light/specification.md b/docs/light/specification.md index d8897b2444a0..15f36b014460 100644 --- a/docs/light/specification.md +++ b/docs/light/specification.md @@ -323,6 +323,14 @@ return KeyOutput{ TODO +### [/stake/delegators/{delegatorAddr}/validators](api.md#stakedelegatorsdelegatorAddrvalidators---get) + +TODO + +### [/stake/delegators/{delegatorAddr}/validators/{validatorAddr}](api.md#stakedelegatorsdelegatorAddrvalidatorsvalidatorAddr---get) + +TODO + ### [/stake/delegators/{delegatorAddr}/txs](api.md#stakedelegatorsdelegatorAddrtxs---get) TODO diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index ac660f98f66b..1741f88234b7 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -20,41 +20,54 @@ const storeName = "stake" func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec) { - // GET /stake/delegators/{delegatorAddr} // Get all delegations (delegation, undelegation and redelegation) from a delegator + // Get all delegations (delegation, undelegation and redelegation) from a delegator r.HandleFunc( "/stake/delegators/{delegatorAddr}", delegatorHandlerFn(cliCtx, cdc), ).Methods("GET") - // GET /stake/delegators/{delegatorAddr}/txs?type= // Get all staking txs (i.e msgs) from a delegator + // Get all staking txs (i.e msgs) from a delegator r.HandleFunc( "/stake/delegators/{delegatorAddr}/txs", delegatorTxsHandlerFn(cliCtx, cdc), ).Methods("GET") - // GET /stake/delegators/{delegatorAddr}/delegations/{validatorAddr} // Query a delegation between a delegator and a validator + // Query all validators that a delegator is bonded to + r.HandleFunc( + "/stake/delegators/{delegatorAddr}/validators", + delegatorValidatorsHandlerFn(cliCtx, cdc), + ).Methods("GET") + + // Query a validator that a delegator is bonded to + r.HandleFunc( + "/stake/delegators/{delegatorAddr}/validators/{validatorAddr}", + delegatorValidatorHandlerFn(cliCtx, cdc), + ).Methods("GET") + + // Query a delegation between a delegator and a validator r.HandleFunc( "/stake/delegators/{delegatorAddr}/delegations/{validatorAddr}", delegationHandlerFn(cliCtx, cdc), ).Methods("GET") - // GET /stake/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr} // Query all unbonding_delegations between a delegator and a validator + // Query all unbonding_delegations between a delegator and a validator r.HandleFunc( "/stake/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}", unbondingDelegationsHandlerFn(cliCtx, cdc), ).Methods("GET") - // GET /stake/validators/ + // Get all validators r.HandleFunc( "/stake/validators", validatorsHandlerFn(cliCtx, cdc), ).Methods("GET") - // GET /stake/validators/{addr} + // Get a single validator info r.HandleFunc( "/stake/validators/{addr}", validatorHandlerFn(cliCtx, cdc), ).Methods("GET") + } // already resolve the rational shares to not handle this in the client diff --git a/x/stake/client/rest/utils.go b/x/stake/client/rest/utils.go index 86e714662861..da00eda0bd56 100644 --- a/x/stake/client/rest/utils.go +++ b/x/stake/client/rest/utils.go @@ -29,7 +29,6 @@ func contains(stringSlice []string, txType string) bool { func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAccAddr sdk.AccAddress) ( validator types.BechValidator, httpStatusCode int, errMsg string, err error) { - // check if the delegator is bonded or redelegated to the validator keyDel := stake.GetDelegationKey(delegatorAddr, validatorAccAddr) res, err := cliCtx.QueryStore(keyDel, storeName) @@ -46,7 +45,6 @@ func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delegator return types.BechValidator{}, http.StatusInternalServerError, "Error: ", err } if len(kvs) == 0 { - // the query will return empty if there are no delegations return types.BechValidator{}, http.StatusNoContent, "", nil } @@ -65,7 +63,6 @@ func getDelegatorDelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegat return DelegationWithoutRat{}, http.StatusInternalServerError, "couldn't query delegation. Error: ", err } - // the query will return empty if there is no data for this record if len(marshalledDelegation) == 0 { return DelegationWithoutRat{}, http.StatusNoContent, "", nil } @@ -93,7 +90,6 @@ func getDelegatorUndelegations(cliCtx context.CLIContext, cdc *wire.Codec, deleg return types.UnbondingDelegation{}, http.StatusInternalServerError, "couldn't query unbonding-delegation. Error: ", err } - // the query will return empty if there is no data for this record if len(marshalledUnbondingDelegation) == 0 { return types.UnbondingDelegation{}, http.StatusNoContent, "", nil }