From efd1a3ac44f09dcc8e8622951080948424efebac Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 14 May 2018 16:03:03 -0700 Subject: [PATCH 01/21] Typo fix --- types/tx_msg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/tx_msg.go b/types/tx_msg.go index e17d152a5..9e9a369ff 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -152,7 +152,7 @@ func (msg StdSignMsg) Bytes() []byte { //__________________________________________________________ -// TxDeocder unmarshals transaction bytes +// TxDecoder unmarshals transaction bytes type TxDecoder func(txBytes []byte) (Tx, Error) //__________________________________________________________ From ad3c63dded9e5a4aa77ce06bfb856f53efcf13f6 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 14 May 2018 16:43:51 -0700 Subject: [PATCH 02/21] Added POST /stake/bondunbond endpoint --- x/stake/client/rest/query.go | 7 +-- x/stake/client/rest/rest.go | 14 +++++ x/stake/client/rest/tx.go | 117 +++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 x/stake/client/rest/rest.go create mode 100644 x/stake/client/rest/tx.go diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 609390293..4a4b83901 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -14,13 +14,12 @@ import ( "github.com/cosmos/cosmos-sdk/x/stake" ) -// RegisterRoutes - Central function to define routes that get registered by the main application -func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { - r.HandleFunc("/stake/{delegator}/bonding_status/{validator}", BondingStatusHandlerFn("stake", cdc, kb, ctx)).Methods("GET") +func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { + r.HandleFunc("/stake/{delegator}/bonding_status/{candidate}", bondingStatusHandlerFn("stake", cdc, kb, ctx)).Methods("GET") } // BondingStatusHandlerFn - http request handler to query delegator bonding status -func BondingStatusHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // read parameters vars := mux.Vars(r) diff --git a/x/stake/client/rest/rest.go b/x/stake/client/rest/rest.go new file mode 100644 index 000000000..32d56f42c --- /dev/null +++ b/x/stake/client/rest/rest.go @@ -0,0 +1,14 @@ +package rest + +import ( + "github.com/gorilla/mux" + "github.com/tendermint/go-crypto/keys" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/wire" +) + +func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { + registerQueryRoutes(ctx, r, cdc, kb) + registerTxRoutes(ctx, r, cdc, kb) +} diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go new file mode 100644 index 000000000..75e0f8d75 --- /dev/null +++ b/x/stake/client/rest/tx.go @@ -0,0 +1,117 @@ +package rest + +import ( + "encoding/json" + "io/ioutil" + "net/http" + + "github.com/gorilla/mux" + "github.com/tendermint/go-crypto/keys" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + + "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 registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { + r.HandleFunc("/stake/bondunbond", bondUnbondRequestHandlerFn(cdc, kb, ctx)).Methods("POST") +} + +type bond struct { + Amount sdk.Coin `json:"amount"` + Candidate sdk.Address `json:"candidate"` +} + +type unbond struct { + Shares string `json:"shares"` + Candidate sdk.Address `json:"candidate"` +} + +type bondUnbondBody struct { + // fees is not used currently + // Fees sdk.Coin `json="fees"` + LocalAccountName string `json:"name"` + Password string `json:"password"` + ChainID string `json:"chain_id"` + Sequence int64 `json:"sequence"` + Bond []bond `json:"bond"` + Unbond []unbond `json:"unbond"` +} + +func bondUnbondRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var m bondUnbondBody + body, err := ioutil.ReadAll(r.Body) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + err = json.Unmarshal(body, &m) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + info, err := kb.Get(m.LocalAccountName) + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(err.Error())) + return + } + + // build messages + messages := make([]sdk.Msg, 0, len(m.Bond)+len(m.Unbond)) + for _, bond := range m.Bond { + msg := stake.NewMsgDelegate(info.Address(), bond.Candidate, bond.Amount) + messages = append(messages, msg) + } + for _, unbond := range m.Unbond { + msg := stake.NewMsgUnbond(info.Address(), unbond.Candidate, unbond.Shares) + messages = append(messages, msg) + } + + // sign messages + signedTxs := make([][]byte, 0, len(messages)) + for _, msg := range messages { + // increment sequence for each message + ctx = ctx.WithSequence(m.Sequence) + m.Sequence++ + + txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, msg, cdc) + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(err.Error())) + return + } + + signedTxs = append(signedTxs, txBytes) + } + + // send + // XXX the operation might not be atomic if a tx fails + // should we have a sdk.MultiMsg type to make sending atomic? + results := make([]*ctypes.ResultBroadcastTxCommit, 0, len(signedTxs)) + for _, txBytes := range signedTxs { + res, err := ctx.BroadcastTx(txBytes) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + results = append(results, res) + } + + output, err := json.MarshalIndent(results, "", " ") + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + + w.Write(output) + } +} From 660e4e9080580e7a7b7880c5832db330b37c70e0 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 14 May 2018 16:44:07 -0700 Subject: [PATCH 03/21] Fixed json field names in stake msg types --- x/stake/msg.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x/stake/msg.go b/x/stake/msg.go index 0adff84d9..4bfc496de 100644 --- a/x/stake/msg.go +++ b/x/stake/msg.go @@ -117,8 +117,8 @@ func (msg MsgEditCandidacy) ValidateBasic() sdk.Error { // MsgDelegate - struct for bonding transactions type MsgDelegate struct { - DelegatorAddr sdk.Address `json:"address"` - ValidatorAddr sdk.Address `json:"address"` + DelegatorAddr sdk.Address `json:"delegator"` + ValidatorAddr sdk.Address `json:"candidate"` Bond sdk.Coin `json:"bond"` } @@ -164,8 +164,8 @@ func (msg MsgDelegate) ValidateBasic() sdk.Error { // MsgUnbond - struct for unbonding transactions type MsgUnbond struct { - DelegatorAddr sdk.Address `json:"address"` - ValidatorAddr sdk.Address `json:"address"` + DelegatorAddr sdk.Address `json:"delegator"` + ValidatorAddr sdk.Address `json:"candidate"` Shares string `json:"shares"` } From 5b81938e576ddd17e1dfd3fe5806b0686c906081 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 14 May 2018 16:49:26 -0700 Subject: [PATCH 04/21] Enable stake REST routes --- client/lcd/root.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/lcd/root.go b/client/lcd/root.go index a7be5079b..df8be897c 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -22,6 +22,7 @@ import ( auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest" bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest" ibc "github.com/cosmos/cosmos-sdk/x/ibc/client/rest" + stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest" ) const ( @@ -83,5 +84,6 @@ func createHandler(cdc *wire.Codec) http.Handler { auth.RegisterRoutes(ctx, r, cdc, "acc") bank.RegisterRoutes(ctx, r, cdc, kb) ibc.RegisterRoutes(ctx, r, cdc, kb) + stake.RegisterRoutes(ctx, r, cdc, kb) return r } From 8e104030d5578956cc462022305f4043f88eaca8 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 14 May 2018 17:01:51 -0700 Subject: [PATCH 05/21] Fixed stake query REST handler --- x/stake/client/rest/query.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 4a4b83901..700a65f2b 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -24,7 +24,7 @@ func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, // read parameters vars := mux.Vars(r) delegator := vars["delegator"] - validator := vars["validator"] + candidate := vars["candidate"] bz, err := hex.DecodeString(delegator) if err != nil { @@ -34,7 +34,7 @@ func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, } delegatorAddr := sdk.Address(bz) - bz, err = hex.DecodeString(validator) + bz, err = hex.DecodeString(candidate) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) From 39995fe0659caecba754bb27c2a420db0905c5eb Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 14 May 2018 17:43:46 -0700 Subject: [PATCH 06/21] Added (non-working) stake REST tests --- client/lcd/lcd_test.go | 235 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 221 insertions(+), 14 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 66a8a4085..d78e7655c 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -32,15 +32,19 @@ import ( client "github.com/cosmos/cosmos-sdk/client" keys "github.com/cosmos/cosmos-sdk/client/keys" bapp "github.com/cosmos/cosmos-sdk/examples/basecoin/app" - btypes "github.com/cosmos/cosmos-sdk/examples/basecoin/types" tests "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/stake" ) var ( coinDenom = "mycoin" coinAmount = int64(10000000) + stakeDenom = "steak" + candidateAddr1 = "127A12E4489FEB5A74201426B0CB538732FB4C8E" + candidateAddr2 = "C2893CA8EBDDD1C5F938CAB3BAEFE53A2E266698" + // XXX bad globals name = "test" password = "0123456789" @@ -305,6 +309,56 @@ func TestTxs(t *testing.T) { // assert.NotEqual(t, "[]", body) } +func TestBond(t *testing.T) { + + acc := getAccount(t, sendAddr) + initialBalance := acc.GetCoins() + + // create bond TX + resultTx := doBond(t, port, seed) + tests.WaitForHeight(resultTx.Height+1, port) + + // check if tx was commited + assert.Equal(t, uint32(0), resultTx.CheckTx.Code) + assert.Equal(t, uint32(0), resultTx.DeliverTx.Code) + + // query sender + acc = getAccount(t, sendAddr) + coins := acc.GetCoins() + mycoins := coins[0] + assert.Equal(t, coinDenom, mycoins.Denom) + assert.Equal(t, initialBalance[0].Amount-1, mycoins.Amount) + + // query candidate + bond := getDelegatorBond(t, sendAddr, candidateAddr1) + assert.Equal(t, "foo", bond.Shares.String()) +} + +func TestUnbond(t *testing.T) { + + acc := getAccount(t, sendAddr) + initialBalance := acc.GetCoins() + + // create unbond TX + resultTx := doUnbond(t, port, seed) + tests.WaitForHeight(resultTx.Height+1, port) + + // check if tx was commited + assert.Equal(t, uint32(0), resultTx.CheckTx.Code) + assert.Equal(t, uint32(0), resultTx.DeliverTx.Code) + + // query sender + acc = getAccount(t, sendAddr) + coins := acc.GetCoins() + mycoins := coins[0] + assert.Equal(t, coinDenom, mycoins.Denom) + assert.Equal(t, initialBalance[0].Amount, mycoins.Amount) + + // query candidate + bond := getDelegatorBond(t, sendAddr, candidateAddr1) + assert.Equal(t, "foo", bond.Shares.String()) +} + //__________________________________________________________ // helpers @@ -347,21 +401,74 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { return nil, nil, err } - coins := sdk.Coins{{coinDenom, coinAmount}} - appState := map[string]interface{}{ - "accounts": []*btypes.GenesisAccount{ + genDoc.AppStateJSON = []byte(` + { + "accounts": [ { - Name: "tester", - Address: pubKey.Address(), - Coins: coins, - }, - }, + "name": "tester", + "address": "` + pubKey.Address().String() + `", + "coins": [{"denom": "` + coinDenom + `", "amount": 100000}] + } + ], + "stake": { + "pool": { + "total_supply": 1650, + "bonded_shares": "1100", + "unbonded_shares": "0", + "bonded_pool": 1100, + "unbonded_pool": 0, + "inflation_last_time": 0, + "inflation": "7/100" + }, + "params": { + "inflation_rate_change": "13/100", + "inflation_max": "1/5", + "inflation_min": "7/100", + "goal_bonded": "67/100", + "max_validators": 100, + "bond_denom": "` + stakeDenom + `" + }, + "candidates": [ + { + "status": 1, + "owner": "` + candidateAddr1 + `", + "pub_key": { + "type": "AC26791624DE60", + "value": "TZTQnfqOsi89SeoXVnIw+tnFJnr4X8qVC0U8AsEmFk4=" + }, + "assets": "100", + "liabilities": "0", + "description": { + "moniker": "adrian", + "identity": "", + "website": "", + "details": "" + }, + "validator_bond_height": 0, + "validator_bond_counter": 0 + }, + { + "status": 1, + "owner": "` + candidateAddr2 + `", + "pub_key": { + "type": "AC26791624DE60", + "value": "RpX+xkwnCNw5DpBelscz4//TiODyC9RDiyIuD6NEwx0=" + }, + "assets": "100", + "liabilities": "0", + "description": { + "moniker": "yourname", + "identity": "", + "website": "", + "details": "" + }, + "validator_bond_height": 0, + "validator_bond_counter": 0 + } + ] + } } - stateBytes, err := json.Marshal(appState) - if err != nil { - return nil, nil, err - } - genDoc.AppStateJSON = stateBytes + `) // LCD listen address port = fmt.Sprintf("%d", 17377) // XXX @@ -490,3 +597,103 @@ func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroad return resultTx } + +func getDelegatorBond(t *testing.T, delegatorAddr, candidateAddr string) stake.DelegatorBond { + // get the account to get the sequence + res, body := request(t, port, "GET", "/stake/"+delegatorAddr+"/bonding_info/"+candidateAddr, nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + var bond stake.DelegatorBond + err := cdc.UnmarshalJSON([]byte(body), &bond) + require.Nil(t, err) + return bond +} + +func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) { + // get the account to get the sequence + acc := getAccount(t, sendAddr) + sequence := acc.GetSequence() + + // send + jsonStr := []byte(fmt.Sprintf(`{ + "name": "%s", + "password": "%s", + "sequence": %d, + "bond": [ + { + "candidate": "%s", + "amount": { "denom": "%s", "amount": 100 } + } + ], + "unbond": [] + }`, name, password, sequence, candidateAddr1, stakeDenom)) + res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + err := cdc.UnmarshalJSON([]byte(body), &resultTx) + require.Nil(t, err) + + return +} + +func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) { + // get the account to get the sequence + acc := getAccount(t, sendAddr) + sequence := acc.GetSequence() + + // send + jsonStr := []byte(fmt.Sprintf(`{ + "name": "%s", + "password": "%s", + "sequence": %d, + "bond": [], + "unbond": [ + { + "candidate": "%s", + "shares": "1" + } + ] + }`, name, password, sequence, candidateAddr1, stakeDenom)) + res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + err := cdc.UnmarshalJSON([]byte(body), &resultTx) + require.Nil(t, err) + + return +} + +func doMultiBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) { + // get the account to get the sequence + acc := getAccount(t, sendAddr) + sequence := acc.GetSequence() + + // send + jsonStr := []byte(fmt.Sprintf(`{ + "name": "%s", + "password": "%s", + "sequence": %d, + "bond": [ + { + "candidate": "%s", + "amount": { "denom": "%s", "amount": 1 } + }, + { + "candidate": "%s", + "amount": { "denom": "%s", "amount": 1 } + }, + ], + "unbond": [ + { + "candidate": "%s", + "shares": "1" + } + ] + }`, name, password, sequence, candidateAddr1, stakeDenom, candidateAddr2, stakeDenom, candidateAddr1)) + res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + err := cdc.UnmarshalJSON([]byte(body), &resultTx) + require.Nil(t, err) + + return +} From 98b9040c633d69a5a905de5d4966a9817bff8cce Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Fri, 18 May 2018 17:05:15 +0900 Subject: [PATCH 07/21] Use actual types for genesis doc instead of unmarshaling JSON --- client/lcd/lcd_test.go | 134 ++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 68 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index d78e7655c..9406d7ce9 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -16,6 +16,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" cryptoKeys "github.com/tendermint/go-crypto/keys" tmcfg "github.com/tendermint/tendermint/config" nm "github.com/tendermint/tendermint/node" @@ -32,6 +33,7 @@ import ( client "github.com/cosmos/cosmos-sdk/client" keys "github.com/cosmos/cosmos-sdk/client/keys" bapp "github.com/cosmos/cosmos-sdk/examples/basecoin/app" + btypes "github.com/cosmos/cosmos-sdk/examples/basecoin/types" tests "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake" @@ -387,6 +389,8 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { config.Consensus.TimeoutCommit = 1000 config.Consensus.SkipTimeoutCommit = false + fmt.Println("test") + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) // logger = log.NewFilter(logger, log.AllowError()) privValidatorFile := config.PrivValidatorFile() @@ -401,74 +405,68 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { return nil, nil, err } - genDoc.AppStateJSON = []byte(` - { - "accounts": [ - { - "name": "tester", - "address": "` + pubKey.Address().String() + `", - "coins": [{"denom": "` + coinDenom + `", "amount": 100000}] - } - ], - "stake": { - "pool": { - "total_supply": 1650, - "bonded_shares": "1100", - "unbonded_shares": "0", - "bonded_pool": 1100, - "unbonded_pool": 0, - "inflation_last_time": 0, - "inflation": "7/100" - }, - "params": { - "inflation_rate_change": "13/100", - "inflation_max": "1/5", - "inflation_min": "7/100", - "goal_bonded": "67/100", - "max_validators": 100, - "bond_denom": "` + stakeDenom + `" - }, - "candidates": [ - { - "status": 1, - "owner": "` + candidateAddr1 + `", - "pub_key": { - "type": "AC26791624DE60", - "value": "TZTQnfqOsi89SeoXVnIw+tnFJnr4X8qVC0U8AsEmFk4=" - }, - "assets": "100", - "liabilities": "0", - "description": { - "moniker": "adrian", - "identity": "", - "website": "", - "details": "" - }, - "validator_bond_height": 0, - "validator_bond_counter": 0 - }, - { - "status": 1, - "owner": "` + candidateAddr2 + `", - "pub_key": { - "type": "AC26791624DE60", - "value": "RpX+xkwnCNw5DpBelscz4//TiODyC9RDiyIuD6NEwx0=" - }, - "assets": "100", - "liabilities": "0", - "description": { - "moniker": "yourname", - "identity": "", - "website": "", - "details": "" - }, - "validator_bond_height": 0, - "validator_bond_counter": 0 - } - ] - } + genDoc.Validators = []tmtypes.GenesisValidator{ + tmtypes.GenesisValidator{ + PubKey: crypto.GenPrivKeyEd25519().PubKey(), + Power: 100, + Name: "val1", + }, + tmtypes.GenesisValidator{ + PubKey: crypto.GenPrivKeyEd25519().PubKey(), + Power: 100, + Name: "val2", + }, } - `) + + coins := sdk.Coins{{coinDenom, coinAmount}} + appState := map[string]interface{}{ + "accounts": []*btypes.GenesisAccount{ + { + Name: "tester", + Address: pubKey.Address(), + Coins: coins, + }, + }, + "stake": stake.GenesisState{ + Pool: stake.Pool{ + TotalSupply: 1650, + BondedShares: sdk.NewRat(200, 1), + UnbondedShares: sdk.ZeroRat(), + BondedPool: 200, + UnbondedPool: 0, + InflationLastTime: 0, + Inflation: sdk.NewRat(7, 100), + }, + Params: stake.Params{ + InflationRateChange: sdk.NewRat(13, 100), + InflationMax: sdk.NewRat(1, 5), + InflationMin: sdk.NewRat(7, 100), + GoalBonded: sdk.NewRat(67, 100), + MaxValidators: 100, + BondDenom: stakeDenom, + }, + Candidates: []stake.Candidate{ + { + Status: 1, + Address: genDoc.Validators[0].PubKey.Address(), + PubKey: genDoc.Validators[0].PubKey, + Assets: sdk.NewRat(100, 1), + Liabilities: sdk.ZeroRat(), + Description: stake.Description{ + Moniker: "adrian", + }, + ValidatorBondHeight: 0, + ValidatorBondCounter: 0, + }, + }, + }, + } + + stateBytes, err := json.Marshal(appState) + if err != nil { + return nil, nil, err + } + genDoc.AppStateJSON = stateBytes // LCD listen address port = fmt.Sprintf("%d", 17377) // XXX @@ -652,7 +650,7 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT "shares": "1" } ] - }`, name, password, sequence, candidateAddr1, stakeDenom)) + }`, name, password, sequence, candidateAddr1)) res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) From 10056d36d1b761093c79934e134e47c77313870c Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Sun, 20 May 2018 14:09:52 +0900 Subject: [PATCH 08/21] Set generated candidate addresses in lcd tests --- client/lcd/lcd_test.go | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 9406d7ce9..263d75c25 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -2,6 +2,7 @@ package lcd import ( "bytes" + "encoding/hex" "encoding/json" "fmt" "io/ioutil" @@ -44,8 +45,8 @@ var ( coinAmount = int64(10000000) stakeDenom = "steak" - candidateAddr1 = "127A12E4489FEB5A74201426B0CB538732FB4C8E" - candidateAddr2 = "C2893CA8EBDDD1C5F938CAB3BAEFE53A2E266698" + candidateAddr1 = "" + candidateAddr2 = "" // XXX bad globals name = "test" @@ -405,18 +406,20 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { return nil, nil, err } - genDoc.Validators = []tmtypes.GenesisValidator{ + genDoc.Validators = append(genDoc.Validators, tmtypes.GenesisValidator{ PubKey: crypto.GenPrivKeyEd25519().PubKey(), - Power: 100, + Power: 1, Name: "val1", }, tmtypes.GenesisValidator{ PubKey: crypto.GenPrivKeyEd25519().PubKey(), - Power: 100, + Power: 1, Name: "val2", }, - } + ) + candidateAddr1 = hex.EncodeToString(genDoc.Validators[0].PubKey.Address()) + candidateAddr2 = hex.EncodeToString(genDoc.Validators[1].PubKey.Address()) coins := sdk.Coins{{coinDenom, coinAmount}} appState := map[string]interface{}{ @@ -453,7 +456,19 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { Assets: sdk.NewRat(100, 1), Liabilities: sdk.ZeroRat(), Description: stake.Description{ - Moniker: "adrian", + Moniker: "validator1", + }, + ValidatorBondHeight: 0, + ValidatorBondCounter: 0, + }, + { + Status: 1, + Address: genDoc.Validators[1].PubKey.Address(), + PubKey: genDoc.Validators[1].PubKey, + Assets: sdk.NewRat(100, 1), + Liabilities: sdk.ZeroRat(), + Description: stake.Description{ + Moniker: "validator2", }, ValidatorBondHeight: 0, ValidatorBondCounter: 0, From 074dfd79200c4bb8e0e6a2506ceedc790813df30 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Sun, 20 May 2018 14:43:53 +0900 Subject: [PATCH 09/21] Added candidate list REST query handler --- x/stake/client/rest/query.go | 45 ++++++++++++++++++++++++++++++++---- x/stake/client/rest/rest.go | 3 ++- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 700a65f2b..576bad3cc 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -6,7 +6,6 @@ import ( "net/http" "github.com/gorilla/mux" - "github.com/tendermint/go-crypto/keys" "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,12 +13,13 @@ import ( "github.com/cosmos/cosmos-sdk/x/stake" ) -func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { - r.HandleFunc("/stake/{delegator}/bonding_status/{candidate}", bondingStatusHandlerFn("stake", cdc, kb, ctx)).Methods("GET") +func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) { + r.HandleFunc("/stake/{delegator}/bonding_status/{candidate}", bondingStatusHandlerFn("stake", cdc, ctx)).Methods("GET") + r.HandleFunc("/stake/candidates", candidatesHandlerFn("stake", cdc, ctx)).Methods("GET") } -// BondingStatusHandlerFn - http request handler to query delegator bonding status -func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +// bondingStatusHandlerFn - http request handler to query delegator bonding status +func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // read parameters vars := mux.Vars(r) @@ -75,3 +75,38 @@ func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, w.Write(output) } } + +// candidatesHandlerFn - http request handler to query list of candidates +func candidatesHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + res, err := ctx.Query(stake.CandidatesKey, storeName) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Couldn't query bond. Error: %s", err.Error()))) + return + } + + // the query will return empty if there is no data for this bond + if len(res) == 0 { + w.WriteHeader(http.StatusNoContent) + return + } + + var candidates []stake.Candidate + err = cdc.UnmarshalBinary(res, &candidates) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Couldn't decode candidates. Error: %s", err.Error()))) + return + } + + output, err := cdc.MarshalJSON(candidates) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + + w.Write(output) + } +} diff --git a/x/stake/client/rest/rest.go b/x/stake/client/rest/rest.go index 32d56f42c..1f3a2957d 100644 --- a/x/stake/client/rest/rest.go +++ b/x/stake/client/rest/rest.go @@ -8,7 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/wire" ) +// RegisterRoutes registers staking-related REST handlers to a router func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { - registerQueryRoutes(ctx, r, cdc, kb) + registerQueryRoutes(ctx, r, cdc) registerTxRoutes(ctx, r, cdc, kb) } From 2c46662141a072480f60db9492583656dd488d7d Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Sun, 20 May 2018 14:59:29 +0900 Subject: [PATCH 10/21] Added LCD test for candidates query --- client/lcd/lcd_test.go | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 263d75c25..5ed6ddcc9 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -312,6 +312,13 @@ func TestTxs(t *testing.T) { // assert.NotEqual(t, "[]", body) } +func TestCandidates(t *testing.T) { + candidates := getCandidates(t) + assert.Equal(t, len(candidates), 2) + assert.Equal(t, hex.EncodeToString(candidates[0].Address), candidateAddr1) + assert.Equal(t, hex.EncodeToString(candidates[1].Address), candidateAddr2) +} + func TestBond(t *testing.T) { acc := getAccount(t, sendAddr) @@ -390,10 +397,8 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { config.Consensus.TimeoutCommit = 1000 config.Consensus.SkipTimeoutCommit = false - fmt.Println("test") - logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - // logger = log.NewFilter(logger, log.AllowError()) + logger = log.NewFilter(logger, log.AllowError()) privValidatorFile := config.PrivValidatorFile() privVal := pvm.LoadOrGenFilePV(privValidatorFile) db := dbm.NewMemDB() @@ -418,8 +423,8 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { Name: "val2", }, ) - candidateAddr1 = hex.EncodeToString(genDoc.Validators[0].PubKey.Address()) - candidateAddr2 = hex.EncodeToString(genDoc.Validators[1].PubKey.Address()) + candidateAddr1 = hex.EncodeToString(genDoc.Validators[1].PubKey.Address()) + candidateAddr2 = hex.EncodeToString(genDoc.Validators[2].PubKey.Address()) coins := sdk.Coins{{coinDenom, coinAmount}} appState := map[string]interface{}{ @@ -451,8 +456,8 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { Candidates: []stake.Candidate{ { Status: 1, - Address: genDoc.Validators[0].PubKey.Address(), - PubKey: genDoc.Validators[0].PubKey, + Address: genDoc.Validators[1].PubKey.Address(), + PubKey: genDoc.Validators[1].PubKey, Assets: sdk.NewRat(100, 1), Liabilities: sdk.ZeroRat(), Description: stake.Description{ @@ -463,8 +468,8 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { }, { Status: 1, - Address: genDoc.Validators[1].PubKey.Address(), - PubKey: genDoc.Validators[1].PubKey, + Address: genDoc.Validators[2].PubKey.Address(), + PubKey: genDoc.Validators[2].PubKey, Assets: sdk.NewRat(100, 1), Liabilities: sdk.ZeroRat(), Description: stake.Description{ @@ -621,6 +626,16 @@ func getDelegatorBond(t *testing.T, delegatorAddr, candidateAddr string) stake.D return bond } +func getCandidates(t *testing.T) []stake.Candidate { + // get the account to get the sequence + res, body := request(t, port, "GET", "/stake/candidates", nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + var candidates []stake.Candidate + err := cdc.UnmarshalJSON([]byte(body), &candidates) + require.Nil(t, err) + return candidates +} + func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) { // get the account to get the sequence acc := getAccount(t, sendAddr) From ae9a9eaaa3433e3ba890345984d34f5afca35937 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Sun, 20 May 2018 15:16:07 +0900 Subject: [PATCH 11/21] Updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a9eeb71f..89b7ec744 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ FEATURES * [stake] Creation of a validator/delegation generics in `/types` * [stake] Helper Description of the store in x/stake/store.md * [stake] removed use of caches in the stake keeper +* [stake] Added REST API BUG FIXES From cb107c738343274022f7a1778cbfdf825c78bcd8 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 21 May 2018 10:46:09 +0900 Subject: [PATCH 12/21] Fixed LCD tests --- client/lcd/lcd_test.go | 83 ++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 47 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 5ed6ddcc9..157a38681 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -33,8 +33,7 @@ import ( client "github.com/cosmos/cosmos-sdk/client" keys "github.com/cosmos/cosmos-sdk/client/keys" - bapp "github.com/cosmos/cosmos-sdk/examples/basecoin/app" - btypes "github.com/cosmos/cosmos-sdk/examples/basecoin/types" + gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app" tests "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake" @@ -321,9 +320,6 @@ func TestCandidates(t *testing.T) { func TestBond(t *testing.T) { - acc := getAccount(t, sendAddr) - initialBalance := acc.GetCoins() - // create bond TX resultTx := doBond(t, port, seed) tests.WaitForHeight(resultTx.Height+1, port) @@ -333,22 +329,17 @@ func TestBond(t *testing.T) { assert.Equal(t, uint32(0), resultTx.DeliverTx.Code) // query sender - acc = getAccount(t, sendAddr) + acc := getAccount(t, sendAddr) coins := acc.GetCoins() - mycoins := coins[0] - assert.Equal(t, coinDenom, mycoins.Denom) - assert.Equal(t, initialBalance[0].Amount-1, mycoins.Amount) + assert.Equal(t, int64(9999900), coins.AmountOf(stakeDenom)) // query candidate bond := getDelegatorBond(t, sendAddr, candidateAddr1) - assert.Equal(t, "foo", bond.Shares.String()) + assert.Equal(t, "100/1", bond.Shares.String()) } func TestUnbond(t *testing.T) { - acc := getAccount(t, sendAddr) - initialBalance := acc.GetCoins() - // create unbond TX resultTx := doUnbond(t, port, seed) tests.WaitForHeight(resultTx.Height+1, port) @@ -358,15 +349,13 @@ func TestUnbond(t *testing.T) { assert.Equal(t, uint32(0), resultTx.DeliverTx.Code) // query sender - acc = getAccount(t, sendAddr) + acc := getAccount(t, sendAddr) coins := acc.GetCoins() - mycoins := coins[0] - assert.Equal(t, coinDenom, mycoins.Denom) - assert.Equal(t, initialBalance[0].Amount, mycoins.Amount) + assert.Equal(t, int64(9999911), coins.AmountOf(stakeDenom)) // query candidate bond := getDelegatorBond(t, sendAddr, candidateAddr1) - assert.Equal(t, "foo", bond.Shares.String()) + assert.Equal(t, "99/1", bond.Shares.String()) } //__________________________________________________________ @@ -398,12 +387,12 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { config.Consensus.SkipTimeoutCommit = false logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - logger = log.NewFilter(logger, log.AllowError()) + // logger = log.NewFilter(logger, log.AllowError()) privValidatorFile := config.PrivValidatorFile() privVal := pvm.LoadOrGenFilePV(privValidatorFile) db := dbm.NewMemDB() - app := bapp.NewBasecoinApp(logger, db) - cdc = bapp.MakeCodec() // XXX + app := gapp.NewGaiaApp(logger, db) + cdc = gapp.MakeCodec() // XXX genesisFile := config.GenesisFile() genDoc, err := tmtypes.GenesisDocFromFile(genesisFile) @@ -415,27 +404,24 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { tmtypes.GenesisValidator{ PubKey: crypto.GenPrivKeyEd25519().PubKey(), Power: 1, - Name: "val1", - }, - tmtypes.GenesisValidator{ - PubKey: crypto.GenPrivKeyEd25519().PubKey(), - Power: 1, - Name: "val2", + Name: "val", }, ) - candidateAddr1 = hex.EncodeToString(genDoc.Validators[1].PubKey.Address()) - candidateAddr2 = hex.EncodeToString(genDoc.Validators[2].PubKey.Address()) + candidateAddr1 = hex.EncodeToString(genDoc.Validators[0].PubKey.Address()) + candidateAddr2 = hex.EncodeToString(genDoc.Validators[1].PubKey.Address()) - coins := sdk.Coins{{coinDenom, coinAmount}} - appState := map[string]interface{}{ - "accounts": []*btypes.GenesisAccount{ + coins := sdk.Coins{ + {coinDenom, coinAmount}, + {stakeDenom, coinAmount}, + } + appState := gapp.GenesisState{ + Accounts: []gapp.GenesisAccount{ { - Name: "tester", Address: pubKey.Address(), Coins: coins, }, }, - "stake": stake.GenesisState{ + StakeData: stake.GenesisState{ Pool: stake.Pool{ TotalSupply: 1650, BondedShares: sdk.NewRat(200, 1), @@ -456,9 +442,9 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { Candidates: []stake.Candidate{ { Status: 1, - Address: genDoc.Validators[1].PubKey.Address(), - PubKey: genDoc.Validators[1].PubKey, - Assets: sdk.NewRat(100, 1), + Address: genDoc.Validators[0].PubKey.Address(), + PubKey: genDoc.Validators[0].PubKey, + Assets: sdk.NewRat(1000, 1), Liabilities: sdk.ZeroRat(), Description: stake.Description{ Moniker: "validator1", @@ -468,8 +454,8 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { }, { Status: 1, - Address: genDoc.Validators[2].PubKey.Address(), - PubKey: genDoc.Validators[2].PubKey, + Address: genDoc.Validators[1].PubKey.Address(), + PubKey: genDoc.Validators[1].PubKey, Assets: sdk.NewRat(100, 1), Liabilities: sdk.ZeroRat(), Description: stake.Description{ @@ -482,7 +468,7 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { }, } - stateBytes, err := json.Marshal(appState) + stateBytes, err := cdc.MarshalJSONIndent(appState, "", " ") if err != nil { return nil, nil, err } @@ -618,7 +604,7 @@ func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroad func getDelegatorBond(t *testing.T, delegatorAddr, candidateAddr string) stake.DelegatorBond { // get the account to get the sequence - res, body := request(t, port, "GET", "/stake/"+delegatorAddr+"/bonding_info/"+candidateAddr, nil) + res, body := request(t, port, "GET", "/stake/"+delegatorAddr+"/bonding_status/"+candidateAddr, nil) require.Equal(t, http.StatusOK, res.StatusCode, body) var bond stake.DelegatorBond err := cdc.UnmarshalJSON([]byte(body), &bond) @@ -657,10 +643,11 @@ func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxC res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) - err := cdc.UnmarshalJSON([]byte(body), &resultTx) + var results []ctypes.ResultBroadcastTxCommit + err := cdc.UnmarshalJSON([]byte(body), &results) require.Nil(t, err) - return + return results[0] } func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) { @@ -684,10 +671,11 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) - err := cdc.UnmarshalJSON([]byte(body), &resultTx) + var results []ctypes.ResultBroadcastTxCommit + err := cdc.UnmarshalJSON([]byte(body), &results) require.Nil(t, err) - return + return results[0] } func doMultiBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) { @@ -720,8 +708,9 @@ func doMultiBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadca res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) - err := cdc.UnmarshalJSON([]byte(body), &resultTx) + var results []ctypes.ResultBroadcastTxCommit + err := cdc.UnmarshalJSON([]byte(body), &results) require.Nil(t, err) - return + return results[0] } From 6ad16e6c9019d1a1bbd0fd4cc9922105d45fc9f1 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 21 May 2018 10:52:06 +0900 Subject: [PATCH 13/21] Changes to /stake/candidates REST handler --- client/lcd/lcd_test.go | 2 +- x/stake/client/rest/query.go | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 157a38681..578490ca1 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -387,7 +387,7 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { config.Consensus.SkipTimeoutCommit = false logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - // logger = log.NewFilter(logger, log.AllowError()) + logger = log.NewFilter(logger, log.AllowError()) privValidatorFile := config.PrivValidatorFile() privVal := pvm.LoadOrGenFilePV(privValidatorFile) db := dbm.NewMemDB() diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 576bad3cc..4decfdbfd 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -79,25 +79,28 @@ func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreC // candidatesHandlerFn - http request handler to query list of candidates func candidatesHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - res, err := ctx.Query(stake.CandidatesKey, storeName) + res, err := ctx.QuerySubspace(cdc, stake.CandidatesKey, storeName) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("Couldn't query bond. Error: %s", err.Error()))) + w.Write([]byte(fmt.Sprintf("Couldn't query candidates. Error: %s", err.Error()))) return } - // the query will return empty if there is no data for this bond if len(res) == 0 { w.WriteHeader(http.StatusNoContent) return } - var candidates []stake.Candidate - err = cdc.UnmarshalBinary(res, &candidates) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("Couldn't decode candidates. Error: %s", err.Error()))) - return + candidates := make(stake.Candidates, 0, len(res)) + for _, kv := range res { + var candidate stake.Candidate + err = cdc.UnmarshalBinary(kv.Value, &candidate) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Couldn't decode candidate. Error: %s", err.Error()))) + return + } + candidates = append(candidates, candidate) } output, err := cdc.MarshalJSON(candidates) From 0738de17f4ab37157dd199df583ef0acdea93245 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Fri, 25 May 2018 00:14:10 +0900 Subject: [PATCH 14/21] Removed candidates endpoint and addressed some comments --- client/lcd/lcd_test.go | 56 +++++++++--------------------------- x/stake/client/rest/query.go | 48 ++++--------------------------- 2 files changed, 19 insertions(+), 85 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 578490ca1..7d1dab676 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -311,13 +311,6 @@ func TestTxs(t *testing.T) { // assert.NotEqual(t, "[]", body) } -func TestCandidates(t *testing.T) { - candidates := getCandidates(t) - assert.Equal(t, len(candidates), 2) - assert.Equal(t, hex.EncodeToString(candidates[0].Address), candidateAddr1) - assert.Equal(t, hex.EncodeToString(candidates[1].Address), candidateAddr2) -} - func TestBond(t *testing.T) { // create bond TX @@ -334,7 +327,7 @@ func TestBond(t *testing.T) { assert.Equal(t, int64(9999900), coins.AmountOf(stakeDenom)) // query candidate - bond := getDelegatorBond(t, sendAddr, candidateAddr1) + bond := getDelegation(t, sendAddr, candidateAddr1) assert.Equal(t, "100/1", bond.Shares.String()) } @@ -354,7 +347,7 @@ func TestUnbond(t *testing.T) { assert.Equal(t, int64(9999911), coins.AmountOf(stakeDenom)) // query candidate - bond := getDelegatorBond(t, sendAddr, candidateAddr1) + bond := getDelegation(t, sendAddr, candidateAddr1) assert.Equal(t, "99/1", bond.Shares.String()) } @@ -423,13 +416,10 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { }, StakeData: stake.GenesisState{ Pool: stake.Pool{ - TotalSupply: 1650, - BondedShares: sdk.NewRat(200, 1), - UnbondedShares: sdk.ZeroRat(), - BondedPool: 200, - UnbondedPool: 0, - InflationLastTime: 0, - Inflation: sdk.NewRat(7, 100), + BondedShares: sdk.NewRat(200, 1), + UnbondedShares: sdk.ZeroRat(), + Inflation: sdk.NewRat(7, 100), + PrevBondedShares: sdk.ZeroRat(), }, Params: stake.Params{ InflationRateChange: sdk.NewRat(13, 100), @@ -439,30 +429,20 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { MaxValidators: 100, BondDenom: stakeDenom, }, - Candidates: []stake.Candidate{ + Validators: []stake.Validator{ { - Status: 1, - Address: genDoc.Validators[0].PubKey.Address(), - PubKey: genDoc.Validators[0].PubKey, - Assets: sdk.NewRat(1000, 1), - Liabilities: sdk.ZeroRat(), + Owner: genDoc.Validators[0].PubKey.Address(), + PubKey: genDoc.Validators[0].PubKey, Description: stake.Description{ Moniker: "validator1", }, - ValidatorBondHeight: 0, - ValidatorBondCounter: 0, }, { - Status: 1, - Address: genDoc.Validators[1].PubKey.Address(), - PubKey: genDoc.Validators[1].PubKey, - Assets: sdk.NewRat(100, 1), - Liabilities: sdk.ZeroRat(), + Owner: genDoc.Validators[1].PubKey.Address(), + PubKey: genDoc.Validators[1].PubKey, Description: stake.Description{ Moniker: "validator2", }, - ValidatorBondHeight: 0, - ValidatorBondCounter: 0, }, }, }, @@ -602,26 +582,16 @@ func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroad return resultTx } -func getDelegatorBond(t *testing.T, delegatorAddr, candidateAddr string) stake.DelegatorBond { +func getDelegation(t *testing.T, delegatorAddr, candidateAddr string) stake.Delegation { // get the account to get the sequence res, body := request(t, port, "GET", "/stake/"+delegatorAddr+"/bonding_status/"+candidateAddr, nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - var bond stake.DelegatorBond + var bond stake.Delegation err := cdc.UnmarshalJSON([]byte(body), &bond) require.Nil(t, err) return bond } -func getCandidates(t *testing.T) []stake.Candidate { - // get the account to get the sequence - res, body := request(t, port, "GET", "/stake/candidates", nil) - require.Equal(t, http.StatusOK, res.StatusCode, body) - var candidates []stake.Candidate - err := cdc.UnmarshalJSON([]byte(body), &candidates) - require.Nil(t, err) - return candidates -} - func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) { // get the account to get the sequence acc := getAccount(t, sendAddr) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 4decfdbfd..02cc732c9 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -14,8 +14,10 @@ import ( ) func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) { - r.HandleFunc("/stake/{delegator}/bonding_status/{candidate}", bondingStatusHandlerFn("stake", cdc, ctx)).Methods("GET") - r.HandleFunc("/stake/candidates", candidatesHandlerFn("stake", cdc, ctx)).Methods("GET") + r.HandleFunc( + "/stake/{delegator}/bonding_status/{validator}", + bondingStatusHandlerFn("stake", cdc, ctx), + ).Methods("GET") } // bondingStatusHandlerFn - http request handler to query delegator bonding status @@ -24,7 +26,7 @@ func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreC // read parameters vars := mux.Vars(r) delegator := vars["delegator"] - candidate := vars["candidate"] + validator := vars["validator"] bz, err := hex.DecodeString(delegator) if err != nil { @@ -34,7 +36,7 @@ func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreC } delegatorAddr := sdk.Address(bz) - bz, err = hex.DecodeString(candidate) + bz, err = hex.DecodeString(validator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) @@ -75,41 +77,3 @@ func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreC w.Write(output) } } - -// candidatesHandlerFn - http request handler to query list of candidates -func candidatesHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - res, err := ctx.QuerySubspace(cdc, stake.CandidatesKey, storeName) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("Couldn't query candidates. Error: %s", err.Error()))) - return - } - - if len(res) == 0 { - w.WriteHeader(http.StatusNoContent) - return - } - - candidates := make(stake.Candidates, 0, len(res)) - for _, kv := range res { - var candidate stake.Candidate - err = cdc.UnmarshalBinary(kv.Value, &candidate) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("Couldn't decode candidate. Error: %s", err.Error()))) - return - } - candidates = append(candidates, candidate) - } - - output, err := cdc.MarshalJSON(candidates) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) - return - } - - w.Write(output) - } -} From a9bcdb2a0a96b35e8cfb5bcf1f8425b842f401b6 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Fri, 25 May 2018 00:41:17 +0900 Subject: [PATCH 15/21] Addressed comments --- x/stake/client/rest/query.go | 2 +- x/stake/client/rest/tx.go | 52 +++++++++++++++++++----------------- x/stake/msg.go | 8 +++--- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 02cc732c9..cbcf5f5e8 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -20,7 +20,7 @@ func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec ).Methods("GET") } -// bondingStatusHandlerFn - http request handler to query delegator bonding status +// http request handler to query delegator bonding status func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // read parameters diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 75e0f8d75..2560fcc9f 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -1,6 +1,7 @@ package rest import ( + "bytes" "encoding/json" "io/ioutil" "net/http" @@ -16,33 +17,26 @@ import ( ) func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) { - r.HandleFunc("/stake/bondunbond", bondUnbondRequestHandlerFn(cdc, kb, ctx)).Methods("POST") + r.HandleFunc( + "/stake/delegations", + editDelegationsRequestHandlerFn(cdc, kb, ctx), + ).Methods("POST") } -type bond struct { - Amount sdk.Coin `json:"amount"` - Candidate sdk.Address `json:"candidate"` -} - -type unbond struct { - Shares string `json:"shares"` - Candidate sdk.Address `json:"candidate"` -} - -type bondUnbondBody struct { +type editDelegationsBody struct { // fees is not used currently // Fees sdk.Coin `json="fees"` - LocalAccountName string `json:"name"` - Password string `json:"password"` - ChainID string `json:"chain_id"` - Sequence int64 `json:"sequence"` - Bond []bond `json:"bond"` - Unbond []unbond `json:"unbond"` + LocalAccountName string `json:"name"` + Password string `json:"password"` + ChainID string `json:"chain_id"` + Sequence int64 `json:"sequence"` + Delegate []stake.MsgDelegate `json:"delegate"` + Unbond []stake.MsgUnbond `json:"unbond"` } -func bondUnbondRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { +func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var m bondUnbondBody + var m editDelegationsBody body, err := ioutil.ReadAll(r.Body) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -64,13 +58,21 @@ func bondUnbondRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Co } // build messages - messages := make([]sdk.Msg, 0, len(m.Bond)+len(m.Unbond)) - for _, bond := range m.Bond { - msg := stake.NewMsgDelegate(info.Address(), bond.Candidate, bond.Amount) + messages := make([]sdk.Msg, 0, len(m.Delegate)+len(m.Unbond)) + for _, msg := range m.Delegate { + if !bytes.Equal(info.Address(), msg.DelegatorAddr) { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte("Must use own delegator address")) + return + } messages = append(messages, msg) } - for _, unbond := range m.Unbond { - msg := stake.NewMsgUnbond(info.Address(), unbond.Candidate, unbond.Shares) + for _, msg := range m.Unbond { + if !bytes.Equal(info.Address(), msg.DelegatorAddr) { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte("Must use own delegator address")) + return + } messages = append(messages, msg) } diff --git a/x/stake/msg.go b/x/stake/msg.go index 4bfc496de..2d1757947 100644 --- a/x/stake/msg.go +++ b/x/stake/msg.go @@ -117,8 +117,8 @@ func (msg MsgEditCandidacy) ValidateBasic() sdk.Error { // MsgDelegate - struct for bonding transactions type MsgDelegate struct { - DelegatorAddr sdk.Address `json:"delegator"` - ValidatorAddr sdk.Address `json:"candidate"` + DelegatorAddr sdk.Address `json:"delegator_addr"` + ValidatorAddr sdk.Address `json:"validator_addr"` Bond sdk.Coin `json:"bond"` } @@ -164,8 +164,8 @@ func (msg MsgDelegate) ValidateBasic() sdk.Error { // MsgUnbond - struct for unbonding transactions type MsgUnbond struct { - DelegatorAddr sdk.Address `json:"delegator"` - ValidatorAddr sdk.Address `json:"candidate"` + DelegatorAddr sdk.Address `json:"delegator_addr"` + ValidatorAddr sdk.Address `json:"validator_addr"` Shares string `json:"shares"` } From 57d86cc04c03871622179e96a51da9e5671e7af6 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 25 May 2018 10:17:49 -0400 Subject: [PATCH 16/21] fix many lcd errors, restructure lcd init --- Gopkg.lock | 47 +--------------- client/lcd/lcd_test.go | 110 ++++++++++++++++---------------------- cmd/gaia/app/genesis.go | 44 ++++++++++----- x/stake/genesis.go | 4 +- x/stake/keeper_test.go | 6 +-- x/stake/params.go | 3 +- x/stake/pool.go | 2 +- x/stake/test_common.go | 4 +- x/stake/tick_test.go | 2 +- x/stake/validator_test.go | 2 +- 10 files changed, 89 insertions(+), 135 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index dcc57cab3..37a32820c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -13,51 +13,6 @@ packages = ["btcec"] revision = "1432d294a5b055c297457c25434efbf13384cc46" -[[projects]] - name = "github.com/cosmos/cosmos-sdk" - packages = [ - "baseapp", - "client", - "client/context", - "client/keys", - "client/lcd", - "client/rpc", - "client/tx", - "cmd/gaia/app", - "examples/basecoin/app", - "examples/basecoin/types", - "examples/democoin/app", - "examples/democoin/types", - "examples/democoin/x/cool", - "examples/democoin/x/cool/client/cli", - "examples/democoin/x/pow", - "examples/democoin/x/pow/client/cli", - "examples/democoin/x/simplestake", - "examples/democoin/x/simplestake/client/cli", - "examples/democoin/x/sketchy", - "mock", - "server", - "store", - "tests", - "types", - "version", - "wire", - "x/auth", - "x/auth/client/cli", - "x/auth/client/rest", - "x/bank", - "x/bank/client", - "x/bank/client/cli", - "x/bank/client/rest", - "x/ibc", - "x/ibc/client/cli", - "x/ibc/client/rest", - "x/stake", - "x/stake/client/cli" - ] - revision = "187be1a5df81de1fd71da9053102d3a4868ec979" - version = "v0.17.2" - [[projects]] name = "github.com/davecgh/go-spew" packages = ["spew"] @@ -502,6 +457,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "9b6ee069da61cf1815c332c5624e8af99b51ea72e2e9b91d780db92299598dcc" + inputs-digest = "7540d2ecdb5d7d5084ab4e6132e929bbd501bd6add3006d8f08a6b2c127e0c7d" solver-name = "gps-cdcl" solver-version = 1 diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 7d1dab676..5108279ac 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -36,16 +36,18 @@ import ( gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app" tests "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/stake" ) var ( - coinDenom = "mycoin" + coinDenom = "steak" coinAmount = int64(10000000) stakeDenom = "steak" - candidateAddr1 = "" - candidateAddr2 = "" + validatorAddr1 = "" + validatorAddr2 = "" // XXX bad globals name = "test" @@ -222,6 +224,7 @@ func TestValidators(t *testing.T) { func TestCoinSend(t *testing.T) { // query empty + //res, body := request(t, port, "GET", "/accounts/8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6", nil) res, body := request(t, port, "GET", "/accounts/8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6", nil) require.Equal(t, http.StatusNoContent, res.StatusCode, body) @@ -327,7 +330,7 @@ func TestBond(t *testing.T) { assert.Equal(t, int64(9999900), coins.AmountOf(stakeDenom)) // query candidate - bond := getDelegation(t, sendAddr, candidateAddr1) + bond := getDelegation(t, sendAddr, validatorAddr1) assert.Equal(t, "100/1", bond.Shares.String()) } @@ -347,7 +350,7 @@ func TestUnbond(t *testing.T) { assert.Equal(t, int64(9999911), coins.AmountOf(stakeDenom)) // query candidate - bond := getDelegation(t, sendAddr, candidateAddr1) + bond := getDelegation(t, sendAddr, validatorAddr1) assert.Equal(t, "99/1", bond.Shares.String()) } @@ -366,14 +369,6 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { if err != nil { return nil, nil, err } - var info cryptoKeys.Info - info, seed, err = kb.Create(name, password, cryptoKeys.AlgoEd25519) // XXX global seed - if err != nil { - return nil, nil, err - } - - pubKey := info.PubKey - sendAddr = pubKey.Address().String() // XXX global config := GetConfig() config.Consensus.TimeoutCommit = 1000 @@ -400,59 +395,46 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { Name: "val", }, ) - candidateAddr1 = hex.EncodeToString(genDoc.Validators[0].PubKey.Address()) - candidateAddr2 = hex.EncodeToString(genDoc.Validators[1].PubKey.Address()) - coins := sdk.Coins{ - {coinDenom, coinAmount}, - {stakeDenom, coinAmount}, - } - appState := gapp.GenesisState{ - Accounts: []gapp.GenesisAccount{ - { - Address: pubKey.Address(), - Coins: coins, - }, - }, - StakeData: stake.GenesisState{ - Pool: stake.Pool{ - BondedShares: sdk.NewRat(200, 1), - UnbondedShares: sdk.ZeroRat(), - Inflation: sdk.NewRat(7, 100), - PrevBondedShares: sdk.ZeroRat(), - }, - Params: stake.Params{ - InflationRateChange: sdk.NewRat(13, 100), - InflationMax: sdk.NewRat(1, 5), - InflationMin: sdk.NewRat(7, 100), - GoalBonded: sdk.NewRat(67, 100), - MaxValidators: 100, - BondDenom: stakeDenom, - }, - Validators: []stake.Validator{ - { - Owner: genDoc.Validators[0].PubKey.Address(), - PubKey: genDoc.Validators[0].PubKey, - Description: stake.Description{ - Moniker: "validator1", - }, - }, - { - Owner: genDoc.Validators[1].PubKey.Address(), - PubKey: genDoc.Validators[1].PubKey, - Description: stake.Description{ - Moniker: "validator2", - }, - }, - }, - }, - } + pk1 := genDoc.Validators[0].PubKey + pk2 := genDoc.Validators[1].PubKey + validatorAddr1 = hex.EncodeToString(pk1.Address()) + validatorAddr2 = hex.EncodeToString(pk2.Address()) - stateBytes, err := cdc.MarshalJSONIndent(appState, "", " ") + // NOTE it's bad practice to reuse pk address for the owner address but doing in the + // test for simplicity + var appGenTxs [2]json.RawMessage + appGenTxs[0], _, _, err = gapp.GaiaAppGenTxNF(cdc, pk1, pk1.Address(), "test_val1", true) if err != nil { return nil, nil, err } - genDoc.AppStateJSON = stateBytes + appGenTxs[1], _, _, err = gapp.GaiaAppGenTxNF(cdc, pk2, pk2.Address(), "test_val2", true) + if err != nil { + return nil, nil, err + } + + genesisState, err := gapp.GaiaAppGenState(cdc, appGenTxs[:]) + if err != nil { + return nil, nil, err + } + + // add the sendAddr to genesis + var info cryptoKeys.Info + info, seed, err = kb.Create(name, password, cryptoKeys.AlgoEd25519) // XXX global seed + if err != nil { + return nil, nil, err + } + sendAddr = info.PubKey.Address().String() // XXX global + accAuth := auth.NewBaseAccountWithAddress(info.PubKey.Address()) + accAuth.Coins = sdk.Coins{{"steak", 100}} + acc := gapp.NewGenesisAccount(&accAuth) + genesisState.Accounts = append(genesisState.Accounts, acc) + + appState, err := wire.MarshalJSONIndent(cdc, genesisState) + if err != nil { + return nil, nil, err + } + genDoc.AppStateJSON = appState // LCD listen address port = fmt.Sprintf("%d", 17377) // XXX @@ -609,7 +591,7 @@ func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxC } ], "unbond": [] - }`, name, password, sequence, candidateAddr1, stakeDenom)) + }`, name, password, sequence, validatorAddr1, stakeDenom)) res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -637,7 +619,7 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT "shares": "1" } ] - }`, name, password, sequence, candidateAddr1)) + }`, name, password, sequence, validatorAddr1)) res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -674,7 +656,7 @@ func doMultiBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadca "shares": "1" } ] - }`, name, password, sequence, candidateAddr1, stakeDenom, candidateAddr2, stakeDenom, candidateAddr1)) + }`, name, password, sequence, validatorAddr1, stakeDenom, validatorAddr2, stakeDenom, validatorAddr1)) res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 525fe8ab0..64db33543 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -74,7 +74,7 @@ func GaiaAppInit() server.AppInit { FlagsAppGenState: fsAppGenState, FlagsAppGenTx: fsAppGenTx, AppGenTx: GaiaAppGenTx, - AppGenState: GaiaAppGenState, + AppGenState: GaiaAppGenStateJSON, } } @@ -85,19 +85,31 @@ type GaiaGenTx struct { PubKey crypto.PubKey `json:"pub_key"` } -// Generate a gaia genesis transaction +// Generate a gaia genesis transaction with flags func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { - - var addr sdk.Address - var secret string clientRoot := viper.GetString(flagClientHome) overwrite := viper.GetBool(flagOWK) name := viper.GetString(flagName) + var addr sdk.Address + var secret string addr, secret, err = server.GenerateSaveCoinKey(clientRoot, name, "1234567890", overwrite) if err != nil { return } + mm := map[string]string{"secret": secret} + var bz []byte + bz, err = cdc.MarshalJSON(mm) + if err != nil { + return + } + cliPrint = json.RawMessage(bz) + return GaiaAppGenTxNF(cdc, pk, addr, name, overwrite) +} + +// Generate a gaia genesis transaction without flags +func GaiaAppGenTxNF(cdc *wire.Codec, pk crypto.PubKey, addr sdk.Address, name string, overwrite bool) ( + appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { var bz []byte gaiaGenTx := GaiaGenTx{ @@ -111,13 +123,6 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( } appGenTx = json.RawMessage(bz) - mm := map[string]string{"secret": secret} - bz, err = cdc.MarshalJSON(mm) - if err != nil { - return - } - cliPrint = json.RawMessage(bz) - validator = tmtypes.GenesisValidator{ PubKey: pk, Power: freeFermionVal, @@ -127,7 +132,7 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( // Create the core parameters for genesis initialization for gaia // note that the pubkey input is this machines pubkey -func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { +func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState GenesisState, err error) { if len(appGenTxs) == 0 { err = errors.New("must provide at least genesis transaction") @@ -171,10 +176,21 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso } // create the final app state - genesisState := GenesisState{ + genesisState = GenesisState{ Accounts: genaccs, StakeData: stakeData, } + return +} + +// GaiaAppGenState but with JSON +func GaiaAppGenStateJSON(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { + + // create the final app state + genesisState, err := GaiaAppGenState(cdc, appGenTxs) + if err != nil { + return nil, err + } appState, err = wire.MarshalJSONIndent(cdc, genesisState) return } diff --git a/x/stake/genesis.go b/x/stake/genesis.go index d45adc3d7..be8d0dbe4 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -22,8 +22,8 @@ func NewGenesisState(pool Pool, params Params, validators []Validator, bonds []D // get raw genesis raw message for testing func DefaultGenesisState() GenesisState { return GenesisState{ - Pool: initialPool(), - Params: defaultParams(), + Pool: InitialPool(), + Params: DefaultParams(), } } diff --git a/x/stake/keeper_test.go b/x/stake/keeper_test.go index f28a2cf68..01d4434e8 100644 --- a/x/stake/keeper_test.go +++ b/x/stake/keeper_test.go @@ -586,7 +586,7 @@ func TestGetTendermintUpdatesInserted(t *testing.T) { func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) - params := defaultParams() + params := DefaultParams() params.MaxValidators = 2 keeper.setParams(ctx, params) @@ -721,7 +721,7 @@ func TestBond(t *testing.T) { func TestParams(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) - expParams := defaultParams() + expParams := DefaultParams() //check that the empty keeper loads the default resParams := keeper.GetParams(ctx) @@ -736,7 +736,7 @@ func TestParams(t *testing.T) { func TestPool(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) - expPool := initialPool() + expPool := InitialPool() //check that the empty keeper loads the default resPool := keeper.GetPool(ctx) diff --git a/x/stake/params.go b/x/stake/params.go index 32b8c0ae8..ace39935c 100644 --- a/x/stake/params.go +++ b/x/stake/params.go @@ -23,7 +23,8 @@ func (p Params) equal(p2 Params) bool { return bytes.Equal(bz1, bz2) } -func defaultParams() Params { +// default params +func DefaultParams() Params { return Params{ InflationRateChange: sdk.NewRat(13, 100), InflationMax: sdk.NewRat(20, 100), diff --git a/x/stake/pool.go b/x/stake/pool.go index e2547b050..0b320432e 100644 --- a/x/stake/pool.go +++ b/x/stake/pool.go @@ -31,7 +31,7 @@ func (p Pool) equal(p2 Pool) bool { } // initial pool for testing -func initialPool() Pool { +func InitialPool() Pool { return Pool{ LooseUnbondedTokens: 0, BondedTokens: 0, diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 2dac36069..a0aca4a57 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -111,8 +111,8 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context ) ck := bank.NewKeeper(accountMapper) keeper := NewKeeper(cdc, keyStake, ck, DefaultCodespace) - keeper.setPool(ctx, initialPool()) - keeper.setNewParams(ctx, defaultParams()) + keeper.setPool(ctx, InitialPool()) + keeper.setNewParams(ctx, DefaultParams()) // fill all the addresses with some coins for _, addr := range addrs { diff --git a/x/stake/tick_test.go b/x/stake/tick_test.go index 4f0f6dc06..438b678f1 100644 --- a/x/stake/tick_test.go +++ b/x/stake/tick_test.go @@ -61,7 +61,7 @@ func TestGetInflation(t *testing.T) { func TestProcessProvisions(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) - params := defaultParams() + params := DefaultParams() params.MaxValidators = 2 keeper.setParams(ctx, params) pool := keeper.GetPool(ctx) diff --git a/x/stake/validator_test.go b/x/stake/validator_test.go index 1ca5ba2f7..db6ab6f4c 100644 --- a/x/stake/validator_test.go +++ b/x/stake/validator_test.go @@ -169,7 +169,7 @@ func randomValidator(r *rand.Rand) Validator { // generate a random staking state func randomSetup(r *rand.Rand, numValidators int) (Pool, Validators) { - pool := initialPool() + pool := InitialPool() validators := make([]Validator, numValidators) for i := 0; i < numValidators; i++ { From cfa1d42292344f4ca6f034acb17ae104ff939936 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Sat, 26 May 2018 17:37:39 +0900 Subject: [PATCH 17/21] Fixed LCD staking tests --- client/lcd/lcd_test.go | 44 +++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 5108279ac..d2b6d7d4e 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -45,7 +45,6 @@ var ( coinDenom = "steak" coinAmount = int64(10000000) - stakeDenom = "steak" validatorAddr1 = "" validatorAddr2 = "" @@ -327,11 +326,11 @@ func TestBond(t *testing.T) { // query sender acc := getAccount(t, sendAddr) coins := acc.GetCoins() - assert.Equal(t, int64(9999900), coins.AmountOf(stakeDenom)) + assert.Equal(t, int64(87), coins.AmountOf(coinDenom)) // query candidate bond := getDelegation(t, sendAddr, validatorAddr1) - assert.Equal(t, "100/1", bond.Shares.String()) + assert.Equal(t, "10/1", bond.Shares.String()) } func TestUnbond(t *testing.T) { @@ -347,11 +346,11 @@ func TestUnbond(t *testing.T) { // query sender acc := getAccount(t, sendAddr) coins := acc.GetCoins() - assert.Equal(t, int64(9999911), coins.AmountOf(stakeDenom)) + assert.Equal(t, int64(98), coins.AmountOf(coinDenom)) // query candidate bond := getDelegation(t, sendAddr, validatorAddr1) - assert.Equal(t, "99/1", bond.Shares.String()) + assert.Equal(t, "9/1", bond.Shares.String()) } //__________________________________________________________ @@ -584,15 +583,16 @@ func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxC "name": "%s", "password": "%s", "sequence": %d, - "bond": [ + "delegate": [ { - "candidate": "%s", - "amount": { "denom": "%s", "amount": 100 } + "delegator_addr": "%x", + "validator_addr": "%s", + "bond": { "denom": "%s", "amount": 10 } } ], "unbond": [] - }`, name, password, sequence, validatorAddr1, stakeDenom)) - res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) + }`, name, password, sequence, acc.GetAddress(), validatorAddr1, coinDenom)) + res, body := request(t, port, "POST", "/stake/delegations", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) var results []ctypes.ResultBroadcastTxCommit @@ -615,12 +615,13 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT "bond": [], "unbond": [ { - "candidate": "%s", + "delegator_addr": "%x", + "validator_addr": "%s", "shares": "1" } ] - }`, name, password, sequence, validatorAddr1)) - res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) + }`, name, password, sequence, acc.GetAddress(), validatorAddr1)) + res, body := request(t, port, "POST", "/stake/delegations", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) var results []ctypes.ResultBroadcastTxCommit @@ -642,22 +643,25 @@ func doMultiBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadca "sequence": %d, "bond": [ { - "candidate": "%s", - "amount": { "denom": "%s", "amount": 1 } + "delegator_addr": "%x", + "validator_addr": "%s", + "bond": { "denom": "%s", "amount": 1 } }, { - "candidate": "%s", - "amount": { "denom": "%s", "amount": 1 } + "delegator_addr": "%x", + "validator_addr": "%s", + "bond": { "denom": "%s", "amount": 1 } }, ], "unbond": [ { - "candidate": "%s", + "delegator_addr": "%x", + "validator_addr": "%s", "shares": "1" } ] - }`, name, password, sequence, validatorAddr1, stakeDenom, validatorAddr2, stakeDenom, validatorAddr1)) - res, body := request(t, port, "POST", "/stake/bondunbond", jsonStr) + }`, name, password, sequence, acc.GetAddress(), validatorAddr1, coinDenom, acc.GetAddress(), validatorAddr2, coinDenom, acc.GetAddress(), validatorAddr1)) + res, body := request(t, port, "POST", "/stake/delegations", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) var results []ctypes.ResultBroadcastTxCommit From 99e5c5a18ff056f392462e3924a19bceeb71ffaf Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 29 May 2018 15:07:03 +0900 Subject: [PATCH 18/21] Restored validators query endpoint --- client/lcd/lcd_test.go | 47 +++++++++--------------------------- x/stake/client/rest/query.go | 43 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 35 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 0959a29c7..6c5bcfd71 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -313,6 +313,13 @@ func TestTxs(t *testing.T) { // assert.NotEqual(t, "[]", body) } +func TestValidatorsQuery(t *testing.T) { + validators := getValidators(t) + assert.Equal(t, len(validators), 2) + assert.Equal(t, hex.EncodeToString(validators[0].Owner), validatorAddr1) + assert.Equal(t, hex.EncodeToString(validators[1].Owner), validatorAddr2) +} + func TestBond(t *testing.T) { // create bond TX @@ -631,42 +638,12 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT return results[0] } -func doMultiBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) { +func getValidators(t *testing.T) []stake.Validator { // get the account to get the sequence - acc := getAccount(t, sendAddr) - sequence := acc.GetSequence() - - // send - jsonStr := []byte(fmt.Sprintf(`{ - "name": "%s", - "password": "%s", - "sequence": %d, - "bond": [ - { - "delegator_addr": "%x", - "validator_addr": "%s", - "bond": { "denom": "%s", "amount": 1 } - }, - { - "delegator_addr": "%x", - "validator_addr": "%s", - "bond": { "denom": "%s", "amount": 1 } - }, - ], - "unbond": [ - { - "delegator_addr": "%x", - "validator_addr": "%s", - "shares": "1" - } - ] - }`, name, password, sequence, acc.GetAddress(), validatorAddr1, coinDenom, acc.GetAddress(), validatorAddr2, coinDenom, acc.GetAddress(), validatorAddr1)) - res, body := request(t, port, "POST", "/stake/delegations", jsonStr) + res, body := request(t, port, "GET", "/stake/validators", nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - - var results []ctypes.ResultBroadcastTxCommit - err := cdc.UnmarshalJSON([]byte(body), &results) + var validators stake.Validators + err := cdc.UnmarshalJSON([]byte(body), &validators) require.Nil(t, err) - - return results[0] + return validators } diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index cbcf5f5e8..0388467c4 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -18,6 +18,10 @@ func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec "/stake/{delegator}/bonding_status/{validator}", bondingStatusHandlerFn("stake", cdc, ctx), ).Methods("GET") + r.HandleFunc( + "/stake/validators", + validatorsHandlerFn("stake", cdc, ctx), + ).Methods("GET") } // http request handler to query delegator bonding status @@ -77,3 +81,42 @@ func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreC w.Write(output) } } + +// http request handler to query list of validators +func validatorsHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + res, 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(res) == 0 { + w.WriteHeader(http.StatusNoContent) + return + } + + validators := make(stake.Validators, 0, len(res)) + for _, kv := range res { + var validator stake.Validator + err = cdc.UnmarshalBinary(kv.Value, &validator) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) + return + } + validators = append(validators, validator) + } + + output, err := cdc.MarshalJSON(validators) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + + w.Write(output) + } +} From 52cd8b8c1fe25dacb6910b84189755bd5bad4a7b Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 30 May 2018 07:42:59 -0700 Subject: [PATCH 19/21] fix endPath missing bug for query --- client/context/helpers.go | 2 +- client/lcd/lcd_test.go | 4 ++-- x/stake/client/cli/query.go | 12 ++++++------ x/stake/client/rest/query.go | 4 +++- x/stake/client/rest/tx.go | 2 -- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/client/context/helpers.go b/client/context/helpers.go index f4686befd..f47cc7ff4 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -59,7 +59,7 @@ func (ctx CoreContext) QuerySubspace(cdc *wire.Codec, subspace []byte, storeName // Query from Tendermint with the provided storename and path func (ctx CoreContext) query(key cmn.HexBytes, storeName, endPath string) (res []byte, err error) { - path := fmt.Sprintf("/store/%s/key", storeName) + path := fmt.Sprintf("/store/%s/%s", storeName, endPath) node, err := ctx.GetNode() if err != nil { return res, err diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 6c5bcfd71..289075bc9 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -454,7 +454,7 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { if err != nil { return nil, nil, err } - lcd, err := startLCD(logger, listenAddr) + lcd, err := startLCD(logger, listenAddr, cdc) if err != nil { return nil, nil, err } @@ -493,7 +493,7 @@ func startTM(cfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, p } // start the LCD. note this blocks! -func startLCD(logger log.Logger, listenAddr string) (net.Listener, error) { +func startLCD(logger log.Logger, listenAddr string, cdc *wire.Codec) (net.Listener, error) { handler := createHandler(cdc) return tmrpc.StartHTTPServer(listenAddr, handler, logger) } diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index 079dd003d..26b508e0d 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -62,15 +62,15 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command { return err } - // parse out the candidates - var candidates []stake.Validator + // parse out the validators + var validators []stake.Validator for _, KV := range resKVs { var validator stake.Validator cdc.MustUnmarshalBinary(KV.Value, &validator) - candidates = append(candidates, validator) + validators = append(validators, validator) } - output, err := wire.MarshalJSONIndent(cdc, candidates) + output, err := wire.MarshalJSONIndent(cdc, validators) if err != nil { return err } @@ -127,7 +127,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { return cmd } -// get the command to query all the candidates bonded to a delegation +// get the command to query all the validators bonded to a delegation func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "delegations [delegator-addr]", @@ -146,7 +146,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command { return err } - // parse out the candidates + // parse out the validators var delegations []stake.Delegation for _, KV := range resKVs { var delegation stake.Delegation diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 0388467c4..1eda2ac53 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -27,6 +27,7 @@ func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec // http request handler to query delegator bonding status func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { + // read parameters vars := mux.Vars(r) delegator := vars["delegator"] @@ -98,7 +99,8 @@ func validatorsHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreCont return } - validators := make(stake.Validators, 0, len(res)) + // parse out the validators + var validators []stake.Validator for _, kv := range res { var validator stake.Validator err = cdc.UnmarshalBinary(kv.Value, &validator) diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 2560fcc9f..2718b3876 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -24,8 +24,6 @@ func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, k } type editDelegationsBody struct { - // fees is not used currently - // Fees sdk.Coin `json="fees"` LocalAccountName string `json:"name"` Password string `json:"password"` ChainID string `json:"chain_id"` From 6207d4131c131bd6e1e662e80bf9c0b92883129c Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 30 May 2018 08:16:09 -0700 Subject: [PATCH 20/21] minor fixes --- x/stake/client/rest/query.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 1eda2ac53..41b0fa085 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -16,16 +16,16 @@ import ( func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) { r.HandleFunc( "/stake/{delegator}/bonding_status/{validator}", - bondingStatusHandlerFn("stake", cdc, ctx), + bondingStatusHandlerFn(ctx, "stake", cdc), ).Methods("GET") r.HandleFunc( "/stake/validators", - validatorsHandlerFn("stake", cdc, ctx), + validatorsHandlerFn(ctx, "stake", cdc), ).Methods("GET") } // http request handler to query delegator bonding status -func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { +func bondingStatusHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // read parameters @@ -84,9 +84,9 @@ func bondingStatusHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreC } // http request handler to query list of validators -func validatorsHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { +func validatorsHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - res, err := ctx.QuerySubspace(cdc, stake.ValidatorsKey, storeName) + 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()))) @@ -94,14 +94,14 @@ func validatorsHandlerFn(storeName string, cdc *wire.Codec, ctx context.CoreCont } // the query will return empty if there are no validators - if len(res) == 0 { + if len(kvs) == 0 { w.WriteHeader(http.StatusNoContent) return } // parse out the validators var validators []stake.Validator - for _, kv := range res { + for _, kv := range kvs { var validator stake.Validator err = cdc.UnmarshalBinary(kv.Value, &validator) if err != nil { From ecf800810c338767a4e804401faae17ad2b556f1 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 30 May 2018 09:00:00 -0700 Subject: [PATCH 21/21] remove append usage from lcd, fix address order test issue in lcd --- client/lcd/lcd_test.go | 14 ++++++++++++-- x/stake/client/rest/query.go | 6 +++--- x/stake/client/rest/tx.go | 23 +++++++++++++---------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index c8d493d1f..8c6530dec 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -319,8 +319,18 @@ func TestTxs(t *testing.T) { func TestValidatorsQuery(t *testing.T) { validators := getValidators(t) assert.Equal(t, len(validators), 2) - assert.Equal(t, hex.EncodeToString(validators[0].Owner), validatorAddr1) - assert.Equal(t, hex.EncodeToString(validators[1].Owner), validatorAddr2) + + // make sure all the validators were found (order unknown because sorted by owner addr) + foundVal1, foundVal2 := false, false + res1, res2 := hex.EncodeToString(validators[0].Owner), hex.EncodeToString(validators[1].Owner) + if res1 == validatorAddr1 || res2 == validatorAddr1 { + foundVal1 = true + } + if res1 == validatorAddr2 || res2 == validatorAddr2 { + foundVal2 = true + } + assert.True(t, foundVal1, "validatorAddr1 %v, res1 %v, res2 %v", validatorAddr1, res1, res2) + assert.True(t, foundVal2, "validatorAddr2 %v, res1 %v, res2 %v", validatorAddr2, res1, res2) } func TestBond(t *testing.T) { diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 41b0fa085..3e439c2b4 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -100,8 +100,8 @@ func validatorsHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Co } // parse out the validators - var validators []stake.Validator - for _, kv := range kvs { + validators := make([]stake.Validator, len(kvs)) + for i, kv := range kvs { var validator stake.Validator err = cdc.UnmarshalBinary(kv.Value, &validator) if err != nil { @@ -109,7 +109,7 @@ func validatorsHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Co w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - validators = append(validators, validator) + validators[i] = validator } output, err := cdc.MarshalJSON(validators) diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 2718b3876..eaf206bf6 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -56,14 +56,16 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte } // build messages - messages := make([]sdk.Msg, 0, len(m.Delegate)+len(m.Unbond)) + messages := make([]sdk.Msg, len(m.Delegate)+len(m.Unbond)) + i := 0 for _, msg := range m.Delegate { if !bytes.Equal(info.Address(), msg.DelegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return } - messages = append(messages, msg) + messages[i] = msg + i++ } for _, msg := range m.Unbond { if !bytes.Equal(info.Address(), msg.DelegatorAddr) { @@ -71,12 +73,13 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte w.Write([]byte("Must use own delegator address")) return } - messages = append(messages, msg) + messages[i] = msg + i++ } // sign messages - signedTxs := make([][]byte, 0, len(messages)) - for _, msg := range messages { + signedTxs := make([][]byte, len(messages[:])) + for i, msg := range messages { // increment sequence for each message ctx = ctx.WithSequence(m.Sequence) m.Sequence++ @@ -88,24 +91,24 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte return } - signedTxs = append(signedTxs, txBytes) + signedTxs[i] = txBytes } // send // XXX the operation might not be atomic if a tx fails // should we have a sdk.MultiMsg type to make sending atomic? - results := make([]*ctypes.ResultBroadcastTxCommit, 0, len(signedTxs)) - for _, txBytes := range signedTxs { + results := make([]*ctypes.ResultBroadcastTxCommit, len(signedTxs[:])) + for i, txBytes := range signedTxs { res, err := ctx.BroadcastTx(txBytes) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) return } - results = append(results, res) + results[i] = res } - output, err := json.MarshalIndent(results, "", " ") + output, err := json.MarshalIndent(results[:], "", " ") if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error()))