From 8f4234b44dc607284a6cfcb9ea386297c5a6e3a6 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 22 May 2018 10:40:04 +0200 Subject: [PATCH 001/128] Require --name on init gen-tx --- cmd/gaia/app/genesis.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 7cb7564dd3..b70ac17a1a 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -65,7 +65,7 @@ func GaiaAppInit() server.AppInit { fsAppGenState := pflag.NewFlagSet("", pflag.ContinueOnError) fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError) - fsAppGenTx.String(flagName, "", "validator moniker, if left blank, do not add validator") + fsAppGenTx.String(flagName, "", "validator moniker, required") fsAppGenTx.String(flagClientHome, DefaultCLIHome, "home directory for the client, used for key generation") fsAppGenTx.Bool(flagOWK, false, "overwrite the accounts created") @@ -94,6 +94,9 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( clientRoot := viper.GetString(flagClientHome) overwrite := viper.GetBool(flagOWK) name := viper.GetString(flagName) + if name == "" { + return nil, nil, tmtypes.GenesisValidator{}, errors.New("Must specify --name (validator moniker)") + } addr, secret, err = server.GenerateSaveCoinKey(clientRoot, name, "1234567890", overwrite) if err != nil { return From efd1a3ac44f09dcc8e8622951080948424efebac Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 14 May 2018 16:03:03 -0700 Subject: [PATCH 002/128] 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 e17d152a5f..9e9a369ffb 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 003/128] 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 6093902934..4a4b83901e 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 0000000000..32d56f42c5 --- /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 0000000000..75e0f8d75d --- /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 004/128] 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 0adff84d9b..4bfc496dee 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 005/128] 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 a7be5079bf..df8be897c3 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 006/128] 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 4a4b83901e..700a65f2b9 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 007/128] 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 66a8a4085f..d78e7655c8 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 008/128] 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 d78e7655c8..9406d7ce9c 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 009/128] 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 9406d7ce9c..263d75c25e 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 010/128] 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 700a65f2b9..576bad3cc9 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 32d56f42c5..1f3a2957d5 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 011/128] 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 263d75c25e..5ed6ddcc9c 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 012/128] Updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a9eeb71f3..89b7ec744b 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 013/128] 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 5ed6ddcc9c..157a386811 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 014/128] 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 157a386811..578490ca13 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 576bad3cc9..4decfdbfd8 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 015/128] 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 578490ca13..7d1dab6762 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 4decfdbfd8..02cc732c9d 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 016/128] 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 02cc732c9d..cbcf5f5e8e 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 75e0f8d75d..2560fcc9f0 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 4bfc496dee..2d1757947e 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 017/128] 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 dcc57cab33..37a32820c2 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 7d1dab6762..5108279ac0 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 525fe8ab07..64db335435 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 d45adc3d7f..be8d0dbe44 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 f28a2cf684..01d4434e83 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 32b8c0ae83..ace39935c3 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 e2547b0503..0b320432ed 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 2dac36069e..a0aca4a57c 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 4f0f6dc061..438b678f1d 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 1ca5ba2f75..db6ab6f4c7 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 018/128] 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 5108279ac0..d2b6d7d4e8 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 2d8756385663b840bd30ee2c73978b807e32b59e Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Mon, 28 May 2018 11:26:43 -0700 Subject: [PATCH 019/128] Change to go-wire UnmarshalJSON for bank transactions The bank module now uses it's own codec to encode and decode Bank Msgs into JSON. --- CHANGELOG.md | 11 +++++++++++ x/bank/msgs.go | 8 ++++---- x/bank/msgs_test.go | 18 ++++++++++++++++-- x/bank/wire.go | 6 ++++++ 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index faacc6e341..f2f68824ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## Pending + +BREAKING CHANGES + +FEATURES + +IMPROVEMENTS +* bank module uses go-wire codec instead of 'encoding/json' + +FIXES + ## 0.18.1 BREAKING CHANGES diff --git a/x/bank/msgs.go b/x/bank/msgs.go index de7f2a8b15..c256b6de61 100644 --- a/x/bank/msgs.go +++ b/x/bank/msgs.go @@ -1,8 +1,6 @@ package bank import ( - "encoding/json" - sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -55,7 +53,8 @@ func (msg MsgSend) ValidateBasic() sdk.Error { // Implements Msg. func (msg MsgSend) GetSignBytes() []byte { - b, err := json.Marshal(msg) // XXX: ensure some canonical form + cdc := getCodec() + b, err := cdc.MarshalJSON(msg) // XXX: ensure some canonical form if err != nil { panic(err) } @@ -104,7 +103,8 @@ func (msg MsgIssue) ValidateBasic() sdk.Error { // Implements Msg. func (msg MsgIssue) GetSignBytes() []byte { - b, err := json.Marshal(msg) // XXX: ensure some canonical form + cdc := getCodec() + b, err := cdc.MarshalJSON(msg) // XXX: ensure some canonical form if err != nil { panic(err) } diff --git a/x/bank/msgs_test.go b/x/bank/msgs_test.go index 78de01f400..fd1992e3c9 100644 --- a/x/bank/msgs_test.go +++ b/x/bank/msgs_test.go @@ -186,8 +186,15 @@ func TestMsgSendGetSignBytes(t *testing.T) { Outputs: []Output{NewOutput(addr2, coins)}, } res := msg.GetSignBytes() + + cdc := getCodec() + unmarshaledMsg := &MsgSend{} + cdc.UnmarshalJSON(res, unmarshaledMsg) + assert.Equal(t, &msg, unmarshaledMsg) + // TODO bad results - assert.Equal(t, string(res), `{"inputs":[{"address":"696E707574","coins":[{"denom":"atom","amount":10}]}],"outputs":[{"address":"6F7574707574","coins":[{"denom":"atom","amount":10}]}]}`) + expected := `{"type":"EAFDE32A2C87F8","value":{"inputs":[{"address":"696E707574","coins":[{"denom":"atom","amount":10}]}],"outputs":[{"address":"6F7574707574","coins":[{"denom":"atom","amount":10}]}]}}` + assert.Equal(t, expected, string(res)) } func TestMsgSendGetSigners(t *testing.T) { @@ -255,8 +262,15 @@ func TestMsgIssueGetSignBytes(t *testing.T) { Outputs: []Output{NewOutput(addr, coins)}, } res := msg.GetSignBytes() + + cdc := getCodec() + unmarshaledMsg := &MsgIssue{} + cdc.UnmarshalJSON(res, unmarshaledMsg) + assert.Equal(t, &msg, unmarshaledMsg) + // TODO bad results - assert.Equal(t, string(res), `{"banker":"696E707574","outputs":[{"address":"6C6F616E2D66726F6D2D62616E6B","coins":[{"denom":"atom","amount":10}]}]}`) + expected := `{"type":"72E617C06ABAD0","value":{"banker":"696E707574","outputs":[{"address":"6C6F616E2D66726F6D2D62616E6B","coins":[{"denom":"atom","amount":10}]}]}}` + assert.Equal(t, expected, string(res)) } func TestMsgIssueGetSigners(t *testing.T) { diff --git a/x/bank/wire.go b/x/bank/wire.go index fdb6c252b5..49511ef0e5 100644 --- a/x/bank/wire.go +++ b/x/bank/wire.go @@ -9,3 +9,9 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(MsgSend{}, "cosmos-sdk/Send", nil) cdc.RegisterConcrete(MsgIssue{}, "cosmos-sdk/Issue", nil) } + +func getCodec() *wire.Codec { + cdc := wire.NewCodec() + RegisterWire(cdc) + return cdc +} From 95c5baf449b28a55f0b3c6cbcae086a70797e95a Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 23 May 2018 22:25:56 +0200 Subject: [PATCH 020/128] Rebase & squash slashing --- Gopkg.lock | 32 ++-- Gopkg.toml | 9 +- baseapp/baseapp.go | 18 ++- baseapp/baseapp_test.go | 2 +- cmd/gaia/app/app.go | 29 ++-- docs/spec/staking/old/spec.md | 12 +- docs/spec/staking/old/spec2.md | 18 +-- docs/spec/staking/transactions.md | 4 +- docs/spec/staking/valset-changes.md | 70 +++++---- examples/basecoin/app/app.go | 2 +- examples/democoin/app/app.go | 2 +- examples/democoin/x/cool/keeper_test.go | 2 +- examples/democoin/x/pow/handler_test.go | 2 +- examples/democoin/x/pow/keeper_test.go | 2 +- .../democoin/x/simplestake/keeper_test.go | 4 +- mock/app.go | 2 +- mock/app_test.go | 2 +- types/context.go | 12 +- types/context_test.go | 4 +- types/lib/mapper_test.go | 2 +- types/stake.go | 13 +- types/tags.go | 5 + x/auth/ante_test.go | 10 +- x/auth/context_test.go | 4 +- x/auth/mapper_test.go | 2 +- x/bank/keeper_test.go | 6 +- x/ibc/ibc_test.go | 2 +- x/slashing/errors.go | 32 ++++ x/slashing/keeper.go | 148 ++++++++++++++++++ x/slashing/keeper_test.go | 17 ++ x/slashing/tick.go | 44 ++++++ x/stake/test_common.go | 2 +- x/stake/validator.go | 6 + 33 files changed, 400 insertions(+), 121 deletions(-) create mode 100644 x/slashing/errors.go create mode 100644 x/slashing/keeper.go create mode 100644 x/slashing/keeper_test.go create mode 100644 x/slashing/tick.go diff --git a/Gopkg.lock b/Gopkg.lock index 37a32820c2..7f1f6185e6 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -253,6 +253,7 @@ revision = "e6d6b529196422703d54ff5c40e79809ec2020b3" [[projects]] + branch = "cwgoes/timestamp-in-evidence" name = "github.com/tendermint/abci" packages = [ "client", @@ -261,8 +262,7 @@ "server", "types" ] - revision = "78a8905690ef54f9d57e3b2b0ee7ad3a04ef3f1f" - version = "v0.10.3" + revision = "e196dacf804e3a4ab74252c27e99cb17b39bf501" [[projects]] branch = "master" @@ -293,18 +293,16 @@ version = "v0.6.2" [[projects]] - name = "github.com/tendermint/go-wire" - packages = ["."] - revision = "fa721242b042ecd4c6ed1a934ee740db4f74e45c" - version = "v0.7.3" - -[[projects]] + branch = "develop" name = "github.com/tendermint/iavl" - packages = ["."] - revision = "fd37a0fa3a7454423233bc3d5ea828f38e0af787" - version = "v0.7.0" + packages = [ + ".", + "sha256truncated" + ] + revision = "9b6f9c3f49d599cfcf43f1a56c3c22882d1f9f21" [[projects]] + branch = "cwgoes/update-abci" name = "github.com/tendermint/tendermint" packages = [ "blockchain", @@ -313,6 +311,9 @@ "consensus", "consensus/types", "evidence", + "libs/events", + "libs/pubsub", + "libs/pubsub/query", "lite", "lite/client", "lite/errors", @@ -341,8 +342,7 @@ "types/priv_validator", "version" ] - revision = "018e096748bafe1d2d1e69b909e4158f3b26f6b2" - version = "v0.19.5-rc1" + revision = "d3093426f455c4b33cee818e3bbf2d2b83e4b38d" [[projects]] name = "github.com/tendermint/tmlibs" @@ -355,9 +355,7 @@ "db", "flowrate", "log", - "merkle", - "pubsub", - "pubsub/query" + "merkle" ] revision = "cc5f287c4798ffe88c04d02df219ecb6932080fd" version = "v0.8.3-rc0" @@ -457,6 +455,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "7540d2ecdb5d7d5084ab4e6132e929bbd501bd6add3006d8f08a6b2c127e0c7d" + inputs-digest = "2bb789b91c383e3a861979c83e61f5f8fd71ea5661837c092353aaacf3091de1" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 5480bc03fc..05b01bfaef 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -52,9 +52,9 @@ name = "github.com/stretchr/testify" version = "~1.2.1" -[[constraint]] +[[override]] name = "github.com/tendermint/abci" - version = "~0.10.3" + branch = "cwgoes/timestamp-in-evidence" [[constraint]] name = "github.com/tendermint/go-crypto" @@ -70,11 +70,11 @@ [[constraint]] name = "github.com/tendermint/iavl" - version = "~0.7.0" + branch = "develop" [[constraint]] name = "github.com/tendermint/tendermint" - version = "0.19.5-rc1" + branch = "cwgoes/update-abci" [[override]] name = "github.com/tendermint/tmlibs" @@ -88,4 +88,3 @@ [prune] go-tests = true unused-packages = true - diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 4ce8a05d9b..baed1fb47d 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -65,9 +65,10 @@ type BaseApp struct { // See methods setCheckState and setDeliverState. // .valUpdates accumulate in DeliverTx and are reset in BeginBlock. // QUESTION: should we put valUpdates in the deliverState.ctx? - checkState *state // for CheckTx - deliverState *state // for DeliverTx - valUpdates []abci.Validator // cached validator changes from DeliverTx + checkState *state // for CheckTx + deliverState *state // for DeliverTx + valUpdates []abci.Validator // cached validator changes from DeliverTx + absentValidators [][]byte // absent validators from begin block } var _ abci.Application = (*BaseApp)(nil) @@ -234,9 +235,9 @@ func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error { // NewContext returns a new Context with the correct store, the given header, and nil txBytes. func (app *BaseApp) NewContext(isCheckTx bool, header abci.Header) sdk.Context { if isCheckTx { - return sdk.NewContext(app.checkState.ms, header, true, nil, app.Logger) + return sdk.NewContext(app.checkState.ms, header, true, nil, app.Logger, nil) } - return sdk.NewContext(app.deliverState.ms, header, false, nil, app.Logger) + return sdk.NewContext(app.deliverState.ms, header, false, nil, app.Logger, nil) } type state struct { @@ -252,7 +253,7 @@ func (app *BaseApp) setCheckState(header abci.Header) { ms := app.cms.CacheMultiStore() app.checkState = &state{ ms: ms, - ctx: sdk.NewContext(ms, header, true, nil, app.Logger), + ctx: sdk.NewContext(ms, header, true, nil, app.Logger, nil), } } @@ -260,7 +261,7 @@ func (app *BaseApp) setDeliverState(header abci.Header) { ms := app.cms.CacheMultiStore() app.deliverState = &state{ ms: ms, - ctx: sdk.NewContext(ms, header, false, nil, app.Logger), + ctx: sdk.NewContext(ms, header, false, nil, app.Logger, nil), } } @@ -384,6 +385,8 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg if app.beginBlocker != nil { res = app.beginBlocker(app.deliverState.ctx, req) } + // set the absent validators for addition to context in deliverTx + app.absentValidators = req.AbsentValidators return } @@ -493,6 +496,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk ctx = app.checkState.ctx.WithTxBytes(txBytes) } else { ctx = app.deliverState.ctx.WithTxBytes(txBytes) + ctx = ctx.WithAbsentValidators(app.absentValidators) } // Simulate a DeliverTx for gas calculation diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 61498b1b19..0b825e1ee8 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -183,7 +183,7 @@ func TestInitChainer(t *testing.T) { // set initChainer and try again - should see the value app.SetInitChainer(initChainer) - app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}")}) // must have valid JSON genesis file, even if empty + app.InitChain(abci.RequestInitChain{GenesisBytes: []byte("{}")}) // must have valid JSON genesis file, even if empty app.Commit() res = app.Query(query) assert.Equal(t, value, res.Value) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index dbecada004..7ad3709a10 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -15,6 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -34,10 +35,11 @@ type GaiaApp struct { cdc *wire.Codec // keys to access the substores - keyMain *sdk.KVStoreKey - keyAccount *sdk.KVStoreKey - keyIBC *sdk.KVStoreKey - keyStake *sdk.KVStoreKey + keyMain *sdk.KVStoreKey + keyAccount *sdk.KVStoreKey + keyIBC *sdk.KVStoreKey + keyStake *sdk.KVStoreKey + keySlashing *sdk.KVStoreKey // Manage getting and setting accounts accountMapper auth.AccountMapper @@ -45,6 +47,7 @@ type GaiaApp struct { coinKeeper bank.Keeper ibcMapper ibc.Mapper stakeKeeper stake.Keeper + slashingKeeper slashing.Keeper } func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { @@ -52,12 +55,13 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { // create your application object var app = &GaiaApp{ - BaseApp: bam.NewBaseApp(appName, cdc, logger, db), - cdc: cdc, - keyMain: sdk.NewKVStoreKey("main"), - keyAccount: sdk.NewKVStoreKey("acc"), - keyIBC: sdk.NewKVStoreKey("ibc"), - keyStake: sdk.NewKVStoreKey("stake"), + BaseApp: bam.NewBaseApp(appName, cdc, logger, db), + cdc: cdc, + keyMain: sdk.NewKVStoreKey("main"), + keyAccount: sdk.NewKVStoreKey("acc"), + keyIBC: sdk.NewKVStoreKey("ibc"), + keyStake: sdk.NewKVStoreKey("stake"), + keySlashing: sdk.NewKVStoreKey("slashing"), } // define the accountMapper @@ -71,6 +75,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { app.coinKeeper = bank.NewKeeper(app.accountMapper) app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace)) app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace)) + app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.RegisterCodespace(slashing.DefaultCodespace)) // register message routes app.Router(). @@ -80,6 +85,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { // initialize BaseApp app.SetInitChainer(app.initChainer) + app.SetBeginBlocker(slashing.NewBeginBlocker(app.slashingKeeper)) app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper)) app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake) app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) @@ -105,7 +111,8 @@ func MakeCodec() *wire.Codec { // custom logic for gaia initialization func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - stateJSON := req.AppStateBytes + stateJSON := req.GenesisBytes + // TODO is this now the whole genesis file? var genesisState GenesisState err := app.cdc.UnmarshalJSON(stateJSON, &genesisState) diff --git a/docs/spec/staking/old/spec.md b/docs/spec/staking/old/spec.md index bd87ec0285..1eddc3e33d 100644 --- a/docs/spec/staking/old/spec.md +++ b/docs/spec/staking/old/spec.md @@ -297,12 +297,12 @@ type TxProveLive struct { ## Delegator bond Atom holders may delegate coins to validators, under this circumstance their -funds are held in a `DelegatorBond`. It is owned by one delegator, and is +funds are held in a `Delegation`. It is owned by one delegator, and is associated with the shares for one validator. The sender of the transaction is considered to be the owner of the bond, ``` golang -type DelegatorBond struct { +type Delegation struct { Candidate crypto.PubKey Shares rational.Rat AdjustmentFeePool coin.Coins @@ -318,11 +318,11 @@ Description: - AdjustmentRewardPool: Adjustment factor used to passively calculate each bonds entitled fees from `Candidate.ProposerRewardPool`` -Each `DelegatorBond` is individually indexed within the store by delegator +Each `Delegation` is individually indexed within the store by delegator address and candidate pubkey. - key: Delegator and Candidate-Pubkey - - value: DelegatorBond + - value: Delegation ### Delegating @@ -330,7 +330,7 @@ address and candidate pubkey. Delegator bonds are created using the TxDelegate transaction. Within this transaction the validator candidate queried with an amount of coins, whereby given the current exchange rate of candidate's delegator-shares-to-atoms the -candidate will return shares which are assigned in `DelegatorBond.Shares`. +candidate will return shares which are assigned in `Delegation.Shares`. ``` golang type TxDelegate struct { @@ -671,5 +671,5 @@ rate, all commission on fees must be simultaneously withdrawn. `candidate.Adjustment` must be set to the value of `canidate.Count` for the height which the candidate is added on the validator set. - The feePool of a new delegator bond will be 0 for the height at which the bond - was added. This is achieved by setting `DelegatorBond.FeeWithdrawalHeight` to + was added. This is achieved by setting `Delegation.FeeWithdrawalHeight` to the height which the bond was added. diff --git a/docs/spec/staking/old/spec2.md b/docs/spec/staking/old/spec2.md index 72bb8a2e37..68f20703dc 100644 --- a/docs/spec/staking/old/spec2.md +++ b/docs/spec/staking/old/spec2.md @@ -34,7 +34,7 @@ The staking module persists the following to the store: - `GlobalState`, describing the global pools - a `Candidate` for each candidate validator, indexed by public key - a `Candidate` for each candidate validator, indexed by shares in the global pool (ie. ordered) -- a `DelegatorBond` for each delegation to a candidate by a delegator, indexed by delegator and candidate +- a `Delegation` for each delegation to a candidate by a delegator, indexed by delegator and candidate public keys - a `Queue` of unbonding delegations (TODO) @@ -146,15 +146,15 @@ When validators are kicked from the validator set they are removed from this list. -### DelegatorBond +### Delegation Atom holders may delegate coins to validators, under this circumstance their -funds are held in a `DelegatorBond`. It is owned by one delegator, and is +funds are held in a `Delegation`. It is owned by one delegator, and is associated with the shares for one validator. The sender of the transaction is considered to be the owner of the bond, ``` golang -type DelegatorBond struct { +type Delegation struct { Candidate crypto.PubKey Shares rational.Rat AdjustmentFeePool coin.Coins @@ -170,11 +170,11 @@ Description: - AdjustmentRewardPool: Adjustment factor used to passively calculate each bonds entitled fees from `Candidate.ProposerRewardPool`` -Each `DelegatorBond` is individually indexed within the store by delegator +Each `Delegation` is individually indexed within the store by delegator address and candidate pubkey. - key: Delegator and Candidate-Pubkey - - value: DelegatorBond + - value: Delegation ### Unbonding Queue @@ -308,7 +308,7 @@ All bonding, whether self-bonding or delegation, is done via Delegator bonds are created using the TxDelegate transaction. Within this transaction the validator candidate queried with an amount of coins, whereby given the current exchange rate of candidate's delegator-shares-to-atoms the -candidate will return shares which are assigned in `DelegatorBond.Shares`. +candidate will return shares which are assigned in `Delegation.Shares`. ``` golang type TxDelegate struct { @@ -616,7 +616,7 @@ synced past the height of the oldest `powerChange`. This trim procedure will occur on an epoch basis. ```golang -type powerChange struct { +type powerChange struct height int64 // block height at change power rational.Rat // total power at change prevpower rational.Rat // total power at previous height-1 @@ -694,5 +694,5 @@ rate, all commission on fees must be simultaneously withdrawn. `candidate.Adjustment` must be set to the value of `canidate.Count` for the height which the candidate is added on the validator set. - The feePool of a new delegator bond will be 0 for the height at which the bond - was added. This is achieved by setting `DelegatorBond.FeeWithdrawalHeight` to + was added. This is achieved by setting `Delegation.FeeWithdrawalHeight` to the height which the bond was added. diff --git a/docs/spec/staking/transactions.md b/docs/spec/staking/transactions.md index 52f324b0f7..eed082503b 100644 --- a/docs/spec/staking/transactions.md +++ b/docs/spec/staking/transactions.md @@ -203,7 +203,7 @@ unbond(tx TxUnbond): return removeShares(candidate Candidate, shares rational.Rat): - globalPoolSharesToRemove = delegatorShareExRate(candidate) * shares + globalPoolSharesToRemove = DelegatorShareExRate(candidate) * shares if candidate.Status == Bonded gs.BondedShares -= globalPoolSharesToRemove @@ -218,7 +218,7 @@ removeShares(candidate Candidate, shares rational.Rat): candidate.IssuedDelegatorShares -= shares return returnedCoins -delegatorShareExRate(candidate Candidate): +DelegatorShareExRate(candidate Candidate): if candidate.IssuedDelegatorShares.IsZero() then return rational.One return candidate.GlobalStakeShares / candidate.IssuedDelegatorShares diff --git a/docs/spec/staking/valset-changes.md b/docs/spec/staking/valset-changes.md index bc52b89980..e5979af39a 100644 --- a/docs/spec/staking/valset-changes.md +++ b/docs/spec/staking/valset-changes.md @@ -31,8 +31,8 @@ tick(ctx Context): if time > unbondDelegationQueue.head().InitTime + UnbondingPeriod for each element elem in the unbondDelegationQueue where time > elem.InitTime + UnbondingPeriod do - transfer(unbondingQueueAddress, elem.Payout, elem.Tokens) - unbondDelegationQueue.remove(elem) + transfer(unbondingQueueAddress, elem.Payout, elem.Tokens) + unbondDelegationQueue.remove(elem) if time > reDelegationQueue.head().InitTime + UnbondingPeriod for each element elem in the unbondDelegationQueue where time > elem.InitTime + UnbondingPeriod do @@ -55,9 +55,9 @@ nextInflation(hrsPerYr rational.Rat): inflation = gs.Inflation + inflationRateChange if inflation > params.InflationMax then inflation = params.InflationMax - + if inflation < params.InflationMin then inflation = params.InflationMin - + return inflation UpdateValidatorSet(): @@ -71,26 +71,26 @@ UpdateValidatorSet(): updateVotingPower(candidates Candidates): foreach candidate in candidates do - candidate.VotingPower = (candidate.IssuedDelegatorShares - candidate.RedelegatingShares) * delegatorShareExRate(candidate) - + candidate.VotingPower = (candidate.IssuedDelegatorShares - candidate.RedelegatingShares) * DelegatorShareExRate(candidate) + candidates.Sort() - + foreach candidate in candidates do - if candidate is not in the first params.MaxVals - candidate.VotingPower = rational.Zero - if candidate.Status == Bonded then bondedToUnbondedPool(candidate Candidate) - - else if candidate.Status == UnBonded then unbondedToBondedPool(candidate) + if candidate is not in the first params.MaxVals + candidate.VotingPower = rational.Zero + if candidate.Status == Bonded then bondedToUnbondedPool(candidate Candidate) + + else if candidate.Status == UnBonded then unbondedToBondedPool(candidate) - saveCandidate(store, c) - + saveCandidate(store, c) + return candidates unbondedToBondedPool(candidate Candidate): removedTokens = exchangeRate(gs.UnbondedShares, gs.UnbondedPool) * candidate.GlobalStakeShares gs.UnbondedShares -= candidate.GlobalStakeShares gs.UnbondedPool -= removedTokens - + gs.BondedPool += removedTokens issuedShares = removedTokens / exchangeRate(gs.BondedShares, gs.BondedPool) gs.BondedShares += issuedShares @@ -155,16 +155,17 @@ The following information is stored with each validator candidate, and is only n ```go type ValidatorSigningInfo struct { - StartHeight int64 - SignedBlocksBitArray BitArray + StartHeight int64 + SignedBlocksBitArray BitArray + SignedBlocksCounter int64 } ``` Where: * `StartHeight` is set to the height that the candidate became an active validator (with non-zero voting power). * `SignedBlocksBitArray` is a bit-array of size `SIGNED_BLOCKS_WINDOW` that records, for each of the last `SIGNED_BLOCKS_WINDOW` blocks, -whether or not this validator was included in the LastCommit. It uses a `0` if the validator was included, and a `1` if it was not. -Note it is initialized with all 0s. +whether or not this validator was included in the LastCommit. It uses a `1` if the validator was included, and a `0` if it was not. Note it is initialized with all 0s. +* `SignedBlocksCounter` is a counter kept to avoid unnecessary array reads. `SignedBlocksBitArray.Sum() == SignedBlocksCounter` always. At the beginning of each block, we update the signing info for each validator and check if they should be automatically unbonded: @@ -173,18 +174,23 @@ h = block.Height index = h % SIGNED_BLOCKS_WINDOW for val in block.Validators: - signInfo = val.SignInfo - if val in block.LastCommit: - signInfo.SignedBlocksBitArray.Set(index, 0) - else - signInfo.SignedBlocksBitArray.Set(index, 1) + signInfo = val.SignInfo + previous = signInfo.SignedBlocksBitArray.Get(index) - // validator must be active for at least SIGNED_BLOCKS_WINDOW - // before they can be automatically unbonded for failing to be - // included in 50% of the recent LastCommits - minHeight = signInfo.StartHeight + SIGNED_BLOCKS_WINDOW - minSigned = SIGNED_BLOCKS_WINDOW / 2 - blocksSigned = signInfo.SignedBlocksBitArray.Sum() - if h > minHeight AND blocksSigned < minSigned: - unbond the validator + // update counter if array has changed + if previous and val in block.AbsentValidators: + signInfo.SignedBlocksBitArray.Set(index, 0) + signInfo.SignedBlocksCounter-- + else if !previous and val not in block.AbsentValidators: + signInfo.SignedBlocksBitArray.Set(index, 1) + signInfo.SignedBlocksCounter++ + // else previous == val not in block.AbsentValidators, no change + + // validator must be active for at least SIGNED_BLOCKS_WINDOW + // before they can be automatically unbonded for failing to be + // included in 50% of the recent LastCommits + minHeight = signInfo.StartHeight + SIGNED_BLOCKS_WINDOW + minSigned = SIGNED_BLOCKS_WINDOW / 2 + if h > minHeight AND signInfo.SignedBlocksCounter < minSigned: + unbond the validator ``` diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index 086fa32b36..a0b1f86ad6 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -104,7 +104,7 @@ func MakeCodec() *wire.Codec { // Custom logic for basecoin initialization func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - stateJSON := req.AppStateBytes + stateJSON := req.GenesisBytes genesisState := new(types.GenesisState) err := app.cdc.UnmarshalJSON(stateJSON, genesisState) diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 2075a64da0..b8b8642cf3 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -118,7 +118,7 @@ func MakeCodec() *wire.Codec { // custom logic for democoin initialization func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - stateJSON := req.AppStateBytes + stateJSON := req.GenesisBytes genesisState := new(types.GenesisState) err := app.cdc.UnmarshalJSON(stateJSON, genesisState) diff --git a/examples/democoin/x/cool/keeper_test.go b/examples/democoin/x/cool/keeper_test.go index d497dee699..f632ae31ee 100644 --- a/examples/democoin/x/cool/keeper_test.go +++ b/examples/democoin/x/cool/keeper_test.go @@ -30,7 +30,7 @@ func TestCoolKeeper(t *testing.T) { auth.RegisterBaseAccount(cdc) am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, nil, nil) ck := bank.NewKeeper(am) keeper := NewKeeper(capKey, ck, DefaultCodespace) diff --git a/examples/democoin/x/pow/handler_test.go b/examples/democoin/x/pow/handler_test.go index 30aeafa2a5..867120eb84 100644 --- a/examples/democoin/x/pow/handler_test.go +++ b/examples/democoin/x/pow/handler_test.go @@ -20,7 +20,7 @@ func TestPowHandler(t *testing.T) { auth.RegisterBaseAccount(cdc) am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) config := NewConfig("pow", int64(1)) ck := bank.NewKeeper(am) keeper := NewKeeper(capKey, config, ck, DefaultCodespace) diff --git a/examples/democoin/x/pow/keeper_test.go b/examples/democoin/x/pow/keeper_test.go index a4afb876a9..98e8ebcfea 100644 --- a/examples/democoin/x/pow/keeper_test.go +++ b/examples/democoin/x/pow/keeper_test.go @@ -33,7 +33,7 @@ func TestPowKeeperGetSet(t *testing.T) { auth.RegisterBaseAccount(cdc) am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) config := NewConfig("pow", int64(1)) ck := bank.NewKeeper(am) keeper := NewKeeper(capKey, config, ck, DefaultCodespace) diff --git a/examples/democoin/x/simplestake/keeper_test.go b/examples/democoin/x/simplestake/keeper_test.go index 515c19cc59..ef34f3085c 100644 --- a/examples/democoin/x/simplestake/keeper_test.go +++ b/examples/democoin/x/simplestake/keeper_test.go @@ -35,9 +35,9 @@ func TestKeeperGetSet(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) stakeKeeper := NewKeeper(capKey, bank.NewKeeper(accountMapper), DefaultCodespace) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) addr := sdk.Address([]byte("some-address")) bi := stakeKeeper.getBondInfo(ctx, addr) @@ -63,7 +63,7 @@ func TestBonding(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := bank.NewKeeper(accountMapper) diff --git a/mock/app.go b/mock/app.go index ab1a8447a5..09d7a658c7 100644 --- a/mock/app.go +++ b/mock/app.go @@ -88,7 +88,7 @@ type GenesisJSON struct { // with key/value pairs func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci.ResponseInitChain { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - stateJSON := req.AppStateBytes + stateJSON := req.GenesisBytes genesisState := new(GenesisJSON) err := json.Unmarshal(stateJSON, genesisState) diff --git a/mock/app_test.go b/mock/app_test.go index be1d778295..50b0761c17 100644 --- a/mock/app_test.go +++ b/mock/app_test.go @@ -26,7 +26,7 @@ func TestInitApp(t *testing.T) { //TODO test validators in the init chain? req := abci.RequestInitChain{ - AppStateBytes: appState, + GenesisBytes: appState, } app.InitChain(req) app.Commit() diff --git a/types/context.go b/types/context.go index 4ab0a5d093..993c148ec5 100644 --- a/types/context.go +++ b/types/context.go @@ -30,7 +30,9 @@ type Context struct { } // create a new context -func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byte, logger log.Logger) Context { +func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, + txBytes []byte, logger log.Logger, absentValidators [][]byte) Context { + c := Context{ Context: context.Background(), pst: newThePast(), @@ -43,6 +45,7 @@ func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byt c = c.WithIsCheckTx(isCheckTx) c = c.WithTxBytes(txBytes) c = c.WithLogger(logger) + c = c.WithAbsentValidators(absentValidators) c = c.WithGasMeter(NewInfiniteGasMeter()) return c } @@ -128,6 +131,7 @@ const ( contextKeyIsCheckTx contextKeyTxBytes contextKeyLogger + contextKeyAbsentValidators contextKeyGasMeter ) @@ -157,6 +161,9 @@ func (c Context) TxBytes() []byte { func (c Context) Logger() log.Logger { return c.Value(contextKeyLogger).(log.Logger) } +func (c Context) AbsentValidators() [][]byte { + return c.Value(contextKeyAbsentValidators).([][]byte) +} func (c Context) GasMeter() GasMeter { return c.Value(contextKeyGasMeter).(GasMeter) } @@ -182,6 +189,9 @@ func (c Context) WithTxBytes(txBytes []byte) Context { func (c Context) WithLogger(logger log.Logger) Context { return c.withValue(contextKeyLogger, logger) } +func (c Context) WithAbsentValidators(AbsentValidators [][]byte) Context { + return c.withValue(contextKeyAbsentValidators, AbsentValidators) +} func (c Context) WithGasMeter(meter GasMeter) Context { return c.withValue(contextKeyGasMeter, meter) } diff --git a/types/context_test.go b/types/context_test.go index ec5faab440..1eafdaf7e7 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -43,7 +43,7 @@ func (l MockLogger) With(kvs ...interface{}) log.Logger { func TestContextGetOpShouldNeverPanic(t *testing.T) { var ms types.MultiStore - ctx := types.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := types.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) indices := []int64{ -10, 1, 0, 10, 20, } @@ -58,7 +58,7 @@ func defaultContext(key types.StoreKey) types.Context { cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, types.StoreTypeIAVL, db) cms.LoadLatestVersion() - ctx := types.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := types.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger(), nil) return ctx } diff --git a/types/lib/mapper_test.go b/types/lib/mapper_test.go index e1759b06ac..a610f1e0fa 100644 --- a/types/lib/mapper_test.go +++ b/types/lib/mapper_test.go @@ -25,7 +25,7 @@ func defaultComponents(key sdk.StoreKey) (sdk.Context, *wire.Codec) { cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) cms.LoadLatestVersion() - ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger(), nil) cdc := wire.NewCodec() return ctx, cdc } diff --git a/types/stake.go b/types/stake.go index df74a705b9..e60c4f43cb 100644 --- a/types/stake.go +++ b/types/stake.go @@ -17,11 +17,14 @@ const ( // validator for a delegated proof of stake system type Validator interface { - GetStatus() BondStatus // status of the validator - GetOwner() Address // owner address to receive/return validators coins - GetPubKey() crypto.PubKey // validation pubkey - GetPower() Rat // validation power - GetBondHeight() int64 // height in which the validator became active + GetStatus() BondStatus // status of the validator + GetOwner() Address // owner address to receive/return validators coins + GetPubKey() crypto.PubKey // validation pubkey + GetPower() Rat // validation power + GetBondHeight() int64 // height in which the validator became active + Slash(Context, int64, Rat) // slash the validator and delegators of the validator + // for an offense at a specified height by a specified fraction + ForceUnbond(Context, int64) // force unbond the validator, including a duration which must pass before they can rebond } // validator which fulfills abci validator interface for use in Tendermint diff --git a/types/tags.go b/types/tags.go index 95a826fd78..5a8eb1f473 100644 --- a/types/tags.go +++ b/types/tags.go @@ -25,6 +25,11 @@ func (t Tags) AppendTags(a Tags) Tags { return append(t, a...) } +// Turn tags into KVPair list +func (t Tags) ToKVPairs() []cmn.KVPair { + return []cmn.KVPair(t) +} + // New variadic tags, must be k string, v []byte repeating func NewTags(tags ...interface{}) Tags { var ret Tags diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index b7f22e5d54..729f0769ef 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -75,7 +75,7 @@ func TestAnteHandlerSigErrors(t *testing.T) { mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) // keys and addresses priv1, addr1 := privAndAddr() @@ -117,7 +117,7 @@ func TestAnteHandlerSequences(t *testing.T) { mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) // keys and addresses priv1, addr1 := privAndAddr() @@ -184,7 +184,7 @@ func TestAnteHandlerFees(t *testing.T) { mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) // keys and addresses priv1, addr1 := privAndAddr() @@ -226,7 +226,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) // keys and addresses priv1, addr1 := privAndAddr() @@ -302,7 +302,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) { mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) // keys and addresses priv1, addr1 := privAndAddr() diff --git a/x/auth/context_test.go b/x/auth/context_test.go index a93de44d0c..c4aaca269a 100644 --- a/x/auth/context_test.go +++ b/x/auth/context_test.go @@ -12,8 +12,8 @@ import ( ) func TestContextWithSigners(t *testing.T) { - ms, _, _ := setupMultiStore() - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) + ms, _ := setupMultiStore() + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) _, _, addr1 := keyPubAddr() _, _, addr2 := keyPubAddr() diff --git a/x/auth/mapper_test.go b/x/auth/mapper_test.go index 7f6397069a..dc6afef57e 100644 --- a/x/auth/mapper_test.go +++ b/x/auth/mapper_test.go @@ -31,7 +31,7 @@ func TestAccountMapperGetSet(t *testing.T) { RegisterBaseAccount(cdc) // make context and mapper - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) addr := sdk.Address([]byte("some-address")) diff --git a/x/bank/keeper_test.go b/x/bank/keeper_test.go index 117c69e7ae..07ba91e0c5 100644 --- a/x/bank/keeper_test.go +++ b/x/bank/keeper_test.go @@ -31,7 +31,7 @@ func TestKeeper(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := NewKeeper(accountMapper) @@ -116,7 +116,7 @@ func TestSendKeeper(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := NewKeeper(accountMapper) sendKeeper := NewSendKeeper(accountMapper) @@ -185,7 +185,7 @@ func TestViewKeeper(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := NewKeeper(accountMapper) viewKeeper := NewViewKeeper(accountMapper) diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index e13df4f8dd..9ed4b38254 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -24,7 +24,7 @@ func defaultContext(key sdk.StoreKey) sdk.Context { cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) cms.LoadLatestVersion() - ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger(), nil) return ctx } diff --git a/x/slashing/errors.go b/x/slashing/errors.go new file mode 100644 index 0000000000..bf57c337d7 --- /dev/null +++ b/x/slashing/errors.go @@ -0,0 +1,32 @@ +package slashing + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Local code type +type CodeType = sdk.CodeType + +const ( + // Default slashing codespace + DefaultCodespace sdk.CodespaceType = 10 +) + +func codeToDefaultMsg(code CodeType) string { + switch code { + default: + return sdk.CodeToDefaultMsg(code) + } +} + +func msgOrDefaultMsg(msg string, code CodeType) string { + if msg != "" { + return msg + } + return codeToDefaultMsg(code) +} + +func newError(codespace sdk.CodespaceType, code CodeType, msg string) sdk.Error { + msg = msgOrDefaultMsg(msg, code) + return sdk.NewError(codespace, code, msg) +} diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go new file mode 100644 index 0000000000..f1aac7f586 --- /dev/null +++ b/x/slashing/keeper.go @@ -0,0 +1,148 @@ +package slashing + +import ( + "encoding/binary" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/stake" + crypto "github.com/tendermint/go-crypto" +) + +const ( + // MaxEvidenceAge - Max age for evidence - 21 days (3 weeks) + // TODO Should this be a governance parameter or just modifiable with SoftwareUpgradeProposals? + // MaxEvidenceAge = 60 * 60 * 24 * 7 * 3 + // TODO Temporarily set to 2 minutes for testnets. + MaxEvidenceAge int64 = 60 * 2 + + // SignedBlocksWindow - sliding window for downtime slashing + // TODO Governance parameter? + // TODO Temporarily set to 100 blocks for testnets + SignedBlocksWindow int64 = 100 + + // Downtime slashing threshold - 50% + // TODO Governance parameter? + MinSignedPerWindow int64 = SignedBlocksWindow / 2 + + // Downtime unbond duration - 1 day + // TODO Governance parameter? + DowntimeUnbondDuration int64 = 86400 +) + +var ( + // SlashFractionDoubleSign - currently 5% + // TODO Governance parameter? + SlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20)) + + // SlashFractionDowntime - currently 0 + // TODO Governance parameter? + SlashFractionDowntime = sdk.ZeroRat() +) + +// Keeper of the slashing store +type Keeper struct { + storeKey sdk.StoreKey + cdc *wire.Codec + stakeKeeper stake.Keeper + + // codespace + codespace sdk.CodespaceType +} + +// NewKeeper creates a slashing keeper +func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, sk stake.Keeper, codespace sdk.CodespaceType) Keeper { + keeper := Keeper{ + storeKey: key, + cdc: cdc, + stakeKeeper: sk, + codespace: codespace, + } + return keeper +} + +// handle a validator signing two blocks at the same height +func (k Keeper) handleDoubleSign(ctx sdk.Context, height int64, timestamp int64, pubkey crypto.PubKey) { + logger := ctx.Logger().With("module", "x/slashing") + age := ctx.BlockHeader().Time - timestamp + if age > MaxEvidenceAge { + logger.Info(fmt.Sprintf("Ignored double sign from %v at height %d, age of %d past max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) + return + } + logger.Info(fmt.Sprintf("Confirmed double sign from %v at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) + validator := k.stakeKeeper.Validator(ctx, pubkey.Address()) + validator.Slash(ctx, height, SlashFractionDoubleSign) + logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v for double-sign at height %d", pubkey.Address(), SlashFractionDoubleSign, height)) +} + +// handle a validator signature, must be called once per validator per block +func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, signed bool) { + logger := ctx.Logger().With("module", "x/slashing") + height := ctx.BlockHeight() + if !signed { + logger.Info(fmt.Sprintf("Absent validator %v at height %d", pubkey.Address(), height)) + } + index := height % SignedBlocksWindow + address := pubkey.Address() + signInfo := k.getValidatorSigningInfo(ctx, address) + previous := k.getValidatorSigningBitArray(ctx, address, index) + if previous && !signed { + k.setValidatorSigningBitArray(ctx, address, index, false) + signInfo.SignedBlocksCounter-- + k.setValidatorSigningInfo(ctx, address, signInfo) + } else if !previous && signed { + k.setValidatorSigningBitArray(ctx, address, index, true) + signInfo.SignedBlocksCounter++ + k.setValidatorSigningInfo(ctx, address, signInfo) + } + minHeight := signInfo.StartHeight + SignedBlocksWindow + if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { + validator := k.stakeKeeper.Validator(ctx, address) + validator.Slash(ctx, height, SlashFractionDowntime) + validator.ForceUnbond(ctx, DowntimeUnbondDuration) + logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v and unbonded for downtime at height %d, cannot rebond for %ds", + address, SlashFractionDowntime, height, DowntimeUnbondDuration)) + } +} + +func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (info validatorSigningInfo) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(validatorSigningInfoKey(address)) + k.cdc.MustUnmarshalBinary(bz, &info) + return +} + +func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.Address, info validatorSigningInfo) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshalBinary(info) + store.Set(validatorSigningInfoKey(address), bz) +} + +func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64) (signed bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(validatorSigningBitArrayKey(address, index)) + k.cdc.MustUnmarshalBinary(bz, &signed) + return +} + +func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64, signed bool) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshalBinary(signed) + store.Set(validatorSigningBitArrayKey(address, index), bz) +} + +type validatorSigningInfo struct { + StartHeight int64 `json:"start_height"` + SignedBlocksCounter int64 `json:"signed_blocks_counter"` +} + +func validatorSigningInfoKey(v sdk.Address) []byte { + return append([]byte{0x01}, v.Bytes()...) +} + +func validatorSigningBitArrayKey(v sdk.Address, i int64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, uint64(i)) + return append([]byte{0x02}, append(v.Bytes(), b...)...) +} diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go new file mode 100644 index 0000000000..9085a7ae60 --- /dev/null +++ b/x/slashing/keeper_test.go @@ -0,0 +1,17 @@ +package slashing + +import ( + "testing" + + "github.com/stretchr/testify/require" + // sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestHandleDoubleSign(t *testing.T) { + require.Equal(t, true, true) + // TODO +} + +func TestHandleAbsentValidator(t *testing.T) { + // TODO +} diff --git a/x/slashing/tick.go b/x/slashing/tick.go new file mode 100644 index 0000000000..e76c06abe3 --- /dev/null +++ b/x/slashing/tick.go @@ -0,0 +1,44 @@ +package slashing + +import ( + "bytes" + "encoding/binary" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" +) + +func NewBeginBlocker(sk Keeper) sdk.BeginBlocker { + return func(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { + heightBytes := make([]byte, 8) + binary.LittleEndian.PutUint64(heightBytes, uint64(req.Header.Height)) + tags := sdk.NewTags("height", heightBytes) + for _, evidence := range req.ByzantineValidators { + var pk crypto.PubKey + sk.cdc.MustUnmarshalBinary(evidence.PubKey, &pk) + switch { + case bytes.Compare(evidence.Type, []byte("doubleSign")) == 0: + sk.handleDoubleSign(ctx, evidence.Height, evidence.Time, pk) + default: + ctx.Logger().With("module", "x/slashing").Error(fmt.Sprintf("Ignored unknown evidence type: %s", string(evidence.Type))) + } + } + absent := make(map[string]bool) + for _, pubkey := range req.AbsentValidators { + var pk crypto.PubKey + sk.cdc.MustUnmarshalBinary(pubkey, &pk) + absent[string(pk.Bytes())] = true + } + sk.stakeKeeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { + pubkey := validator.GetPubKey() + sk.handleValidatorSignature(ctx, pubkey, !absent[string(pubkey.Bytes())]) + return false + }) + // TODO Add some more tags so clients can track slashing + return abci.ResponseBeginBlock{ + Tags: tags.ToKVPairs(), + } + } +} diff --git a/x/stake/test_common.go b/x/stake/test_common.go index b7a5152c09..1cd46549b0 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -103,7 +103,7 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context err := ms.LoadLatestVersion() require.Nil(t, err) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil, log.NewNopLogger(), nil) cdc := makeTestCodec() accountMapper := auth.NewAccountMapper( cdc, // amino codec diff --git a/x/stake/validator.go b/x/stake/validator.go index 88f061f315..7848724fd6 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -236,3 +236,9 @@ func (v Validator) GetOwner() sdk.Address { return v.Owner } func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } func (v Validator) GetPower() sdk.Rat { return v.PoolShares.Bonded() } func (v Validator) GetBondHeight() int64 { return v.BondHeight } +func (v Validator) Slash(ctx sdk.Context, height int64, fraction sdk.Rat) { + panic("not implemented") +} +func (v Validator) ForceUnbond(ctx sdk.Context, jailDuration int64) { + panic("not implemented") +} From 67f7f31ba9bb3c19e7aec03aa27511f0ba63db48 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 23 May 2018 22:52:56 +0200 Subject: [PATCH 021/128] Fix testcases by mounting store --- cmd/gaia/app/app.go | 2 +- x/slashing/keeper.go | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 7ad3709a10..28904e1ac9 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -87,8 +87,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { app.SetInitChainer(app.initChainer) app.SetBeginBlocker(slashing.NewBeginBlocker(app.slashingKeeper)) app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper)) - app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake) app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) + app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing) err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index f1aac7f586..4945da6a74 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -85,7 +85,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, } index := height % SignedBlocksWindow address := pubkey.Address() - signInfo := k.getValidatorSigningInfo(ctx, address) + signInfo, _ := k.getValidatorSigningInfo(ctx, address) previous := k.getValidatorSigningBitArray(ctx, address, index) if previous && !signed { k.setValidatorSigningBitArray(ctx, address, index, false) @@ -106,10 +106,15 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, } } -func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (info validatorSigningInfo) { +func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (info validatorSigningInfo, found bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(validatorSigningInfoKey(address)) - k.cdc.MustUnmarshalBinary(bz, &info) + if bz == nil { + found = false + } else { + k.cdc.MustUnmarshalBinary(bz, &info) + found = true + } return } @@ -122,7 +127,12 @@ func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.Address, in func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64) (signed bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(validatorSigningBitArrayKey(address, index)) - k.cdc.MustUnmarshalBinary(bz, &signed) + if bz == nil { + // lazy: treat empty key as unsigned + signed = false + } else { + k.cdc.MustUnmarshalBinary(bz, &signed) + } return } From adec1cd7a956dad6d9a3050fee8d015f514ef262 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 24 May 2018 01:56:54 +0200 Subject: [PATCH 022/128] Fix dependencies, gaiacli build issue persists --- Gopkg.lock | 20 ++++++++++---------- Gopkg.toml | 13 +++++-------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 7f1f6185e6..286760d609 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -250,10 +250,10 @@ "leveldb/table", "leveldb/util" ] - revision = "e6d6b529196422703d54ff5c40e79809ec2020b3" + revision = "5d6fca44a948d2be89a9702de7717f0168403d3d" [[projects]] - branch = "cwgoes/timestamp-in-evidence" + branch = "develop" name = "github.com/tendermint/abci" packages = [ "client", @@ -262,7 +262,7 @@ "server", "types" ] - revision = "e196dacf804e3a4ab74252c27e99cb17b39bf501" + revision = "f9dce537281ffba5d1e047e6729429f7e5fb90c9" [[projects]] branch = "master" @@ -299,7 +299,7 @@ ".", "sha256truncated" ] - revision = "9b6f9c3f49d599cfcf43f1a56c3c22882d1f9f21" + revision = "c9206995e8f948e99927f5084a88a7e94ca256da" [[projects]] branch = "cwgoes/update-abci" @@ -357,8 +357,8 @@ "log", "merkle" ] - revision = "cc5f287c4798ffe88c04d02df219ecb6932080fd" - version = "v0.8.3-rc0" + revision = "d970af87248a4e162590300dbb74e102183a417d" + version = "v0.8.3" [[projects]] branch = "master" @@ -374,7 +374,7 @@ "ripemd160", "salsa20/salsa" ] - revision = "1a580b3eff7814fc9b40602fd35256c63b50f491" + revision = "75e913eb8a8e3d31a97b216de09de106a7b07681" [[projects]] branch = "master" @@ -388,13 +388,13 @@ "internal/timeseries", "trace" ] - revision = "57065200b4b034a1c8ad54ff77069408c2218ae6" + revision = "9ef9f5bb98a1fdc41f8cf6c250a4404b4085e389" [[projects]] branch = "master" name = "golang.org/x/sys" packages = ["unix"] - revision = "7c87d13f8e835d2fb3a70a2912c811ed0c1d241b" + revision = "77b0e4315053a57ed2962443614bdb28db152054" [[projects]] name = "golang.org/x/text" @@ -455,6 +455,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "2bb789b91c383e3a861979c83e61f5f8fd71ea5661837c092353aaacf3091de1" + inputs-digest = "bbc0ee39f39cb296960a5fcb2a3916a4acc48ecbb675758ea1f61def44e994bb" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 05b01bfaef..53dbabbbb3 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -54,29 +54,25 @@ [[override]] name = "github.com/tendermint/abci" - branch = "cwgoes/timestamp-in-evidence" + branch = "develop" [[constraint]] name = "github.com/tendermint/go-crypto" version = "~0.6.2" -[[override]] - name = "github.com/tendermint/go-wire" - version = "0.7.3" - [[constraint]] name = "github.com/tendermint/go-amino" version = "~0.9.9" -[[constraint]] +[[override]] name = "github.com/tendermint/iavl" branch = "develop" -[[constraint]] +[[override]] name = "github.com/tendermint/tendermint" branch = "cwgoes/update-abci" -[[override]] +[[constraint]] name = "github.com/tendermint/tmlibs" version = "~0.8.3-rc0" @@ -88,3 +84,4 @@ [prune] go-tests = true unused-packages = true + From b005f9f18d7116c7d4e17a5cd438d6ea2cebb746 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 24 May 2018 23:51:42 +0200 Subject: [PATCH 023/128] Validator by pubkey, tests work-in-progress --- types/stake.go | 5 +- x/slashing/keeper.go | 10 +++- x/slashing/keeper_test.go | 97 ++++++++++++++++++++++++++++++++++++++- x/stake/keeper.go | 22 +++++++++ x/stake/keeper_keys.go | 20 +++++--- 5 files changed, 141 insertions(+), 13 deletions(-) diff --git a/types/stake.go b/types/stake.go index e60c4f43cb..6e3d02c3d3 100644 --- a/types/stake.go +++ b/types/stake.go @@ -45,8 +45,9 @@ type ValidatorSet interface { IterateValidatorsBonded(Context, func(index int64, validator Validator) (stop bool)) - Validator(Context, Address) Validator // get a particular validator by owner address - TotalPower(Context) Rat // total power of the validator set + Validator(Context, Address) Validator // get a particular validator by owner address + ValidatorByPubKey(Context, crypto.PubKey) Validator // get a particular validator by public key + TotalPower(Context) Rat // total power of the validator set } //_______________________________________________________________________________ diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 4945da6a74..686f84b65c 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -71,7 +71,10 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, height int64, timestamp int64, return } logger.Info(fmt.Sprintf("Confirmed double sign from %v at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) - validator := k.stakeKeeper.Validator(ctx, pubkey.Address()) + validator := k.stakeKeeper.ValidatorByPubKey(ctx, pubkey) + if validator == nil { + panic(fmt.Errorf("Attempted to slash nonexistent validator with address %s", pubkey.Address())) + } validator.Slash(ctx, height, SlashFractionDoubleSign) logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v for double-sign at height %d", pubkey.Address(), SlashFractionDoubleSign, height)) } @@ -98,7 +101,10 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, } minHeight := signInfo.StartHeight + SignedBlocksWindow if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { - validator := k.stakeKeeper.Validator(ctx, address) + validator := k.stakeKeeper.ValidatorByPubKey(ctx, pubkey) + if validator == nil { + panic(fmt.Errorf("Attempted to slash nonexistent validator with address %s", pubkey.Address())) + } validator.Slash(ctx, height, SlashFractionDowntime) validator.ForceUnbond(ctx, DowntimeUnbondDuration) logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v and unbonded for downtime at height %d, cannot rebond for %ds", diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 9085a7ae60..f360fd9e99 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -1,17 +1,110 @@ package slashing import ( + "encoding/hex" "testing" "github.com/stretchr/testify/require" - // sdk "github.com/cosmos/cosmos-sdk/types" + + abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" + dbm "github.com/tendermint/tmlibs/db" + "github.com/tendermint/tmlibs/log" + + "github.com/cosmos/cosmos-sdk/store" + 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/bank" + "github.com/cosmos/cosmos-sdk/x/stake" ) +var ( + addrs = []sdk.Address{ + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161"), + } + pks = []crypto.PubKey{ + newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"), + newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), + } + initCoins int64 = 100 +) + +func createTestCodec() *wire.Codec { + cdc := wire.NewCodec() + sdk.RegisterWire(cdc) + auth.RegisterWire(cdc) + bank.RegisterWire(cdc) + stake.RegisterWire(cdc) + wire.RegisterCrypto(cdc) + return cdc +} + +func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keeper) { + keyAcc := sdk.NewKVStoreKey("acc") + keyStake := sdk.NewKVStoreKey("stake") + keySlashing := sdk.NewKVStoreKey("slashing") + db := dbm.NewMemDB() + ms := store.NewCommitMultiStore(db) + ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db) + err := ms.LoadLatestVersion() + require.Nil(t, err) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + cdc := createTestCodec() + accountMapper := auth.NewAccountMapper(cdc, keyAcc, &auth.BaseAccount{}) + ck := bank.NewKeeper(accountMapper) + sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) + stake.InitGenesis(ctx, sk, stake.DefaultGenesisState()) + for _, addr := range addrs { + ck.AddCoins(ctx, addr, sdk.Coins{ + {sk.GetParams(ctx).BondDenom, initCoins}, + }) + } + keeper := NewKeeper(cdc, keySlashing, sk, DefaultCodespace) + return ctx, ck, sk, keeper +} + func TestHandleDoubleSign(t *testing.T) { - require.Equal(t, true, true) + ctx, ck, sk, keeper := createTestInput(t) + addr, val, amt := addrs[0], pks[0], int64(10) + got := stake.NewHandler(sk)(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) + require.True(t, got.IsOK()) + _ = sk.Tick(ctx) + require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) + keeper.handleDoubleSign(ctx, 0, 0, val) // TODO } func TestHandleAbsentValidator(t *testing.T) { // TODO } + +func newPubKey(pk string) (res crypto.PubKey) { + pkBytes, err := hex.DecodeString(pk) + if err != nil { + panic(err) + } + var pkEd crypto.PubKeyEd25519 + copy(pkEd[:], pkBytes[:]) + return pkEd +} + +func testAddr(addr string) sdk.Address { + res, err := sdk.GetAddress(addr) + if err != nil { + panic(err) + } + return res +} + +func newTestMsgDeclareCandidacy(address sdk.Address, pubKey crypto.PubKey, amt int64) stake.MsgDeclareCandidacy { + return stake.MsgDeclareCandidacy{ + Description: stake.Description{}, + ValidatorAddr: address, + PubKey: pubKey, + Bond: sdk.Coin{"steak", amt}, + } +} diff --git a/x/stake/keeper.go b/x/stake/keeper.go index ce84b1e177..f46cc6f23a 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/bank" abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" ) // keeper of the staking store @@ -38,6 +39,18 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator Valid return k.getValidator(store, addr) } +// get a single validator by pubkey +func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (validator Validator, found bool) { + store := ctx.KVStore(k.storeKey) + b := store.Get(GetValidatorByPubKeyKey(pubkey)) + if b == nil { + return validator, false + } + var addr sdk.Address + k.cdc.MustUnmarshalBinary(b, &addr) + return k.getValidator(store, addr) +} + // get a single validator (reuse store) func (k Keeper) getValidator(store sdk.KVStore, addr sdk.Address) (validator Validator, found bool) { b := store.Get(GetValidatorKey(addr)) @@ -710,6 +723,15 @@ func (k Keeper) Validator(ctx sdk.Context, addr sdk.Address) sdk.Validator { return val } +// get the sdk.validator for a particular pubkey +func (k Keeper) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) sdk.Validator { + val, found := k.GetValidatorByPubKey(ctx, pubkey) + if !found { + return nil + } + return val +} + // total power from the bond func (k Keeper) TotalPower(ctx sdk.Context) sdk.Rat { pool := k.GetPool(ctx) diff --git a/x/stake/keeper_keys.go b/x/stake/keeper_keys.go index 5a84d08f29..e09a47ecab 100644 --- a/x/stake/keeper_keys.go +++ b/x/stake/keeper_keys.go @@ -16,13 +16,14 @@ var ( ParamKey = []byte{0x00} // key for parameters relating to staking PoolKey = []byte{0x01} // key for the staking pools ValidatorsKey = []byte{0x02} // prefix for each key to a validator - ValidatorsBondedKey = []byte{0x03} // prefix for each key to bonded/actively validating validators - ValidatorsByPowerKey = []byte{0x04} // prefix for each key to a validator sorted by power - ValidatorCliffKey = []byte{0x05} // key for block-local tx index - ValidatorPowerCliffKey = []byte{0x06} // key for block-local tx index - TendermintUpdatesKey = []byte{0x07} // prefix for each key to a validator which is being updated - DelegationKey = []byte{0x08} // prefix for each key to a delegator's bond - IntraTxCounterKey = []byte{0x09} // key for block-local tx index + ValidatorsByPubKeyKey = []byte{0x03} // prefix for each key to a validator by pubkey + ValidatorsBondedKey = []byte{0x04} // prefix for each key to bonded/actively validating validators + ValidatorsByPowerKey = []byte{0x05} // prefix for each key to a validator sorted by power + ValidatorCliffKey = []byte{0x06} // key for block-local tx index + ValidatorPowerCliffKey = []byte{0x07} // key for block-local tx index + TendermintUpdatesKey = []byte{0x08} // prefix for each key to a validator which is being updated + DelegationKey = []byte{0x09} // prefix for each key to a delegator's bond + IntraTxCounterKey = []byte{0x10} // key for block-local tx index ) const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch @@ -32,6 +33,11 @@ func GetValidatorKey(ownerAddr sdk.Address) []byte { return append(ValidatorsKey, ownerAddr.Bytes()...) } +// get the key for the validator with pubkey +func GetValidatorByPubKeyKey(pubkey crypto.PubKey) []byte { + return append(ValidatorsByPubKeyKey, pubkey.Bytes()...) +} + // get the key for the current validator group, ordered like tendermint func GetValidatorsBondedKey(pk crypto.PubKey) []byte { addr := pk.Address() From 66b4461543ef3ccd9572ac558611647d7607b976 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 24 May 2018 23:55:13 +0200 Subject: [PATCH 024/128] Update pointer-by-pubkey store on set and delete --- x/stake/keeper.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/x/stake/keeper.go b/x/stake/keeper.go index f46cc6f23a..83c5b0a0e8 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -64,8 +64,12 @@ func (k Keeper) getValidator(store sdk.KVStore, addr sdk.Address) (validator Val // set the main record holding validator details func (k Keeper) setValidator(ctx sdk.Context, validator Validator) { store := ctx.KVStore(k.storeKey) + // set main store bz := k.cdc.MustMarshalBinary(validator) store.Set(GetValidatorKey(validator.Owner), bz) + // set pointer by pubkey + bz = k.cdc.MustMarshalBinary(validator.Owner) + store.Set(GetValidatorByPubKeyKey(validator.PubKey), bz) } // Get the set of all validators with no limits, used during genesis dump @@ -483,6 +487,7 @@ func (k Keeper) removeValidator(ctx sdk.Context, address sdk.Address) { store := ctx.KVStore(k.storeKey) pool := k.getPool(store) store.Delete(GetValidatorKey(address)) + store.Delete(GetValidatorByPubKeyKey(validator.PubKey)) store.Delete(GetValidatorsByPowerKey(validator, pool)) // delete from the current and power weighted validator groups if the validator From 366d8f932356f63e72888764c8fcd33d9889b4eb Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 25 May 2018 00:12:40 +0200 Subject: [PATCH 025/128] Slash() and ForceUnbond() are functions of ValidatorSet, not Validator --- types/stake.go | 15 +++++++-------- x/slashing/keeper.go | 14 +++----------- x/stake/keeper.go | 8 ++++++++ x/stake/validator.go | 6 ------ 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/types/stake.go b/types/stake.go index 6e3d02c3d3..fed241d014 100644 --- a/types/stake.go +++ b/types/stake.go @@ -17,14 +17,11 @@ const ( // validator for a delegated proof of stake system type Validator interface { - GetStatus() BondStatus // status of the validator - GetOwner() Address // owner address to receive/return validators coins - GetPubKey() crypto.PubKey // validation pubkey - GetPower() Rat // validation power - GetBondHeight() int64 // height in which the validator became active - Slash(Context, int64, Rat) // slash the validator and delegators of the validator - // for an offense at a specified height by a specified fraction - ForceUnbond(Context, int64) // force unbond the validator, including a duration which must pass before they can rebond + GetStatus() BondStatus // status of the validator + GetOwner() Address // owner address to receive/return validators coins + GetPubKey() crypto.PubKey // validation pubkey + GetPower() Rat // validation power + GetBondHeight() int64 // height in which the validator became active } // validator which fulfills abci validator interface for use in Tendermint @@ -48,6 +45,8 @@ type ValidatorSet interface { Validator(Context, Address) Validator // get a particular validator by owner address ValidatorByPubKey(Context, crypto.PubKey) Validator // get a particular validator by public key TotalPower(Context) Rat // total power of the validator set + Slash(Context, crypto.PubKey, int64, Rat) // slash the validator and delegators of the validator, specifying offence height & slash fraction + ForceUnbond(Context, crypto.PubKey, int64) // force unbond the validator, including a duration which must pass before they can rebond } //_______________________________________________________________________________ diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 686f84b65c..17cf349ad3 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -71,11 +71,7 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, height int64, timestamp int64, return } logger.Info(fmt.Sprintf("Confirmed double sign from %v at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) - validator := k.stakeKeeper.ValidatorByPubKey(ctx, pubkey) - if validator == nil { - panic(fmt.Errorf("Attempted to slash nonexistent validator with address %s", pubkey.Address())) - } - validator.Slash(ctx, height, SlashFractionDoubleSign) + k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDoubleSign) logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v for double-sign at height %d", pubkey.Address(), SlashFractionDoubleSign, height)) } @@ -101,12 +97,8 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, } minHeight := signInfo.StartHeight + SignedBlocksWindow if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { - validator := k.stakeKeeper.ValidatorByPubKey(ctx, pubkey) - if validator == nil { - panic(fmt.Errorf("Attempted to slash nonexistent validator with address %s", pubkey.Address())) - } - validator.Slash(ctx, height, SlashFractionDowntime) - validator.ForceUnbond(ctx, DowntimeUnbondDuration) + k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDowntime) + k.stakeKeeper.ForceUnbond(ctx, pubkey, DowntimeUnbondDuration) logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v and unbonded for downtime at height %d, cannot rebond for %ds", address, SlashFractionDowntime, height, DowntimeUnbondDuration)) } diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 83c5b0a0e8..46790e8490 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -776,3 +776,11 @@ func (k Keeper) IterateDelegators(ctx sdk.Context, delAddr sdk.Address, fn func( } iterator.Close() } + +// slash a validator +func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, fraction sdk.Rat) { +} + +// force unbond a validator +func (k Keeper) ForceUnbond(ctx sdk.Context, pubkey crypto.PubKey, jailDuration int64) { +} diff --git a/x/stake/validator.go b/x/stake/validator.go index 7848724fd6..88f061f315 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -236,9 +236,3 @@ func (v Validator) GetOwner() sdk.Address { return v.Owner } func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } func (v Validator) GetPower() sdk.Rat { return v.PoolShares.Bonded() } func (v Validator) GetBondHeight() int64 { return v.BondHeight } -func (v Validator) Slash(ctx sdk.Context, height int64, fraction sdk.Rat) { - panic("not implemented") -} -func (v Validator) ForceUnbond(ctx sdk.Context, jailDuration int64) { - panic("not implemented") -} From 7da5833b8109e574e8e461827ff15785fb11b2da Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 25 May 2018 01:03:26 +0200 Subject: [PATCH 026/128] Implement ValidatorSet.Slash --- x/slashing/keeper.go | 3 --- x/slashing/keeper_test.go | 6 ++++-- x/stake/keeper.go | 20 ++++++++++++++++++++ x/stake/validator.go | 15 +++++++++++++++ 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 17cf349ad3..6ec093dc65 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -72,7 +72,6 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, height int64, timestamp int64, } logger.Info(fmt.Sprintf("Confirmed double sign from %v at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDoubleSign) - logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v for double-sign at height %d", pubkey.Address(), SlashFractionDoubleSign, height)) } // handle a validator signature, must be called once per validator per block @@ -99,8 +98,6 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDowntime) k.stakeKeeper.ForceUnbond(ctx, pubkey, DowntimeUnbondDuration) - logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v and unbonded for downtime at height %d, cannot rebond for %ds", - address, SlashFractionDowntime, height, DowntimeUnbondDuration)) } } diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index f360fd9e99..54461aa31e 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -2,6 +2,7 @@ package slashing import ( "encoding/hex" + "os" "testing" "github.com/stretchr/testify/require" @@ -52,7 +53,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db) err := ms.LoadLatestVersion() require.Nil(t, err) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewTMLogger(os.Stdout), nil) cdc := createTestCodec() accountMapper := auth.NewAccountMapper(cdc, keyAcc, &auth.BaseAccount{}) ck := bank.NewKeeper(accountMapper) @@ -74,8 +75,9 @@ func TestHandleDoubleSign(t *testing.T) { require.True(t, got.IsOK()) _ = sk.Tick(ctx) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) + require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) keeper.handleDoubleSign(ctx, 0, 0, val) - // TODO + require.Equal(t, sdk.NewRat(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) } func TestHandleAbsentValidator(t *testing.T) { diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 46790e8490..7d5073399b 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -779,8 +779,28 @@ func (k Keeper) IterateDelegators(ctx sdk.Context, delAddr sdk.Address, fn func( // slash a validator func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, fraction sdk.Rat) { + // TODO height ignored for now, see https://github.com/cosmos/cosmos-sdk/pull/1011#issuecomment-390253957 + val, found := k.GetValidatorByPubKey(ctx, pubkey) + if !found { + panic(fmt.Errorf("Attempted to slash a nonexistent validator with pubkey %s", pubkey)) + } + sharesToRemove := val.PoolShares.Amount.Mul(fraction) + pool := k.GetPool(ctx) + val, pool, burned := val.removePoolShares(pool, sharesToRemove) + k.setPool(ctx, pool) // update the pool + k.updateValidator(ctx, val) // update the validator, possibly kicking it out + ctx.Logger().With("module", "x/stake").Info(fmt.Sprintf("Validator %v slashed by fraction %v, removed %v shares and burned %d tokens", pubkey, fraction, sharesToRemove, burned)) + return } // force unbond a validator func (k Keeper) ForceUnbond(ctx sdk.Context, pubkey crypto.PubKey, jailDuration int64) { + // TODO Implement + /* + val, found := k.GetValidatorByPubKey(ctx, pubkey) + if !found { + ctx.Logger().Info("Validator with pubkey %s not found, cannot force unbond", pubkey) + return + } + */ } diff --git a/x/stake/validator.go b/x/stake/validator.go index 88f061f315..31ef290618 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -153,6 +153,21 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, return v, pool } +// Remove & burn pool shares, e.g. when slashing a validator +func (v Validator) removePoolShares(pool Pool, amt sdk.Rat) (Validator, Pool, int64) { + var tokens int64 + switch v.Status() { + case sdk.Unbonded: + pool, tokens = pool.removeSharesUnbonded(amt) + case sdk.Unbonding: + pool, tokens = pool.removeSharesUnbonding(amt) + case sdk.Bonded: + pool, tokens = pool.removeSharesBonded(amt) + } + v.PoolShares.Amount = v.PoolShares.Amount.Sub(amt) + return v, pool, tokens +} + // XXX TEST // get the power or potential power for a validator // if bonded, the power is the BondedShares From 14744cff20df53e93ac89679371c76da58f9901e Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 25 May 2018 01:07:18 +0200 Subject: [PATCH 027/128] Update for new Tendermint RPC interface --- client/tx/search.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/client/tx/search.go b/client/tx/search.go index 527661626a..672f29ff14 100644 --- a/client/tx/search.go +++ b/client/tx/search.go @@ -61,15 +61,12 @@ func searchTx(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]byte, } prove := !viper.GetBool(client.FlagTrustNode) - // TODO: take these as args - page := 0 - perPage := 100 - res, err := node.TxSearch(query, prove, page, perPage) + txs, err := node.TxSearch(query, prove) if err != nil { return nil, err } - info, err := formatTxResults(cdc, res.Txs) + info, err := formatTxResults(cdc, txs) if err != nil { return nil, err } From be4b140003874980e86ab180432e5a2ca8c99650 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 25 May 2018 01:30:43 +0200 Subject: [PATCH 028/128] Add testcase past max evidence age --- x/slashing/keeper_test.go | 5 ++++- x/stake/keeper.go | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 54461aa31e..3204ea7aa8 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -76,7 +76,10 @@ func TestHandleDoubleSign(t *testing.T) { _ = sk.Tick(ctx) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) - keeper.handleDoubleSign(ctx, 0, 0, val) + keeper.handleDoubleSign(ctx, 0, 0, val) // double sign less than max age + require.Equal(t, sdk.NewRat(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) + ctx = ctx.WithBlockHeader(abci.Header{Time: 300}) + keeper.handleDoubleSign(ctx, 0, 0, val) // double sign past max age require.Equal(t, sdk.NewRat(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) } diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 7d5073399b..00930aaa64 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -780,6 +780,7 @@ func (k Keeper) IterateDelegators(ctx sdk.Context, delAddr sdk.Address, fn func( // slash a validator func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, fraction sdk.Rat) { // TODO height ignored for now, see https://github.com/cosmos/cosmos-sdk/pull/1011#issuecomment-390253957 + logger := ctx.Logger().With("module", "x/stake") val, found := k.GetValidatorByPubKey(ctx, pubkey) if !found { panic(fmt.Errorf("Attempted to slash a nonexistent validator with pubkey %s", pubkey)) @@ -789,7 +790,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, fract val, pool, burned := val.removePoolShares(pool, sharesToRemove) k.setPool(ctx, pool) // update the pool k.updateValidator(ctx, val) // update the validator, possibly kicking it out - ctx.Logger().With("module", "x/stake").Info(fmt.Sprintf("Validator %v slashed by fraction %v, removed %v shares and burned %d tokens", pubkey, fraction, sharesToRemove, burned)) + logger.Info(fmt.Sprintf("Validator %v slashed by fraction %v, removed %v shares and burned %d tokens", pubkey, fraction, sharesToRemove, burned)) return } From 796948b838efab3c5b709709cdc9689f778540e1 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 25 May 2018 03:30:17 +0200 Subject: [PATCH 029/128] Downtime slashing testcases --- x/slashing/keeper.go | 4 ++-- x/slashing/keeper_test.go | 41 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 6ec093dc65..c940f60c31 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -36,9 +36,9 @@ var ( // TODO Governance parameter? SlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20)) - // SlashFractionDowntime - currently 0 + // SlashFractionDowntime - currently 1% // TODO Governance parameter? - SlashFractionDowntime = sdk.ZeroRat() + SlashFractionDowntime = sdk.NewRat(1).Quo(sdk.NewRat(100)) ) // Keeper of the slashing store diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 3204ea7aa8..429b14f937 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -84,7 +84,46 @@ func TestHandleDoubleSign(t *testing.T) { } func TestHandleAbsentValidator(t *testing.T) { - // TODO + ctx, ck, sk, keeper := createTestInput(t) + addr, val, amt := addrs[0], pks[0], int64(10) + got := stake.NewHandler(sk)(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) + require.True(t, got.IsOK()) + _ = sk.Tick(ctx) + require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) + require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) + info, found := keeper.getValidatorSigningInfo(ctx, val.Address()) + require.False(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, int64(0), info.SignedBlocksCounter) + height := int64(0) + // 1000 blocks OK + for ; height < 1000; height++ { + ctx = ctx.WithBlockHeight(height) + keeper.handleValidatorSignature(ctx, val, true) + } + info, found = keeper.getValidatorSigningInfo(ctx, val.Address()) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, SignedBlocksWindow, info.SignedBlocksCounter) + // 50 blocks missed + for ; height < 1050; height++ { + ctx = ctx.WithBlockHeight(height) + keeper.handleValidatorSignature(ctx, val, false) + } + info, found = keeper.getValidatorSigningInfo(ctx, val.Address()) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, SignedBlocksWindow-50, info.SignedBlocksCounter) + // 51st block missed + ctx = ctx.WithBlockHeight(height) + keeper.handleValidatorSignature(ctx, val, false) + info, found = keeper.getValidatorSigningInfo(ctx, val.Address()) + require.True(t, found) + require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter) + height++ + // should have been slashed + require.Equal(t, sdk.NewRat(amt).Mul(sdk.NewRat(99).Quo(sdk.NewRat(100))), sk.Validator(ctx, addr).GetPower()) } func newPubKey(pk string) (res crypto.PubKey) { From e614799d0f16479aa16e7a91e088ef65eea2e318 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Sat, 26 May 2018 00:13:29 +0200 Subject: [PATCH 030/128] ForceUnbond() implementation WIP --- x/slashing/keeper.go | 9 +++++---- x/slashing/keeper_test.go | 20 ++++++++++++++++++-- x/stake/errors.go | 6 ++++++ x/stake/handler.go | 25 +++++++++++++++++++++++++ x/stake/keeper.go | 26 ++++++++++++++++---------- x/stake/msg.go | 33 +++++++++++++++++++++++++++++++++ x/stake/validator.go | 9 ++++++--- x/stake/wire.go | 1 + 8 files changed, 110 insertions(+), 19 deletions(-) diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index c940f60c31..b64bd6e06b 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -67,10 +67,10 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, height int64, timestamp int64, logger := ctx.Logger().With("module", "x/slashing") age := ctx.BlockHeader().Time - timestamp if age > MaxEvidenceAge { - logger.Info(fmt.Sprintf("Ignored double sign from %v at height %d, age of %d past max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) + logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) return } - logger.Info(fmt.Sprintf("Confirmed double sign from %v at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) + logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDoubleSign) } @@ -79,7 +79,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, logger := ctx.Logger().With("module", "x/slashing") height := ctx.BlockHeight() if !signed { - logger.Info(fmt.Sprintf("Absent validator %v at height %d", pubkey.Address(), height)) + logger.Info(fmt.Sprintf("Absent validator %s at height %d", pubkey.Address(), height)) } index := height % SignedBlocksWindow address := pubkey.Address() @@ -96,8 +96,9 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, } minHeight := signInfo.StartHeight + SignedBlocksWindow if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { + logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, MinSignedPerWindow)) k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDowntime) - k.stakeKeeper.ForceUnbond(ctx, pubkey, DowntimeUnbondDuration) + k.stakeKeeper.ForceUnbond(ctx, pubkey, DowntimeUnbondDuration) // TODO } } diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 429b14f937..dd4bb4cd69 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -58,7 +58,9 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep accountMapper := auth.NewAccountMapper(cdc, keyAcc, &auth.BaseAccount{}) ck := bank.NewKeeper(accountMapper) sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) - stake.InitGenesis(ctx, sk, stake.DefaultGenesisState()) + genesis := stake.DefaultGenesisState() + genesis.Pool.BondedTokens = initCoins * int64(len(addrs)) + stake.InitGenesis(ctx, sk, genesis) for _, addr := range addrs { ck.AddCoins(ctx, addr, sdk.Coins{ {sk.GetParams(ctx).BondDenom, initCoins}, @@ -86,7 +88,8 @@ func TestHandleDoubleSign(t *testing.T) { func TestHandleAbsentValidator(t *testing.T) { ctx, ck, sk, keeper := createTestInput(t) addr, val, amt := addrs[0], pks[0], int64(10) - got := stake.NewHandler(sk)(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) + sh := stake.NewHandler(sk) + got := sh(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) require.True(t, got.IsOK()) _ = sk.Tick(ctx) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) @@ -114,6 +117,9 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, SignedBlocksWindow-50, info.SignedBlocksCounter) + // should be bonded still + validator := sk.ValidatorByPubKey(ctx, val) + require.Equal(t, sdk.Bonded, validator.GetStatus()) // 51st block missed ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, false) @@ -122,6 +128,16 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, int64(0), info.StartHeight) require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter) height++ + // should have been revoked + validator = sk.ValidatorByPubKey(ctx, val) + require.Equal(t, sdk.Unbonded, validator.GetStatus()) + got = sh(ctx, stake.NewMsgUnrevoke(addr)) + require.False(t, got.IsOK()) // should fail prior to jail expiration + ctx = ctx.WithBlockHeader(abci.Header{Time: int64(86400 * 2)}) + got = sh(ctx, stake.NewMsgUnrevoke(addr)) + require.True(t, got.IsOK()) // should succeed after jail expiration + validator = sk.ValidatorByPubKey(ctx, val) + require.Equal(t, sdk.Bonded, validator.GetStatus()) // should have been slashed require.Equal(t, sdk.NewRat(amt).Mul(sdk.NewRat(99).Quo(sdk.NewRat(100))), sk.Validator(ctx, addr).GetPower()) } diff --git a/x/stake/errors.go b/x/stake/errors.go index 83c38d528d..2664a56cad 100644 --- a/x/stake/errors.go +++ b/x/stake/errors.go @@ -16,6 +16,7 @@ const ( CodeInvalidValidator CodeType = 201 CodeInvalidBond CodeType = 202 CodeInvalidInput CodeType = 203 + CodeValidatorJailed CodeType = 204 CodeUnauthorized CodeType = sdk.CodeUnauthorized CodeInternal CodeType = sdk.CodeInternal CodeUnknownRequest CodeType = sdk.CodeUnknownRequest @@ -30,6 +31,8 @@ func codeToDefaultMsg(code CodeType) string { return "Invalid Bond" case CodeInvalidInput: return "Invalid Input" + case CodeValidatorJailed: + return "Validator Jailed" case CodeUnauthorized: return "Unauthorized" case CodeInternal: @@ -98,6 +101,9 @@ func ErrBadShares(codespace sdk.CodespaceType) sdk.Error { func ErrBadRemoveValidator(codespace sdk.CodespaceType) sdk.Error { return newError(codespace, CodeInvalidValidator, "Error removing validator") } +func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeValidatorJailed, "Validator jailed, cannot yet be unrevoked") +} //---------------------------------------- diff --git a/x/stake/handler.go b/x/stake/handler.go index 53653557cc..62c4f27df4 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -19,6 +19,8 @@ func NewHandler(k Keeper) sdk.Handler { return handleMsgDelegate(ctx, msg, k) case MsgUnbond: return handleMsgUnbond(ctx, msg, k) + case MsgUnrevoke: + return handleMsgUnrevoke(ctx, msg, k) default: return sdk.ErrTxDecode("invalid message parse in staking module").Result() } @@ -247,3 +249,26 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result { Tags: tags, } } + +func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { + validator, found := k.GetValidator(ctx, msg.ValidatorAddr) + if !found { + return ErrNoValidatorForAddress(k.codespace).Result() + } + + if ctx.BlockHeader().Time < validator.RevokedUntilTime { + return ErrValidatorJailed(k.codespace).Result() + } + + if ctx.IsCheckTx() { + return sdk.Result{} + } + + validator.Revoked = false + k.updateValidator(ctx, validator) + + tags := sdk.NewTags("action", []byte("unrevoke"), "validator", msg.ValidatorAddr.Bytes()) + return sdk.Result{ + Tags: tags, + } +} diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 00930aaa64..887cdab192 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -220,7 +220,9 @@ func (k Keeper) updateValidator(ctx sdk.Context, validator Validator) Validator oldValidator, oldFound := k.GetValidator(ctx, ownerAddr) if validator.Revoked && oldValidator.Status() == sdk.Bonded { + fmt.Printf("val preupdate: %v\n", validator) validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) + fmt.Printf("val postupdate: %v\n", validator) k.setPool(ctx, pool) } @@ -783,25 +785,29 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, fract logger := ctx.Logger().With("module", "x/stake") val, found := k.GetValidatorByPubKey(ctx, pubkey) if !found { - panic(fmt.Errorf("Attempted to slash a nonexistent validator with pubkey %s", pubkey)) + panic(fmt.Errorf("Attempted to slash a nonexistent validator with address %s", pubkey.Address())) } sharesToRemove := val.PoolShares.Amount.Mul(fraction) pool := k.GetPool(ctx) val, pool, burned := val.removePoolShares(pool, sharesToRemove) k.setPool(ctx, pool) // update the pool k.updateValidator(ctx, val) // update the validator, possibly kicking it out - logger.Info(fmt.Sprintf("Validator %v slashed by fraction %v, removed %v shares and burned %d tokens", pubkey, fraction, sharesToRemove, burned)) + logger.Info(fmt.Sprintf("Validator %s slashed by fraction %v, removed %v shares and burned %d tokens", pubkey.Address(), fraction, sharesToRemove, burned)) return } // force unbond a validator func (k Keeper) ForceUnbond(ctx sdk.Context, pubkey crypto.PubKey, jailDuration int64) { - // TODO Implement - /* - val, found := k.GetValidatorByPubKey(ctx, pubkey) - if !found { - ctx.Logger().Info("Validator with pubkey %s not found, cannot force unbond", pubkey) - return - } - */ + logger := ctx.Logger().With("module", "x/stake") + val, found := k.GetValidatorByPubKey(ctx, pubkey) + if !found { + ctx.Logger().Info("Validator with pubkey %s not found, cannot force unbond", pubkey) + return + } + val.Revoked = true + val.RevokedUntilTime = ctx.BlockHeader().Time + jailDuration + k.updateValidator(ctx, val) // update the validator, now revoked + val, _ = k.GetValidatorByPubKey(ctx, pubkey) + logger.Info(fmt.Sprintf("Validator %s revoked for minimum duration %d", pubkey.Address(), jailDuration)) + return } diff --git a/x/stake/msg.go b/x/stake/msg.go index 0adff84d9b..a668d47d18 100644 --- a/x/stake/msg.go +++ b/x/stake/msg.go @@ -209,3 +209,36 @@ func (msg MsgUnbond) ValidateBasic() sdk.Error { } return nil } + +//______________________________________________________________________ + +// MsgUnrevoke - struct for unrevoking revoked validator +type MsgUnrevoke struct { + ValidatorAddr sdk.Address `json:"address"` +} + +func NewMsgUnrevoke(validatorAddr sdk.Address) MsgUnrevoke { + return MsgUnrevoke{ + ValidatorAddr: validatorAddr, + } +} + +func (msg MsgUnrevoke) Type() string { return MsgType } +func (msg MsgUnrevoke) GetSigners() []sdk.Address { return []sdk.Address{msg.ValidatorAddr} } + +// get the bytes for the message signer to sign on +func (msg MsgUnrevoke) GetSignBytes() []byte { + b, err := json.Marshal(msg) + if err != nil { + panic(err) + } + return b +} + +// quick validity check +func (msg MsgUnrevoke) ValidateBasic() sdk.Error { + if msg.ValidatorAddr == nil { + return ErrBadValidatorAddr(DefaultCodespace) + } + return nil +} diff --git a/x/stake/validator.go b/x/stake/validator.go index 31ef290618..76905212f1 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -17,9 +17,10 @@ import ( // exchange rate. Voting power can be calculated as total bonds multiplied by // exchange rate. type Validator struct { - Owner sdk.Address `json:"owner"` // sender of BondTx - UnbondTx returns here - PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator - Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? + Owner sdk.Address `json:"owner"` // sender of BondTx - UnbondTx returns here + PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator + Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? + RevokedUntilTime int64 `json:"revoked_until_time"` // timestamp before which the validator cannot unrevoke PoolShares PoolShares `json:"pool_shares"` // total shares for tokens held in the pool DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators @@ -46,6 +47,8 @@ func NewValidator(owner sdk.Address, pubKey crypto.PubKey, description Descripti return Validator{ Owner: owner, PubKey: pubKey, + Revoked: false, + RevokedUntilTime: int64(0), PoolShares: NewUnbondedShares(sdk.ZeroRat()), DelegatorShares: sdk.ZeroRat(), Description: description, diff --git a/x/stake/wire.go b/x/stake/wire.go index 6e6e382606..ac382ff14d 100644 --- a/x/stake/wire.go +++ b/x/stake/wire.go @@ -10,6 +10,7 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(MsgEditCandidacy{}, "cosmos-sdk/MsgEditCandidacy", nil) cdc.RegisterConcrete(MsgDelegate{}, "cosmos-sdk/MsgDelegate", nil) cdc.RegisterConcrete(MsgUnbond{}, "cosmos-sdk/MsgUnbond", nil) + cdc.RegisterConcrete(MsgUnrevoke{}, "cosmos-sdk/MsgUnrevoke", nil) } var cdcEmpty = wire.NewCodec() From 97b084b842f4b10369de78439531440168a8401a Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Sat, 26 May 2018 00:27:02 +0200 Subject: [PATCH 031/128] Fix ForceUnbond() testcase --- x/slashing/keeper_test.go | 5 ++++- x/stake/keeper.go | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index dd4bb4cd69..7c7be34e8c 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -120,6 +120,8 @@ func TestHandleAbsentValidator(t *testing.T) { // should be bonded still validator := sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) + pool := sk.GetPool(ctx) + require.Equal(t, int64(210), pool.BondedTokens) // 51st block missed ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, false) @@ -138,8 +140,9 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, got.IsOK()) // should succeed after jail expiration validator = sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) + pool = sk.GetPool(ctx) // should have been slashed - require.Equal(t, sdk.NewRat(amt).Mul(sdk.NewRat(99).Quo(sdk.NewRat(100))), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, int64(208), pool.BondedTokens) } func newPubKey(pk string) (res crypto.PubKey) { diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 887cdab192..e8ac6947c8 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -220,9 +220,7 @@ func (k Keeper) updateValidator(ctx sdk.Context, validator Validator) Validator oldValidator, oldFound := k.GetValidator(ctx, ownerAddr) if validator.Revoked && oldValidator.Status() == sdk.Bonded { - fmt.Printf("val preupdate: %v\n", validator) validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) - fmt.Printf("val postupdate: %v\n", validator) k.setPool(ctx, pool) } From 8aaff4b96e29010d7013fa29757959f30331858a Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Sat, 26 May 2018 00:36:12 +0200 Subject: [PATCH 032/128] Cleanup testcase a bit --- x/slashing/keeper_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 7c7be34e8c..895be24e1b 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -29,7 +29,7 @@ var ( newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"), newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), } - initCoins int64 = 100 + initCoins int64 = 200 ) func createTestCodec() *wire.Codec { @@ -59,7 +59,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep ck := bank.NewKeeper(accountMapper) sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) genesis := stake.DefaultGenesisState() - genesis.Pool.BondedTokens = initCoins * int64(len(addrs)) + genesis.Pool.LooseUnbondedTokens = initCoins * int64(len(addrs)) stake.InitGenesis(ctx, sk, genesis) for _, addr := range addrs { ck.AddCoins(ctx, addr, sdk.Coins{ @@ -72,7 +72,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep func TestHandleDoubleSign(t *testing.T) { ctx, ck, sk, keeper := createTestInput(t) - addr, val, amt := addrs[0], pks[0], int64(10) + addr, val, amt := addrs[0], pks[0], int64(100) got := stake.NewHandler(sk)(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) require.True(t, got.IsOK()) _ = sk.Tick(ctx) @@ -87,7 +87,7 @@ func TestHandleDoubleSign(t *testing.T) { func TestHandleAbsentValidator(t *testing.T) { ctx, ck, sk, keeper := createTestInput(t) - addr, val, amt := addrs[0], pks[0], int64(10) + addr, val, amt := addrs[0], pks[0], int64(100) sh := stake.NewHandler(sk) got := sh(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) require.True(t, got.IsOK()) @@ -121,7 +121,7 @@ func TestHandleAbsentValidator(t *testing.T) { validator := sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) pool := sk.GetPool(ctx) - require.Equal(t, int64(210), pool.BondedTokens) + require.Equal(t, int64(100), pool.BondedTokens) // 51st block missed ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, false) @@ -140,9 +140,9 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, got.IsOK()) // should succeed after jail expiration validator = sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) - pool = sk.GetPool(ctx) // should have been slashed - require.Equal(t, int64(208), pool.BondedTokens) + pool = sk.GetPool(ctx) + require.Equal(t, int64(99), pool.BondedTokens) } func newPubKey(pk string) (res crypto.PubKey) { From 9cfc6de055b7704914ed4d0f613915e05472c77e Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Sat, 26 May 2018 01:34:16 +0200 Subject: [PATCH 033/128] Linter fix --- x/stake/msg.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/stake/msg.go b/x/stake/msg.go index a668d47d18..c0fdb4e5a1 100644 --- a/x/stake/msg.go +++ b/x/stake/msg.go @@ -223,6 +223,7 @@ func NewMsgUnrevoke(validatorAddr sdk.Address) MsgUnrevoke { } } +//nolint func (msg MsgUnrevoke) Type() string { return MsgType } func (msg MsgUnrevoke) GetSigners() []sdk.Address { return []sdk.Address{msg.ValidatorAddr} } From 6f3d81d5d6368af3d9059e55353a1037d228032d Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Sat, 26 May 2018 02:05:46 +0200 Subject: [PATCH 034/128] Swap to individual offset --- x/slashing/keeper.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index b64bd6e06b..87016b18f2 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -81,9 +81,10 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, if !signed { logger.Info(fmt.Sprintf("Absent validator %s at height %d", pubkey.Address(), height)) } - index := height % SignedBlocksWindow address := pubkey.Address() signInfo, _ := k.getValidatorSigningInfo(ctx, address) + signInfo.IndexOffset++ + index := signInfo.IndexOffset % SignedBlocksWindow previous := k.getValidatorSigningBitArray(ctx, address, index) if previous && !signed { k.setValidatorSigningBitArray(ctx, address, index, false) @@ -140,6 +141,7 @@ func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.Address type validatorSigningInfo struct { StartHeight int64 `json:"start_height"` + IndexOffset int64 `json:"index_offset"` SignedBlocksCounter int64 `json:"signed_blocks_counter"` } From e4b0d0a618524d3040788b1d9cb8b3c33753a4c4 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 28 May 2018 21:38:02 +0200 Subject: [PATCH 035/128] Reorganization in progress --- cmd/gaia/app/app.go | 1 + types/stake.go | 3 ++- x/slashing/errors.go | 19 +++++++++++++++++ x/slashing/handler.go | 42 ++++++++++++++++++++++++++++++++++++ x/slashing/keeper.go | 2 +- x/slashing/keeper_test.go | 5 +++-- x/slashing/msg.go | 45 +++++++++++++++++++++++++++++++++++++++ x/slashing/wire.go | 12 +++++++++++ x/stake/errors.go | 5 ----- x/stake/handler.go | 25 ---------------------- x/stake/keeper.go | 22 ++++++++++++++----- x/stake/msg.go | 34 ----------------------------- x/stake/validator.go | 8 +++---- x/stake/wire.go | 1 - 14 files changed, 145 insertions(+), 79 deletions(-) create mode 100644 x/slashing/handler.go create mode 100644 x/slashing/msg.go create mode 100644 x/slashing/wire.go diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 28904e1ac9..4fdb6a6c92 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -103,6 +103,7 @@ func MakeCodec() *wire.Codec { ibc.RegisterWire(cdc) bank.RegisterWire(cdc) stake.RegisterWire(cdc) + slashing.RegisterWire(cdc) auth.RegisterWire(cdc) sdk.RegisterWire(cdc) wire.RegisterCrypto(cdc) diff --git a/types/stake.go b/types/stake.go index fed241d014..a52dc9b071 100644 --- a/types/stake.go +++ b/types/stake.go @@ -46,7 +46,8 @@ type ValidatorSet interface { ValidatorByPubKey(Context, crypto.PubKey) Validator // get a particular validator by public key TotalPower(Context) Rat // total power of the validator set Slash(Context, crypto.PubKey, int64, Rat) // slash the validator and delegators of the validator, specifying offence height & slash fraction - ForceUnbond(Context, crypto.PubKey, int64) // force unbond the validator, including a duration which must pass before they can rebond + Revoke(Context, crypto.PubKey) // revoke a validator + Unrevoke(Context, crypto.PubKey) // unrevoke a validator } //_______________________________________________________________________________ diff --git a/x/slashing/errors.go b/x/slashing/errors.go index bf57c337d7..f61eff17e5 100644 --- a/x/slashing/errors.go +++ b/x/slashing/errors.go @@ -10,10 +10,29 @@ type CodeType = sdk.CodeType const ( // Default slashing codespace DefaultCodespace sdk.CodespaceType = 10 + + // Invalid validator + CodeInvalidValidator CodeType = 201 + // Validator jailed + CodeValidatorJailed CodeType = 202 ) +func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "That address is not associated with any known validator") +} +func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Validator does not exist for that address") +} +func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeValidatorJailed, "Validator jailed, cannot yet be unrevoked") +} + func codeToDefaultMsg(code CodeType) string { switch code { + case CodeInvalidValidator: + return "Invalid Validator" + case CodeValidatorJailed: + return "Validator Jailed" default: return sdk.CodeToDefaultMsg(code) } diff --git a/x/slashing/handler.go b/x/slashing/handler.go new file mode 100644 index 0000000000..931ef58465 --- /dev/null +++ b/x/slashing/handler.go @@ -0,0 +1,42 @@ +package slashing + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func NewHandler(k Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + // NOTE msg already has validate basic run + switch msg := msg.(type) { + case MsgUnrevoke: + return handleMsgUnrevoke(ctx, msg, k) + default: + return sdk.ErrTxDecode("invalid message parse in staking module").Result() + } + } +} + +func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { + validator := k.stakeKeeper.Validator(ctx, msg.ValidatorAddr) + if validator == nil { + return ErrNoValidatorForAddress(k.codespace).Result() + } + + // TODO + /* + if ctx.BlockHeader().Time < validator.RevokedUntilTime { + return ErrValidatorJailed(k.codespace).Result() + } + */ + + if ctx.IsCheckTx() { + return sdk.Result{} + } + + k.stakeKeeper.Unrevoke(ctx, validator.GetPubKey()) + + tags := sdk.NewTags("action", []byte("unrevoke"), "validator", msg.ValidatorAddr.Bytes()) + return sdk.Result{ + Tags: tags, + } +} diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 87016b18f2..918e85c2a3 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -99,7 +99,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, MinSignedPerWindow)) k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDowntime) - k.stakeKeeper.ForceUnbond(ctx, pubkey, DowntimeUnbondDuration) // TODO + k.stakeKeeper.Revoke(ctx, pubkey) // , DowntimeUnbondDuration) // TODO } } diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 895be24e1b..9598b24f3c 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -89,6 +89,7 @@ func TestHandleAbsentValidator(t *testing.T) { ctx, ck, sk, keeper := createTestInput(t) addr, val, amt := addrs[0], pks[0], int64(100) sh := stake.NewHandler(sk) + slh := NewHandler(keeper) got := sh(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) require.True(t, got.IsOK()) _ = sk.Tick(ctx) @@ -133,10 +134,10 @@ func TestHandleAbsentValidator(t *testing.T) { // should have been revoked validator = sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Unbonded, validator.GetStatus()) - got = sh(ctx, stake.NewMsgUnrevoke(addr)) + got = slh(ctx, NewMsgUnrevoke(addr)) require.False(t, got.IsOK()) // should fail prior to jail expiration ctx = ctx.WithBlockHeader(abci.Header{Time: int64(86400 * 2)}) - got = sh(ctx, stake.NewMsgUnrevoke(addr)) + got = slh(ctx, NewMsgUnrevoke(addr)) require.True(t, got.IsOK()) // should succeed after jail expiration validator = sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) diff --git a/x/slashing/msg.go b/x/slashing/msg.go new file mode 100644 index 0000000000..d67ddf70df --- /dev/null +++ b/x/slashing/msg.go @@ -0,0 +1,45 @@ +package slashing + +import ( + "encoding/json" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// name to identify transaction types +const MsgType = "slashing" + +// verify interface at compile time +var _ sdk.Msg = &MsgUnrevoke{} + +// MsgUnrevoke - struct for unrevoking revoked validator +type MsgUnrevoke struct { + ValidatorAddr sdk.Address `json:"address"` +} + +func NewMsgUnrevoke(validatorAddr sdk.Address) MsgUnrevoke { + return MsgUnrevoke{ + ValidatorAddr: validatorAddr, + } +} + +//nolint +func (msg MsgUnrevoke) Type() string { return MsgType } +func (msg MsgUnrevoke) GetSigners() []sdk.Address { return []sdk.Address{msg.ValidatorAddr} } + +// get the bytes for the message signer to sign on +func (msg MsgUnrevoke) GetSignBytes() []byte { + b, err := json.Marshal(msg) + if err != nil { + panic(err) + } + return b +} + +// quick validity check +func (msg MsgUnrevoke) ValidateBasic() sdk.Error { + if msg.ValidatorAddr == nil { + return ErrBadValidatorAddr(DefaultCodespace) + } + return nil +} diff --git a/x/slashing/wire.go b/x/slashing/wire.go new file mode 100644 index 0000000000..465a06587e --- /dev/null +++ b/x/slashing/wire.go @@ -0,0 +1,12 @@ +package slashing + +import ( + "github.com/cosmos/cosmos-sdk/wire" +) + +// Register concrete types on wire codec +func RegisterWire(cdc *wire.Codec) { + cdc.RegisterConcrete(MsgUnrevoke{}, "cosmos-sdk/MsgUnrevoke", nil) +} + +var cdcEmpty = wire.NewCodec() diff --git a/x/stake/errors.go b/x/stake/errors.go index 2664a56cad..77090d9dc3 100644 --- a/x/stake/errors.go +++ b/x/stake/errors.go @@ -31,8 +31,6 @@ func codeToDefaultMsg(code CodeType) string { return "Invalid Bond" case CodeInvalidInput: return "Invalid Input" - case CodeValidatorJailed: - return "Validator Jailed" case CodeUnauthorized: return "Unauthorized" case CodeInternal: @@ -101,9 +99,6 @@ func ErrBadShares(codespace sdk.CodespaceType) sdk.Error { func ErrBadRemoveValidator(codespace sdk.CodespaceType) sdk.Error { return newError(codespace, CodeInvalidValidator, "Error removing validator") } -func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { - return newError(codespace, CodeValidatorJailed, "Validator jailed, cannot yet be unrevoked") -} //---------------------------------------- diff --git a/x/stake/handler.go b/x/stake/handler.go index 62c4f27df4..53653557cc 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -19,8 +19,6 @@ func NewHandler(k Keeper) sdk.Handler { return handleMsgDelegate(ctx, msg, k) case MsgUnbond: return handleMsgUnbond(ctx, msg, k) - case MsgUnrevoke: - return handleMsgUnrevoke(ctx, msg, k) default: return sdk.ErrTxDecode("invalid message parse in staking module").Result() } @@ -249,26 +247,3 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result { Tags: tags, } } - -func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { - validator, found := k.GetValidator(ctx, msg.ValidatorAddr) - if !found { - return ErrNoValidatorForAddress(k.codespace).Result() - } - - if ctx.BlockHeader().Time < validator.RevokedUntilTime { - return ErrValidatorJailed(k.codespace).Result() - } - - if ctx.IsCheckTx() { - return sdk.Result{} - } - - validator.Revoked = false - k.updateValidator(ctx, validator) - - tags := sdk.NewTags("action", []byte("unrevoke"), "validator", msg.ValidatorAddr.Bytes()) - return sdk.Result{ - Tags: tags, - } -} diff --git a/x/stake/keeper.go b/x/stake/keeper.go index e8ac6947c8..aba118ed5a 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -794,8 +794,8 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, fract return } -// force unbond a validator -func (k Keeper) ForceUnbond(ctx sdk.Context, pubkey crypto.PubKey, jailDuration int64) { +// revoke a validator +func (k Keeper) Revoke(ctx sdk.Context, pubkey crypto.PubKey) { logger := ctx.Logger().With("module", "x/stake") val, found := k.GetValidatorByPubKey(ctx, pubkey) if !found { @@ -803,9 +803,21 @@ func (k Keeper) ForceUnbond(ctx sdk.Context, pubkey crypto.PubKey, jailDuration return } val.Revoked = true - val.RevokedUntilTime = ctx.BlockHeader().Time + jailDuration k.updateValidator(ctx, val) // update the validator, now revoked - val, _ = k.GetValidatorByPubKey(ctx, pubkey) - logger.Info(fmt.Sprintf("Validator %s revoked for minimum duration %d", pubkey.Address(), jailDuration)) + logger.Info(fmt.Sprintf("Validator %s revoked", pubkey.Address())) + return +} + +// unrevoke a validator +func (k Keeper) Unrevoke(ctx sdk.Context, pubkey crypto.PubKey) { + logger := ctx.Logger().With("module", "x/stake") + val, found := k.GetValidatorByPubKey(ctx, pubkey) + if !found { + ctx.Logger().Info("Validator with pubkey %s not found, cannot force unbond", pubkey) + return + } + val.Revoked = false + k.updateValidator(ctx, val) // update the validator, now unrevoked + logger.Info(fmt.Sprintf("Validator %s unrevoked", pubkey.Address())) return } diff --git a/x/stake/msg.go b/x/stake/msg.go index c0fdb4e5a1..0adff84d9b 100644 --- a/x/stake/msg.go +++ b/x/stake/msg.go @@ -209,37 +209,3 @@ func (msg MsgUnbond) ValidateBasic() sdk.Error { } return nil } - -//______________________________________________________________________ - -// MsgUnrevoke - struct for unrevoking revoked validator -type MsgUnrevoke struct { - ValidatorAddr sdk.Address `json:"address"` -} - -func NewMsgUnrevoke(validatorAddr sdk.Address) MsgUnrevoke { - return MsgUnrevoke{ - ValidatorAddr: validatorAddr, - } -} - -//nolint -func (msg MsgUnrevoke) Type() string { return MsgType } -func (msg MsgUnrevoke) GetSigners() []sdk.Address { return []sdk.Address{msg.ValidatorAddr} } - -// get the bytes for the message signer to sign on -func (msg MsgUnrevoke) GetSignBytes() []byte { - b, err := json.Marshal(msg) - if err != nil { - panic(err) - } - return b -} - -// quick validity check -func (msg MsgUnrevoke) ValidateBasic() sdk.Error { - if msg.ValidatorAddr == nil { - return ErrBadValidatorAddr(DefaultCodespace) - } - return nil -} diff --git a/x/stake/validator.go b/x/stake/validator.go index 76905212f1..20f5710569 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -17,10 +17,9 @@ import ( // exchange rate. Voting power can be calculated as total bonds multiplied by // exchange rate. type Validator struct { - Owner sdk.Address `json:"owner"` // sender of BondTx - UnbondTx returns here - PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator - Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? - RevokedUntilTime int64 `json:"revoked_until_time"` // timestamp before which the validator cannot unrevoke + Owner sdk.Address `json:"owner"` // sender of BondTx - UnbondTx returns here + PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator + Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? PoolShares PoolShares `json:"pool_shares"` // total shares for tokens held in the pool DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators @@ -48,7 +47,6 @@ func NewValidator(owner sdk.Address, pubKey crypto.PubKey, description Descripti Owner: owner, PubKey: pubKey, Revoked: false, - RevokedUntilTime: int64(0), PoolShares: NewUnbondedShares(sdk.ZeroRat()), DelegatorShares: sdk.ZeroRat(), Description: description, diff --git a/x/stake/wire.go b/x/stake/wire.go index ac382ff14d..6e6e382606 100644 --- a/x/stake/wire.go +++ b/x/stake/wire.go @@ -10,7 +10,6 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(MsgEditCandidacy{}, "cosmos-sdk/MsgEditCandidacy", nil) cdc.RegisterConcrete(MsgDelegate{}, "cosmos-sdk/MsgDelegate", nil) cdc.RegisterConcrete(MsgUnbond{}, "cosmos-sdk/MsgUnbond", nil) - cdc.RegisterConcrete(MsgUnrevoke{}, "cosmos-sdk/MsgUnrevoke", nil) } var cdcEmpty = wire.NewCodec() From d03577a2fc312cc1b260a3d6a59dab1bfa1d56a4 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 28 May 2018 22:08:13 +0200 Subject: [PATCH 036/128] Fixes after rebase, jail in x/slashing --- x/auth/context_test.go | 2 +- x/auth/feekeeper_test.go | 6 +++--- x/slashing/handler.go | 14 ++++++++------ x/slashing/keeper.go | 5 ++++- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/x/auth/context_test.go b/x/auth/context_test.go index c4aaca269a..615b7d5196 100644 --- a/x/auth/context_test.go +++ b/x/auth/context_test.go @@ -12,7 +12,7 @@ import ( ) func TestContextWithSigners(t *testing.T) { - ms, _ := setupMultiStore() + ms, _, _ := setupMultiStore() ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) _, _, addr1 := keyPubAddr() diff --git a/x/auth/feekeeper_test.go b/x/auth/feekeeper_test.go index 2f1ffc59bc..3c9190e4ec 100644 --- a/x/auth/feekeeper_test.go +++ b/x/auth/feekeeper_test.go @@ -23,7 +23,7 @@ func TestFeeCollectionKeeperGetSet(t *testing.T) { cdc := wire.NewCodec() // make context and keeper - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) fck := NewFeeCollectionKeeper(cdc, capKey2) // no coins initially @@ -42,7 +42,7 @@ func TestFeeCollectionKeeperAdd(t *testing.T) { cdc := wire.NewCodec() // make context and keeper - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) fck := NewFeeCollectionKeeper(cdc, capKey2) // no coins initially @@ -62,7 +62,7 @@ func TestFeeCollectionKeeperClear(t *testing.T) { cdc := wire.NewCodec() // make context and keeper - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) fck := NewFeeCollectionKeeper(cdc, capKey2) // set coins initially diff --git a/x/slashing/handler.go b/x/slashing/handler.go index 931ef58465..e1d6607898 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -22,12 +22,14 @@ func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { return ErrNoValidatorForAddress(k.codespace).Result() } - // TODO - /* - if ctx.BlockHeader().Time < validator.RevokedUntilTime { - return ErrValidatorJailed(k.codespace).Result() - } - */ + info, found := k.getValidatorSigningInfo(ctx, validator.GetPubKey().Address()) + if !found { + return ErrNoValidatorForAddress(k.codespace).Result() + } + + if ctx.BlockHeader().Time < info.JailedUntil { + return ErrValidatorJailed(k.codespace).Result() + } if ctx.IsCheckTx() { return sdk.Result{} diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 918e85c2a3..4c9d92a2fa 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -99,7 +99,9 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, MinSignedPerWindow)) k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDowntime) - k.stakeKeeper.Revoke(ctx, pubkey) // , DowntimeUnbondDuration) // TODO + k.stakeKeeper.Revoke(ctx, pubkey) + signInfo.JailedUntil = ctx.BlockHeader().Time + DowntimeUnbondDuration + k.setValidatorSigningInfo(ctx, address, signInfo) } } @@ -142,6 +144,7 @@ func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.Address type validatorSigningInfo struct { StartHeight int64 `json:"start_height"` IndexOffset int64 `json:"index_offset"` + JailedUntil int64 `json:"jailed_until"` SignedBlocksCounter int64 `json:"signed_blocks_counter"` } From bfa9d5f9142d1d196c3b56c4f64d3deef3f8932f Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 28 May 2018 22:12:45 +0200 Subject: [PATCH 037/128] Linter fixes --- x/slashing/errors.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/x/slashing/errors.go b/x/slashing/errors.go index f61eff17e5..8a923f7542 100644 --- a/x/slashing/errors.go +++ b/x/slashing/errors.go @@ -17,12 +17,17 @@ const ( CodeValidatorJailed CodeType = 202 ) +//nolint func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error { return newError(codespace, CodeInvalidValidator, "That address is not associated with any known validator") } + +//nolint func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { return newError(codespace, CodeInvalidValidator, "Validator does not exist for that address") } + +//nolint func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { return newError(codespace, CodeValidatorJailed, "Validator jailed, cannot yet be unrevoked") } From 93f1cb45cc242f55b1c5b683eab026354b8e9305 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 28 May 2018 23:24:58 +0200 Subject: [PATCH 038/128] Split slashing params & signing info into separate files --- x/slashing/keeper.go | 85 -------------------------------------- x/slashing/params.go | 37 +++++++++++++++++ x/slashing/signing_info.go | 60 +++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 85 deletions(-) create mode 100644 x/slashing/params.go create mode 100644 x/slashing/signing_info.go diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 4c9d92a2fa..c8fcbe1b92 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -1,7 +1,6 @@ package slashing import ( - "encoding/binary" "fmt" sdk "github.com/cosmos/cosmos-sdk/types" @@ -10,37 +9,6 @@ import ( crypto "github.com/tendermint/go-crypto" ) -const ( - // MaxEvidenceAge - Max age for evidence - 21 days (3 weeks) - // TODO Should this be a governance parameter or just modifiable with SoftwareUpgradeProposals? - // MaxEvidenceAge = 60 * 60 * 24 * 7 * 3 - // TODO Temporarily set to 2 minutes for testnets. - MaxEvidenceAge int64 = 60 * 2 - - // SignedBlocksWindow - sliding window for downtime slashing - // TODO Governance parameter? - // TODO Temporarily set to 100 blocks for testnets - SignedBlocksWindow int64 = 100 - - // Downtime slashing threshold - 50% - // TODO Governance parameter? - MinSignedPerWindow int64 = SignedBlocksWindow / 2 - - // Downtime unbond duration - 1 day - // TODO Governance parameter? - DowntimeUnbondDuration int64 = 86400 -) - -var ( - // SlashFractionDoubleSign - currently 5% - // TODO Governance parameter? - SlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20)) - - // SlashFractionDowntime - currently 1% - // TODO Governance parameter? - SlashFractionDowntime = sdk.NewRat(1).Quo(sdk.NewRat(100)) -) - // Keeper of the slashing store type Keeper struct { storeKey sdk.StoreKey @@ -104,56 +72,3 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, k.setValidatorSigningInfo(ctx, address, signInfo) } } - -func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (info validatorSigningInfo, found bool) { - store := ctx.KVStore(k.storeKey) - bz := store.Get(validatorSigningInfoKey(address)) - if bz == nil { - found = false - } else { - k.cdc.MustUnmarshalBinary(bz, &info) - found = true - } - return -} - -func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.Address, info validatorSigningInfo) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinary(info) - store.Set(validatorSigningInfoKey(address), bz) -} - -func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64) (signed bool) { - store := ctx.KVStore(k.storeKey) - bz := store.Get(validatorSigningBitArrayKey(address, index)) - if bz == nil { - // lazy: treat empty key as unsigned - signed = false - } else { - k.cdc.MustUnmarshalBinary(bz, &signed) - } - return -} - -func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64, signed bool) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinary(signed) - store.Set(validatorSigningBitArrayKey(address, index), bz) -} - -type validatorSigningInfo struct { - StartHeight int64 `json:"start_height"` - IndexOffset int64 `json:"index_offset"` - JailedUntil int64 `json:"jailed_until"` - SignedBlocksCounter int64 `json:"signed_blocks_counter"` -} - -func validatorSigningInfoKey(v sdk.Address) []byte { - return append([]byte{0x01}, v.Bytes()...) -} - -func validatorSigningBitArrayKey(v sdk.Address, i int64) []byte { - b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, uint64(i)) - return append([]byte{0x02}, append(v.Bytes(), b...)...) -} diff --git a/x/slashing/params.go b/x/slashing/params.go new file mode 100644 index 0000000000..5e611fa0b5 --- /dev/null +++ b/x/slashing/params.go @@ -0,0 +1,37 @@ +package slashing + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + // MaxEvidenceAge - Max age for evidence - 21 days (3 weeks) + // TODO Should this be a governance parameter or just modifiable with SoftwareUpgradeProposals? + // MaxEvidenceAge = 60 * 60 * 24 * 7 * 3 + // TODO Temporarily set to 2 minutes for testnets. + MaxEvidenceAge int64 = 60 * 2 + + // SignedBlocksWindow - sliding window for downtime slashing + // TODO Governance parameter? + // TODO Temporarily set to 100 blocks for testnets + SignedBlocksWindow int64 = 100 + + // Downtime slashing threshold - 50% + // TODO Governance parameter? + MinSignedPerWindow int64 = SignedBlocksWindow / 2 + + // Downtime unbond duration + // TODO Governance parameter? + // TODO Temporarily set to 6 hours for testnets + DowntimeUnbondDuration int64 = 60 * 60 * 6 +) + +var ( + // SlashFractionDoubleSign - currently 5% + // TODO Governance parameter? + SlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20)) + + // SlashFractionDowntime - currently 1% + // TODO Governance parameter? + SlashFractionDowntime = sdk.NewRat(1).Quo(sdk.NewRat(100)) +) diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go new file mode 100644 index 0000000000..8cb66318db --- /dev/null +++ b/x/slashing/signing_info.go @@ -0,0 +1,60 @@ +package slashing + +import ( + "encoding/binary" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (info validatorSigningInfo, found bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(validatorSigningInfoKey(address)) + if bz == nil { + found = false + } else { + k.cdc.MustUnmarshalBinary(bz, &info) + found = true + } + return +} + +func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.Address, info validatorSigningInfo) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshalBinary(info) + store.Set(validatorSigningInfoKey(address), bz) +} + +func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64) (signed bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(validatorSigningBitArrayKey(address, index)) + if bz == nil { + // lazy: treat empty key as unsigned + signed = false + } else { + k.cdc.MustUnmarshalBinary(bz, &signed) + } + return +} + +func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64, signed bool) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshalBinary(signed) + store.Set(validatorSigningBitArrayKey(address, index), bz) +} + +type validatorSigningInfo struct { + StartHeight int64 `json:"start_height"` + IndexOffset int64 `json:"index_offset"` + JailedUntil int64 `json:"jailed_until"` + SignedBlocksCounter int64 `json:"signed_blocks_counter"` +} + +func validatorSigningInfoKey(v sdk.Address) []byte { + return append([]byte{0x01}, v.Bytes()...) +} + +func validatorSigningBitArrayKey(v sdk.Address, i int64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, uint64(i)) + return append([]byte{0x02}, append(v.Bytes(), b...)...) +} From 02ab73e26690e08f25c9acb1c13a55e704930934 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 28 May 2018 23:39:57 +0200 Subject: [PATCH 039/128] Signing info slashing testcases --- x/slashing/keeper_test.go | 86 ----------------------------- x/slashing/signing_info.go | 8 +-- x/slashing/signing_info_test.go | 35 ++++++++++++ x/slashing/test_common.go | 98 +++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 90 deletions(-) create mode 100644 x/slashing/signing_info_test.go create mode 100644 x/slashing/test_common.go diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 9598b24f3c..0919b0a20d 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -1,75 +1,16 @@ package slashing import ( - "encoding/hex" - "os" "testing" "github.com/stretchr/testify/require" abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" - dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/tmlibs/log" - "github.com/cosmos/cosmos-sdk/store" 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/bank" "github.com/cosmos/cosmos-sdk/x/stake" ) -var ( - addrs = []sdk.Address{ - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161"), - } - pks = []crypto.PubKey{ - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), - } - initCoins int64 = 200 -) - -func createTestCodec() *wire.Codec { - cdc := wire.NewCodec() - sdk.RegisterWire(cdc) - auth.RegisterWire(cdc) - bank.RegisterWire(cdc) - stake.RegisterWire(cdc) - wire.RegisterCrypto(cdc) - return cdc -} - -func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keeper) { - keyAcc := sdk.NewKVStoreKey("acc") - keyStake := sdk.NewKVStoreKey("stake") - keySlashing := sdk.NewKVStoreKey("slashing") - db := dbm.NewMemDB() - ms := store.NewCommitMultiStore(db) - ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db) - err := ms.LoadLatestVersion() - require.Nil(t, err) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewTMLogger(os.Stdout), nil) - cdc := createTestCodec() - accountMapper := auth.NewAccountMapper(cdc, keyAcc, &auth.BaseAccount{}) - ck := bank.NewKeeper(accountMapper) - sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) - genesis := stake.DefaultGenesisState() - genesis.Pool.LooseUnbondedTokens = initCoins * int64(len(addrs)) - stake.InitGenesis(ctx, sk, genesis) - for _, addr := range addrs { - ck.AddCoins(ctx, addr, sdk.Coins{ - {sk.GetParams(ctx).BondDenom, initCoins}, - }) - } - keeper := NewKeeper(cdc, keySlashing, sk, DefaultCodespace) - return ctx, ck, sk, keeper -} - func TestHandleDoubleSign(t *testing.T) { ctx, ck, sk, keeper := createTestInput(t) addr, val, amt := addrs[0], pks[0], int64(100) @@ -145,30 +86,3 @@ func TestHandleAbsentValidator(t *testing.T) { pool = sk.GetPool(ctx) require.Equal(t, int64(99), pool.BondedTokens) } - -func newPubKey(pk string) (res crypto.PubKey) { - pkBytes, err := hex.DecodeString(pk) - if err != nil { - panic(err) - } - var pkEd crypto.PubKeyEd25519 - copy(pkEd[:], pkBytes[:]) - return pkEd -} - -func testAddr(addr string) sdk.Address { - res, err := sdk.GetAddress(addr) - if err != nil { - panic(err) - } - return res -} - -func newTestMsgDeclareCandidacy(address sdk.Address, pubKey crypto.PubKey, amt int64) stake.MsgDeclareCandidacy { - return stake.MsgDeclareCandidacy{ - Description: stake.Description{}, - ValidatorAddr: address, - PubKey: pubKey, - Bond: sdk.Coin{"steak", amt}, - } -} diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index 8cb66318db..cadd6d5805 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -43,10 +43,10 @@ func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.Address } type validatorSigningInfo struct { - StartHeight int64 `json:"start_height"` - IndexOffset int64 `json:"index_offset"` - JailedUntil int64 `json:"jailed_until"` - SignedBlocksCounter int64 `json:"signed_blocks_counter"` + StartHeight int64 `json:"start_height"` // height at which validator was first a candidate OR was unrevoked + IndexOffset int64 `json:"index_offset"` // index offset into signed block bit array + JailedUntil int64 `json:"jailed_until"` // timestamp validator cannot be unrevoked until + SignedBlocksCounter int64 `json:"signed_blocks_counter"` // signed blocks counter (to avoid scanning the array every time) } func validatorSigningInfoKey(v sdk.Address) []byte { diff --git a/x/slashing/signing_info_test.go b/x/slashing/signing_info_test.go new file mode 100644 index 0000000000..8000d67450 --- /dev/null +++ b/x/slashing/signing_info_test.go @@ -0,0 +1,35 @@ +package slashing + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGetSetValidatorSigningInfo(t *testing.T) { + ctx, _, _, keeper := createTestInput(t) + info, found := keeper.getValidatorSigningInfo(ctx, addrs[0]) + require.False(t, found) + newInfo := validatorSigningInfo{ + StartHeight: int64(4), + IndexOffset: int64(3), + JailedUntil: int64(2), + SignedBlocksCounter: int64(10), + } + keeper.setValidatorSigningInfo(ctx, addrs[0], newInfo) + info, found = keeper.getValidatorSigningInfo(ctx, addrs[0]) + require.True(t, found) + require.Equal(t, info.StartHeight, int64(4)) + require.Equal(t, info.IndexOffset, int64(3)) + require.Equal(t, info.JailedUntil, int64(2)) + require.Equal(t, info.SignedBlocksCounter, int64(10)) +} + +func TestGetSetValidatorSigningBitArray(t *testing.T) { + ctx, _, _, keeper := createTestInput(t) + signed := keeper.getValidatorSigningBitArray(ctx, addrs[0], 0) + require.False(t, signed) // treat empty key as unsigned + keeper.setValidatorSigningBitArray(ctx, addrs[0], 0, true) + signed = keeper.getValidatorSigningBitArray(ctx, addrs[0], 0) + require.True(t, signed) // now should be signed +} diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go new file mode 100644 index 0000000000..21274df1b8 --- /dev/null +++ b/x/slashing/test_common.go @@ -0,0 +1,98 @@ +package slashing + +import ( + "encoding/hex" + "os" + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" + dbm "github.com/tendermint/tmlibs/db" + "github.com/tendermint/tmlibs/log" + + "github.com/cosmos/cosmos-sdk/store" + 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/bank" + "github.com/cosmos/cosmos-sdk/x/stake" +) + +var ( + addrs = []sdk.Address{ + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161"), + } + pks = []crypto.PubKey{ + newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"), + newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), + } + initCoins int64 = 200 +) + +func createTestCodec() *wire.Codec { + cdc := wire.NewCodec() + sdk.RegisterWire(cdc) + auth.RegisterWire(cdc) + bank.RegisterWire(cdc) + stake.RegisterWire(cdc) + wire.RegisterCrypto(cdc) + return cdc +} + +func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keeper) { + keyAcc := sdk.NewKVStoreKey("acc") + keyStake := sdk.NewKVStoreKey("stake") + keySlashing := sdk.NewKVStoreKey("slashing") + db := dbm.NewMemDB() + ms := store.NewCommitMultiStore(db) + ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db) + err := ms.LoadLatestVersion() + require.Nil(t, err) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewTMLogger(os.Stdout), nil) + cdc := createTestCodec() + accountMapper := auth.NewAccountMapper(cdc, keyAcc, &auth.BaseAccount{}) + ck := bank.NewKeeper(accountMapper) + sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) + genesis := stake.DefaultGenesisState() + genesis.Pool.LooseUnbondedTokens = initCoins * int64(len(addrs)) + stake.InitGenesis(ctx, sk, genesis) + for _, addr := range addrs { + ck.AddCoins(ctx, addr, sdk.Coins{ + {sk.GetParams(ctx).BondDenom, initCoins}, + }) + } + keeper := NewKeeper(cdc, keySlashing, sk, DefaultCodespace) + return ctx, ck, sk, keeper +} + +func newPubKey(pk string) (res crypto.PubKey) { + pkBytes, err := hex.DecodeString(pk) + if err != nil { + panic(err) + } + var pkEd crypto.PubKeyEd25519 + copy(pkEd[:], pkBytes[:]) + return pkEd +} + +func testAddr(addr string) sdk.Address { + res, err := sdk.GetAddress(addr) + if err != nil { + panic(err) + } + return res +} + +func newTestMsgDeclareCandidacy(address sdk.Address, pubKey crypto.PubKey, amt int64) stake.MsgDeclareCandidacy { + return stake.MsgDeclareCandidacy{ + Description: stake.Description{}, + ValidatorAddr: address, + PubKey: pubKey, + Bond: sdk.Coin{"steak", amt}, + } +} From c0487996abf709cfec6bb2b6b3bd256d1310fa3a Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 28 May 2018 23:46:08 +0200 Subject: [PATCH 040/128] Update slashing docs, slight index change --- docs/spec/staking/valset-changes.md | 18 ++++++++++++------ x/slashing/keeper.go | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/spec/staking/valset-changes.md b/docs/spec/staking/valset-changes.md index e5979af39a..0e635fd047 100644 --- a/docs/spec/staking/valset-changes.md +++ b/docs/spec/staking/valset-changes.md @@ -156,25 +156,30 @@ The following information is stored with each validator candidate, and is only n ```go type ValidatorSigningInfo struct { StartHeight int64 - SignedBlocksBitArray BitArray + IndexOffset int64 + JailedUntil int64 SignedBlocksCounter int64 + SignedBlocksBitArray BitArray } ``` Where: * `StartHeight` is set to the height that the candidate became an active validator (with non-zero voting power). +* `IndexOffset` is incremented each time the candidate was a bonded validator in a block (and may have signed a precommit or not). +* `JailedUntil` is set whenever the candidate is revoked due to downtime +* `SignedBlocksCounter` is a counter kept to avoid unnecessary array reads. `SignedBlocksBitArray.Sum() == SignedBlocksCounter` always. * `SignedBlocksBitArray` is a bit-array of size `SIGNED_BLOCKS_WINDOW` that records, for each of the last `SIGNED_BLOCKS_WINDOW` blocks, whether or not this validator was included in the LastCommit. It uses a `1` if the validator was included, and a `0` if it was not. Note it is initialized with all 0s. -* `SignedBlocksCounter` is a counter kept to avoid unnecessary array reads. `SignedBlocksBitArray.Sum() == SignedBlocksCounter` always. At the beginning of each block, we update the signing info for each validator and check if they should be automatically unbonded: ``` -h = block.Height -index = h % SIGNED_BLOCKS_WINDOW +height := block.Height for val in block.Validators: signInfo = val.SignInfo + index := signInfo.IndexOffset % SIGNED_BLOCKS_WINDOW + signInfo.IndexOffset++ previous = signInfo.SignedBlocksBitArray.Get(index) // update counter if array has changed @@ -191,6 +196,7 @@ for val in block.Validators: // included in 50% of the recent LastCommits minHeight = signInfo.StartHeight + SIGNED_BLOCKS_WINDOW minSigned = SIGNED_BLOCKS_WINDOW / 2 - if h > minHeight AND signInfo.SignedBlocksCounter < minSigned: - unbond the validator + if height > minHeight AND signInfo.SignedBlocksCounter < minSigned: + signInfo.JailedUntil = block.Time + DOWNTIME_UNBOND_DURATION + slash & unbond the validator ``` diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index c8fcbe1b92..8b0d585ec5 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -51,8 +51,8 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, } address := pubkey.Address() signInfo, _ := k.getValidatorSigningInfo(ctx, address) - signInfo.IndexOffset++ index := signInfo.IndexOffset % SignedBlocksWindow + signInfo.IndexOffset++ previous := k.getValidatorSigningBitArray(ctx, address, index) if previous && !signed { k.setValidatorSigningBitArray(ctx, address, index, false) From 26f22dbe4dd712f1df1271aa478f81fffd583003 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 28 May 2018 23:55:39 +0200 Subject: [PATCH 041/128] Test start height update --- x/slashing/handler.go | 10 +++++++++- x/slashing/keeper_test.go | 20 +++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/x/slashing/handler.go b/x/slashing/handler.go index e1d6607898..a3218f6e63 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -22,7 +22,9 @@ func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { return ErrNoValidatorForAddress(k.codespace).Result() } - info, found := k.getValidatorSigningInfo(ctx, validator.GetPubKey().Address()) + addr := validator.GetPubKey().Address() + + info, found := k.getValidatorSigningInfo(ctx, addr) if !found { return ErrNoValidatorForAddress(k.codespace).Result() } @@ -35,9 +37,15 @@ func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { return sdk.Result{} } + // Update the starting height (so the validator can't be immediately revoked again) + info.StartHeight = ctx.BlockHeight() + k.setValidatorSigningInfo(ctx, addr, info) + + // Unrevoke the validator k.stakeKeeper.Unrevoke(ctx, validator.GetPubKey()) tags := sdk.NewTags("action", []byte("unrevoke"), "validator", msg.ValidatorAddr.Bytes()) + return sdk.Result{ Tags: tags, } diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 0919b0a20d..b6aad3e6ca 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -71,7 +71,6 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter) - height++ // should have been revoked validator = sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Unbonded, validator.GetStatus()) @@ -85,4 +84,23 @@ func TestHandleAbsentValidator(t *testing.T) { // should have been slashed pool = sk.GetPool(ctx) require.Equal(t, int64(99), pool.BondedTokens) + // start height should have been changed + info, found = keeper.getValidatorSigningInfo(ctx, val.Address()) + require.True(t, found) + require.Equal(t, height, info.StartHeight) + require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter) + // should not be immediately revoked again + height++ + ctx = ctx.WithBlockHeight(height) + keeper.handleValidatorSignature(ctx, val, false) + validator = sk.ValidatorByPubKey(ctx, val) + require.Equal(t, sdk.Bonded, validator.GetStatus()) + // should be revoked again after 100 blocks + nextHeight := height + 100 + for ; height <= nextHeight; height++ { + ctx = ctx.WithBlockHeight(height) + keeper.handleValidatorSignature(ctx, val, false) + } + validator = sk.ValidatorByPubKey(ctx, val) + require.Equal(t, sdk.Unbonded, validator.GetStatus()) } From f4f8cc66d980db731f74d63d77cf62012dc4cae7 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 00:10:52 +0200 Subject: [PATCH 042/128] Add some explanatory comments --- x/slashing/handler.go | 6 ++++++ x/slashing/keeper.go | 10 ++++++++++ x/slashing/keeper_test.go | 21 +++++++++++++-------- x/slashing/tick.go | 12 +++++++++++- x/stake/keeper.go | 6 ++++-- 5 files changed, 44 insertions(+), 11 deletions(-) diff --git a/x/slashing/handler.go b/x/slashing/handler.go index a3218f6e63..cf83a6a992 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -16,7 +16,11 @@ func NewHandler(k Keeper) sdk.Handler { } } +// Validators must submit a transaction to unrevoke themselves after +// having been revoked (and thus unbonded) for downtime func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { + + // Validator must exist validator := k.stakeKeeper.Validator(ctx, msg.ValidatorAddr) if validator == nil { return ErrNoValidatorForAddress(k.codespace).Result() @@ -24,11 +28,13 @@ func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { addr := validator.GetPubKey().Address() + // Signing info must exist info, found := k.getValidatorSigningInfo(ctx, addr) if !found { return ErrNoValidatorForAddress(k.codespace).Result() } + // Cannot be unrevoked until out of jail if ctx.BlockHeader().Time < info.JailedUntil { return ErrValidatorJailed(k.codespace).Result() } diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 8b0d585ec5..f003b33540 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -34,10 +34,14 @@ func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, sk stake.Keeper, codespace sdk func (k Keeper) handleDoubleSign(ctx sdk.Context, height int64, timestamp int64, pubkey crypto.PubKey) { logger := ctx.Logger().With("module", "x/slashing") age := ctx.BlockHeader().Time - timestamp + + // Double sign too old if age > MaxEvidenceAge { logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) return } + + // Double sign confirmed logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDoubleSign) } @@ -50,9 +54,13 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, logger.Info(fmt.Sprintf("Absent validator %s at height %d", pubkey.Address(), height)) } address := pubkey.Address() + + // Local index, so counts blocks validator *should* have signed signInfo, _ := k.getValidatorSigningInfo(ctx, address) index := signInfo.IndexOffset % SignedBlocksWindow signInfo.IndexOffset++ + + // Update signed block bit array & counter previous := k.getValidatorSigningBitArray(ctx, address, index) if previous && !signed { k.setValidatorSigningBitArray(ctx, address, index, false) @@ -63,8 +71,10 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, signInfo.SignedBlocksCounter++ k.setValidatorSigningInfo(ctx, address, signInfo) } + minHeight := signInfo.StartHeight + SignedBlocksWindow if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { + // Downtime confirmed, slash, revoke, and jail the validator logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, MinSignedPerWindow)) k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDowntime) k.stakeKeeper.Revoke(ctx, pubkey) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index b6aad3e6ca..2fef0c974a 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -39,7 +39,9 @@ func TestHandleAbsentValidator(t *testing.T) { info, found := keeper.getValidatorSigningInfo(ctx, val.Address()) require.False(t, found) require.Equal(t, int64(0), info.StartHeight) + require.Equal(t, int64(0), info.IndexOffset) require.Equal(t, int64(0), info.SignedBlocksCounter) + require.Equal(t, int64(0), info.JailedUntil) height := int64(0) // 1000 blocks OK for ; height < 1000; height++ { @@ -59,7 +61,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, SignedBlocksWindow-50, info.SignedBlocksCounter) - // should be bonded still + // validator should be bonded still validator := sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) pool := sk.GetPool(ctx) @@ -71,31 +73,34 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter) - // should have been revoked + // validator should have been revoked validator = sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Unbonded, validator.GetStatus()) + // unrevocation should fail prior to jail expiration got = slh(ctx, NewMsgUnrevoke(addr)) - require.False(t, got.IsOK()) // should fail prior to jail expiration + require.False(t, got.IsOK()) + // unrevocation should succeed after jail expiration ctx = ctx.WithBlockHeader(abci.Header{Time: int64(86400 * 2)}) got = slh(ctx, NewMsgUnrevoke(addr)) - require.True(t, got.IsOK()) // should succeed after jail expiration + require.True(t, got.IsOK()) + // validator should be rebonded now validator = sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) - // should have been slashed + // validator should have been slashed pool = sk.GetPool(ctx) require.Equal(t, int64(99), pool.BondedTokens) - // start height should have been changed + // validator start height should have been changed info, found = keeper.getValidatorSigningInfo(ctx, val.Address()) require.True(t, found) require.Equal(t, height, info.StartHeight) require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter) - // should not be immediately revoked again + // validator should not be immediately revoked again height++ ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, false) validator = sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) - // should be revoked again after 100 blocks + // validator should be revoked again after 100 unsigned blocks nextHeight := height + 100 for ; height <= nextHeight; height++ { ctx = ctx.WithBlockHeight(height) diff --git a/x/slashing/tick.go b/x/slashing/tick.go index e76c06abe3..abec2b3751 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -12,9 +12,12 @@ import ( func NewBeginBlocker(sk Keeper) sdk.BeginBlocker { return func(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { + // Tag the height heightBytes := make([]byte, 8) binary.LittleEndian.PutUint64(heightBytes, uint64(req.Header.Height)) tags := sdk.NewTags("height", heightBytes) + + // Deal with any equivocation evidence for _, evidence := range req.ByzantineValidators { var pk crypto.PubKey sk.cdc.MustUnmarshalBinary(evidence.PubKey, &pk) @@ -25,18 +28,25 @@ func NewBeginBlocker(sk Keeper) sdk.BeginBlocker { ctx.Logger().With("module", "x/slashing").Error(fmt.Sprintf("Ignored unknown evidence type: %s", string(evidence.Type))) } } + + // Figure out which validators were absent absent := make(map[string]bool) for _, pubkey := range req.AbsentValidators { var pk crypto.PubKey sk.cdc.MustUnmarshalBinary(pubkey, &pk) absent[string(pk.Bytes())] = true } + + // Iterate over all the validators which *should* have signed this block sk.stakeKeeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { pubkey := validator.GetPubKey() sk.handleValidatorSignature(ctx, pubkey, !absent[string(pubkey.Bytes())]) return false }) - // TODO Add some more tags so clients can track slashing + + // Return the begin block response + // TODO Return something composable, so other modules can also have BeginBlockers + // TODO Add some more tags so clients can track slashing events return abci.ResponseBeginBlock{ Tags: tags.ToKVPairs(), } diff --git a/x/stake/keeper.go b/x/stake/keeper.go index aba118ed5a..8775dbef53 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -799,7 +799,8 @@ func (k Keeper) Revoke(ctx sdk.Context, pubkey crypto.PubKey) { logger := ctx.Logger().With("module", "x/stake") val, found := k.GetValidatorByPubKey(ctx, pubkey) if !found { - ctx.Logger().Info("Validator with pubkey %s not found, cannot force unbond", pubkey) + // TODO Should we panic? + ctx.Logger().Info("Validator with pubkey %s not found, cannot revoke", pubkey) return } val.Revoked = true @@ -813,7 +814,8 @@ func (k Keeper) Unrevoke(ctx sdk.Context, pubkey crypto.PubKey) { logger := ctx.Logger().With("module", "x/stake") val, found := k.GetValidatorByPubKey(ctx, pubkey) if !found { - ctx.Logger().Info("Validator with pubkey %s not found, cannot force unbond", pubkey) + // TODO Should we panic? + ctx.Logger().Info("Validator with pubkey %s not found, cannot unrevoke", pubkey) return } val.Revoked = false From aed5d94b1ceba2969af993386f1bd9ebc827ac94 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 02:26:17 +0200 Subject: [PATCH 043/128] Remove absent validators from sdk.NewContext --- baseapp/baseapp.go | 8 ++++---- examples/democoin/x/cool/keeper_test.go | 2 +- examples/democoin/x/pow/handler_test.go | 2 +- examples/democoin/x/pow/keeper_test.go | 2 +- examples/democoin/x/simplestake/keeper_test.go | 4 ++-- types/context.go | 5 ++--- types/context_test.go | 4 ++-- types/lib/mapper_test.go | 2 +- x/auth/ante_test.go | 10 +++++----- x/auth/context_test.go | 2 +- x/auth/feekeeper_test.go | 6 +++--- x/auth/mapper_test.go | 2 +- x/bank/keeper_test.go | 6 +++--- x/ibc/ibc_test.go | 2 +- x/slashing/test_common.go | 2 +- x/stake/test_common.go | 2 +- 16 files changed, 30 insertions(+), 31 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index baed1fb47d..cdc5ffcf7a 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -235,9 +235,9 @@ func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error { // NewContext returns a new Context with the correct store, the given header, and nil txBytes. func (app *BaseApp) NewContext(isCheckTx bool, header abci.Header) sdk.Context { if isCheckTx { - return sdk.NewContext(app.checkState.ms, header, true, nil, app.Logger, nil) + return sdk.NewContext(app.checkState.ms, header, true, nil, app.Logger) } - return sdk.NewContext(app.deliverState.ms, header, false, nil, app.Logger, nil) + return sdk.NewContext(app.deliverState.ms, header, false, nil, app.Logger) } type state struct { @@ -253,7 +253,7 @@ func (app *BaseApp) setCheckState(header abci.Header) { ms := app.cms.CacheMultiStore() app.checkState = &state{ ms: ms, - ctx: sdk.NewContext(ms, header, true, nil, app.Logger, nil), + ctx: sdk.NewContext(ms, header, true, nil, app.Logger), } } @@ -261,7 +261,7 @@ func (app *BaseApp) setDeliverState(header abci.Header) { ms := app.cms.CacheMultiStore() app.deliverState = &state{ ms: ms, - ctx: sdk.NewContext(ms, header, false, nil, app.Logger, nil), + ctx: sdk.NewContext(ms, header, false, nil, app.Logger), } } diff --git a/examples/democoin/x/cool/keeper_test.go b/examples/democoin/x/cool/keeper_test.go index f632ae31ee..d497dee699 100644 --- a/examples/democoin/x/cool/keeper_test.go +++ b/examples/democoin/x/cool/keeper_test.go @@ -30,7 +30,7 @@ func TestCoolKeeper(t *testing.T) { auth.RegisterBaseAccount(cdc) am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, nil, nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, nil) ck := bank.NewKeeper(am) keeper := NewKeeper(capKey, ck, DefaultCodespace) diff --git a/examples/democoin/x/pow/handler_test.go b/examples/democoin/x/pow/handler_test.go index 867120eb84..30aeafa2a5 100644 --- a/examples/democoin/x/pow/handler_test.go +++ b/examples/democoin/x/pow/handler_test.go @@ -20,7 +20,7 @@ func TestPowHandler(t *testing.T) { auth.RegisterBaseAccount(cdc) am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) config := NewConfig("pow", int64(1)) ck := bank.NewKeeper(am) keeper := NewKeeper(capKey, config, ck, DefaultCodespace) diff --git a/examples/democoin/x/pow/keeper_test.go b/examples/democoin/x/pow/keeper_test.go index 98e8ebcfea..a4afb876a9 100644 --- a/examples/democoin/x/pow/keeper_test.go +++ b/examples/democoin/x/pow/keeper_test.go @@ -33,7 +33,7 @@ func TestPowKeeperGetSet(t *testing.T) { auth.RegisterBaseAccount(cdc) am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) config := NewConfig("pow", int64(1)) ck := bank.NewKeeper(am) keeper := NewKeeper(capKey, config, ck, DefaultCodespace) diff --git a/examples/democoin/x/simplestake/keeper_test.go b/examples/democoin/x/simplestake/keeper_test.go index ef34f3085c..15bd14c79b 100644 --- a/examples/democoin/x/simplestake/keeper_test.go +++ b/examples/democoin/x/simplestake/keeper_test.go @@ -37,7 +37,7 @@ func TestKeeperGetSet(t *testing.T) { accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) stakeKeeper := NewKeeper(capKey, bank.NewKeeper(accountMapper), DefaultCodespace) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) addr := sdk.Address([]byte("some-address")) bi := stakeKeeper.getBondInfo(ctx, addr) @@ -63,7 +63,7 @@ func TestBonding(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := bank.NewKeeper(accountMapper) diff --git a/types/context.go b/types/context.go index 993c148ec5..10ae99724f 100644 --- a/types/context.go +++ b/types/context.go @@ -30,8 +30,7 @@ type Context struct { } // create a new context -func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, - txBytes []byte, logger log.Logger, absentValidators [][]byte) Context { +func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byte, logger log.Logger) Context { c := Context{ Context: context.Background(), @@ -45,7 +44,7 @@ func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, c = c.WithIsCheckTx(isCheckTx) c = c.WithTxBytes(txBytes) c = c.WithLogger(logger) - c = c.WithAbsentValidators(absentValidators) + c = c.WithAbsentValidators(nil) c = c.WithGasMeter(NewInfiniteGasMeter()) return c } diff --git a/types/context_test.go b/types/context_test.go index 1eafdaf7e7..ec5faab440 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -43,7 +43,7 @@ func (l MockLogger) With(kvs ...interface{}) log.Logger { func TestContextGetOpShouldNeverPanic(t *testing.T) { var ms types.MultiStore - ctx := types.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := types.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) indices := []int64{ -10, 1, 0, 10, 20, } @@ -58,7 +58,7 @@ func defaultContext(key types.StoreKey) types.Context { cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, types.StoreTypeIAVL, db) cms.LoadLatestVersion() - ctx := types.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := types.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger()) return ctx } diff --git a/types/lib/mapper_test.go b/types/lib/mapper_test.go index a610f1e0fa..e1759b06ac 100644 --- a/types/lib/mapper_test.go +++ b/types/lib/mapper_test.go @@ -25,7 +25,7 @@ func defaultComponents(key sdk.StoreKey) (sdk.Context, *wire.Codec) { cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) cms.LoadLatestVersion() - ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger()) cdc := wire.NewCodec() return ctx, cdc } diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index 729f0769ef..b7f22e5d54 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -75,7 +75,7 @@ func TestAnteHandlerSigErrors(t *testing.T) { mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses priv1, addr1 := privAndAddr() @@ -117,7 +117,7 @@ func TestAnteHandlerSequences(t *testing.T) { mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses priv1, addr1 := privAndAddr() @@ -184,7 +184,7 @@ func TestAnteHandlerFees(t *testing.T) { mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses priv1, addr1 := privAndAddr() @@ -226,7 +226,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses priv1, addr1 := privAndAddr() @@ -302,7 +302,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) { mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) // keys and addresses priv1, addr1 := privAndAddr() diff --git a/x/auth/context_test.go b/x/auth/context_test.go index 615b7d5196..a93de44d0c 100644 --- a/x/auth/context_test.go +++ b/x/auth/context_test.go @@ -13,7 +13,7 @@ import ( func TestContextWithSigners(t *testing.T) { ms, _, _ := setupMultiStore() - ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger()) _, _, addr1 := keyPubAddr() _, _, addr2 := keyPubAddr() diff --git a/x/auth/feekeeper_test.go b/x/auth/feekeeper_test.go index 3c9190e4ec..2f1ffc59bc 100644 --- a/x/auth/feekeeper_test.go +++ b/x/auth/feekeeper_test.go @@ -23,7 +23,7 @@ func TestFeeCollectionKeeperGetSet(t *testing.T) { cdc := wire.NewCodec() // make context and keeper - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) fck := NewFeeCollectionKeeper(cdc, capKey2) // no coins initially @@ -42,7 +42,7 @@ func TestFeeCollectionKeeperAdd(t *testing.T) { cdc := wire.NewCodec() // make context and keeper - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) fck := NewFeeCollectionKeeper(cdc, capKey2) // no coins initially @@ -62,7 +62,7 @@ func TestFeeCollectionKeeperClear(t *testing.T) { cdc := wire.NewCodec() // make context and keeper - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) fck := NewFeeCollectionKeeper(cdc, capKey2) // set coins initially diff --git a/x/auth/mapper_test.go b/x/auth/mapper_test.go index dc6afef57e..7f6397069a 100644 --- a/x/auth/mapper_test.go +++ b/x/auth/mapper_test.go @@ -31,7 +31,7 @@ func TestAccountMapperGetSet(t *testing.T) { RegisterBaseAccount(cdc) // make context and mapper - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) addr := sdk.Address([]byte("some-address")) diff --git a/x/bank/keeper_test.go b/x/bank/keeper_test.go index 07ba91e0c5..117c69e7ae 100644 --- a/x/bank/keeper_test.go +++ b/x/bank/keeper_test.go @@ -31,7 +31,7 @@ func TestKeeper(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := NewKeeper(accountMapper) @@ -116,7 +116,7 @@ func TestSendKeeper(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := NewKeeper(accountMapper) sendKeeper := NewSendKeeper(accountMapper) @@ -185,7 +185,7 @@ func TestViewKeeper(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger()) accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := NewKeeper(accountMapper) viewKeeper := NewViewKeeper(accountMapper) diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index 9ed4b38254..e13df4f8dd 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -24,7 +24,7 @@ func defaultContext(key sdk.StoreKey) sdk.Context { cms := store.NewCommitMultiStore(db) cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) cms.LoadLatestVersion() - ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(cms, abci.Header{}, false, nil, log.NewNopLogger()) return ctx } diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 21274df1b8..8ce654f338 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -53,7 +53,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db) err := ms.LoadLatestVersion() require.Nil(t, err) - ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewTMLogger(os.Stdout), nil) + ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewTMLogger(os.Stdout)) cdc := createTestCodec() accountMapper := auth.NewAccountMapper(cdc, keyAcc, &auth.BaseAccount{}) ck := bank.NewKeeper(accountMapper) diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 1cd46549b0..b7a5152c09 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -103,7 +103,7 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context err := ms.LoadLatestVersion() require.Nil(t, err) - ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil, log.NewNopLogger(), nil) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, nil, log.NewNopLogger()) cdc := makeTestCodec() accountMapper := auth.NewAccountMapper( cdc, // amino codec From 0dae7f8e4c2de90dd39e8f2932dd544c068dafa9 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 02:27:43 +0200 Subject: [PATCH 044/128] Panic on revoke/unrevoke nonexistent validator --- x/stake/keeper.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 8775dbef53..d943193a11 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -799,9 +799,7 @@ func (k Keeper) Revoke(ctx sdk.Context, pubkey crypto.PubKey) { logger := ctx.Logger().With("module", "x/stake") val, found := k.GetValidatorByPubKey(ctx, pubkey) if !found { - // TODO Should we panic? - ctx.Logger().Info("Validator with pubkey %s not found, cannot revoke", pubkey) - return + panic(fmt.Errorf("Validator with pubkey %s not found, cannot revoke", pubkey)) } val.Revoked = true k.updateValidator(ctx, val) // update the validator, now revoked @@ -814,9 +812,7 @@ func (k Keeper) Unrevoke(ctx sdk.Context, pubkey crypto.PubKey) { logger := ctx.Logger().With("module", "x/stake") val, found := k.GetValidatorByPubKey(ctx, pubkey) if !found { - // TODO Should we panic? - ctx.Logger().Info("Validator with pubkey %s not found, cannot unrevoke", pubkey) - return + panic(fmt.Errorf("Validator with pubkey %s not found, cannot unrevoke", pubkey)) } val.Revoked = false k.updateValidator(ctx, val) // update the validator, now unrevoked From b8b4fe24e3386a1b4a22c144cd812f5cdfd1c249 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 02:33:01 +0200 Subject: [PATCH 045/128] Absent validators map[crypto.PubKey]struct{} --- x/slashing/tick.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/x/slashing/tick.go b/x/slashing/tick.go index abec2b3751..0d200f5934 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -30,17 +30,21 @@ func NewBeginBlocker(sk Keeper) sdk.BeginBlocker { } // Figure out which validators were absent - absent := make(map[string]bool) + absent := make(map[crypto.PubKey]struct{}) for _, pubkey := range req.AbsentValidators { var pk crypto.PubKey sk.cdc.MustUnmarshalBinary(pubkey, &pk) - absent[string(pk.Bytes())] = true + absent[pk] = struct{}{} } // Iterate over all the validators which *should* have signed this block sk.stakeKeeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { pubkey := validator.GetPubKey() - sk.handleValidatorSignature(ctx, pubkey, !absent[string(pubkey.Bytes())]) + abs := false + if _, ok := absent[pubkey]; ok { + abs = true + } + sk.handleValidatorSignature(ctx, pubkey, abs) return false }) From 7fbecc6b727f83448aa2eae72d0a298fb8f5d279 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 02:35:42 +0200 Subject: [PATCH 046/128] Clarify default signing info --- x/slashing/keeper.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index f003b33540..b27fdb5927 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -56,6 +56,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, address := pubkey.Address() // Local index, so counts blocks validator *should* have signed + // Will use the 0-value default signing info if not present signInfo, _ := k.getValidatorSigningInfo(ctx, address) index := signInfo.IndexOffset % SignedBlocksWindow signInfo.IndexOffset++ @@ -65,11 +66,9 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, if previous && !signed { k.setValidatorSigningBitArray(ctx, address, index, false) signInfo.SignedBlocksCounter-- - k.setValidatorSigningInfo(ctx, address, signInfo) } else if !previous && signed { k.setValidatorSigningBitArray(ctx, address, index, true) signInfo.SignedBlocksCounter++ - k.setValidatorSigningInfo(ctx, address, signInfo) } minHeight := signInfo.StartHeight + SignedBlocksWindow @@ -79,6 +78,8 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDowntime) k.stakeKeeper.Revoke(ctx, pubkey) signInfo.JailedUntil = ctx.BlockHeader().Time + DowntimeUnbondDuration - k.setValidatorSigningInfo(ctx, address, signInfo) } + + // Set the updated signing info + k.setValidatorSigningInfo(ctx, address, signInfo) } From 65945c069c7cbc9fabbe6523fd0086054fd82a1b Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 02:48:29 +0200 Subject: [PATCH 047/128] Clarify counter logic --- x/slashing/keeper.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index b27fdb5927..46ed4591b2 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -63,10 +63,14 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, // Update signed block bit array & counter previous := k.getValidatorSigningBitArray(ctx, address, index) - if previous && !signed { + if previous == signed { + // No need to update counter + } else if previous && !signed { + // Signed => unsigned, decrement counter k.setValidatorSigningBitArray(ctx, address, index, false) signInfo.SignedBlocksCounter-- } else if !previous && signed { + // Unsigned => signed, increment counter k.setValidatorSigningBitArray(ctx, address, index, true) signInfo.SignedBlocksCounter++ } From 345b5b88a8bb357c047f990ded1b97fbb88e5c33 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 02:50:04 +0200 Subject: [PATCH 048/128] Add comment on MsgUnrevoke --- x/slashing/msg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/slashing/msg.go b/x/slashing/msg.go index d67ddf70df..72d2255d61 100644 --- a/x/slashing/msg.go +++ b/x/slashing/msg.go @@ -14,7 +14,7 @@ var _ sdk.Msg = &MsgUnrevoke{} // MsgUnrevoke - struct for unrevoking revoked validator type MsgUnrevoke struct { - ValidatorAddr sdk.Address `json:"address"` + ValidatorAddr sdk.Address `json:"address"` // address of the validator owner } func NewMsgUnrevoke(validatorAddr sdk.Address) MsgUnrevoke { From 88e00257242c028f1f72e1b010deb33994e4f6ef Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 02:56:40 +0200 Subject: [PATCH 049/128] DowntimeUnbondDuration to 10 minutes --- x/slashing/params.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/slashing/params.go b/x/slashing/params.go index 5e611fa0b5..3bba85fa66 100644 --- a/x/slashing/params.go +++ b/x/slashing/params.go @@ -22,8 +22,8 @@ const ( // Downtime unbond duration // TODO Governance parameter? - // TODO Temporarily set to 6 hours for testnets - DowntimeUnbondDuration int64 = 60 * 60 * 6 + // TODO Temporarily set to 10 minutes for testnets + DowntimeUnbondDuration int64 = 60 * 10 ) var ( From 69af8b1a945fc8a42262b87bb06b451c0b38b76f Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 02:58:43 +0200 Subject: [PATCH 050/128] Clarify signing info stored by validator address --- x/slashing/signing_info.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index cadd6d5805..fcbb0d1c7e 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// Stored by *validator* address (not owner address) func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (info validatorSigningInfo, found bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(validatorSigningInfoKey(address)) @@ -18,12 +19,14 @@ func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (i return } +// Stored by *validator* address (not owner address) func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.Address, info validatorSigningInfo) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(info) store.Set(validatorSigningInfoKey(address), bz) } +// Stored by *validator* address (not owner address) func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64) (signed bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(validatorSigningBitArrayKey(address, index)) @@ -36,6 +39,7 @@ func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.Address return } +// Stored by *validator* address (not owner address) func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64, signed bool) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(signed) @@ -49,10 +53,12 @@ type validatorSigningInfo struct { SignedBlocksCounter int64 `json:"signed_blocks_counter"` // signed blocks counter (to avoid scanning the array every time) } +// Stored by *validator* address (not owner address) func validatorSigningInfoKey(v sdk.Address) []byte { return append([]byte{0x01}, v.Bytes()...) } +// Stored by *validator* address (not owner address) func validatorSigningBitArrayKey(v sdk.Address, i int64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, uint64(i)) From ef3e2200a5fca8313a3e0340224355d5722e51ef Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 05:00:47 +0200 Subject: [PATCH 051/128] Fix dependencies --- Gopkg.lock | 17 ++++++++--------- Gopkg.toml | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 286760d609..5fe7b1a876 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -11,7 +11,7 @@ branch = "master" name = "github.com/btcsuite/btcd" packages = ["btcec"] - revision = "1432d294a5b055c297457c25434efbf13384cc46" + revision = "bc0944904505aab55e089371a892be2f87883161" [[projects]] name = "github.com/davecgh/go-spew" @@ -253,7 +253,6 @@ revision = "5d6fca44a948d2be89a9702de7717f0168403d3d" [[projects]] - branch = "develop" name = "github.com/tendermint/abci" packages = [ "client", @@ -277,8 +276,8 @@ [[projects]] name = "github.com/tendermint/go-amino" packages = ["."] - revision = "ed62928576cfcaf887209dc96142cd79cdfff389" - version = "0.9.9" + revision = "3c22a7a539411f89a96738fcfa14c1027e24e5ec" + version = "0.9.10" [[projects]] name = "github.com/tendermint/go-crypto" @@ -342,7 +341,7 @@ "types/priv_validator", "version" ] - revision = "d3093426f455c4b33cee818e3bbf2d2b83e4b38d" + revision = "3b8c1ae119da990664f3b98bb2518032f5d837f9" [[projects]] name = "github.com/tendermint/tmlibs" @@ -374,7 +373,7 @@ "ripemd160", "salsa20/salsa" ] - revision = "75e913eb8a8e3d31a97b216de09de106a7b07681" + revision = "ab813273cd59e1333f7ae7bff5d027d4aadf528c" [[projects]] branch = "master" @@ -388,13 +387,13 @@ "internal/timeseries", "trace" ] - revision = "9ef9f5bb98a1fdc41f8cf6c250a4404b4085e389" + revision = "dfa909b99c79129e1100513e5cd36307665e5723" [[projects]] branch = "master" name = "golang.org/x/sys" packages = ["unix"] - revision = "77b0e4315053a57ed2962443614bdb28db152054" + revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f" [[projects]] name = "golang.org/x/text" @@ -455,6 +454,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "bbc0ee39f39cb296960a5fcb2a3916a4acc48ecbb675758ea1f61def44e994bb" + inputs-digest = "dc095a5d071dc8e1d7c3fd1208efbbe7d3c09551ecef76fdfafcdcdd88a49f50" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 53dbabbbb3..61d11f999b 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -54,7 +54,7 @@ [[override]] name = "github.com/tendermint/abci" - branch = "develop" + revision = "f9dce537281ffba5d1e047e6729429f7e5fb90c9" [[constraint]] name = "github.com/tendermint/go-crypto" From 5254a4aa1d847181d373144c1a283b5205909dd4 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 05:24:57 +0200 Subject: [PATCH 052/128] Dependency fix, try II --- Gopkg.lock | 6 +++--- Gopkg.toml | 4 ++-- client/tx/search.go | 7 +++++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 5fe7b1a876..e30a97fda3 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -276,8 +276,8 @@ [[projects]] name = "github.com/tendermint/go-amino" packages = ["."] - revision = "3c22a7a539411f89a96738fcfa14c1027e24e5ec" - version = "0.9.10" + revision = "ed62928576cfcaf887209dc96142cd79cdfff389" + version = "0.9.9" [[projects]] name = "github.com/tendermint/go-crypto" @@ -454,6 +454,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "dc095a5d071dc8e1d7c3fd1208efbbe7d3c09551ecef76fdfafcdcdd88a49f50" + inputs-digest = "5ec04e1fee08c36e90fd44ec2cdd217f41d80ef5b256fee07cf4030c6cdfd413" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 61d11f999b..ce6ecda982 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -62,9 +62,9 @@ [[constraint]] name = "github.com/tendermint/go-amino" - version = "~0.9.9" + version = "=0.9.9" -[[override]] +[[constraint]] name = "github.com/tendermint/iavl" branch = "develop" diff --git a/client/tx/search.go b/client/tx/search.go index 672f29ff14..527661626a 100644 --- a/client/tx/search.go +++ b/client/tx/search.go @@ -61,12 +61,15 @@ func searchTx(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]byte, } prove := !viper.GetBool(client.FlagTrustNode) - txs, err := node.TxSearch(query, prove) + // TODO: take these as args + page := 0 + perPage := 100 + res, err := node.TxSearch(query, prove, page, perPage) if err != nil { return nil, err } - info, err := formatTxResults(cdc, txs) + info, err := formatTxResults(cdc, res.Txs) if err != nil { return nil, err } From 4447440c2907d15d50ba26a9345856018dc3f3c4 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 05:47:28 +0200 Subject: [PATCH 053/128] Switch to tagged ABCI version --- Gopkg.lock | 3 ++- Gopkg.toml | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index e30a97fda3..f4da3a15cc 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -262,6 +262,7 @@ "types" ] revision = "f9dce537281ffba5d1e047e6729429f7e5fb90c9" + version = "v0.11.0-rc0" [[projects]] branch = "master" @@ -454,6 +455,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "5ec04e1fee08c36e90fd44ec2cdd217f41d80ef5b256fee07cf4030c6cdfd413" + inputs-digest = "ad811206ccd65d54f53041f1284d45d3645c1e89b77e1e6843af786630f0b587" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index ce6ecda982..74569e5082 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -52,9 +52,9 @@ name = "github.com/stretchr/testify" version = "~1.2.1" -[[override]] +[[constraint]] name = "github.com/tendermint/abci" - revision = "f9dce537281ffba5d1e047e6729429f7e5fb90c9" + version = "0.11.0-rc0" [[constraint]] name = "github.com/tendermint/go-crypto" From a5395f061925e87232589bb605b60ecc01671d20 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 06:07:55 +0200 Subject: [PATCH 054/128] Swap to tagged IAVL version --- Gopkg.lock | 6 +++--- Gopkg.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index f4da3a15cc..39e549b08f 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -293,13 +293,13 @@ version = "v0.6.2" [[projects]] - branch = "develop" name = "github.com/tendermint/iavl" packages = [ ".", "sha256truncated" ] revision = "c9206995e8f948e99927f5084a88a7e94ca256da" + version = "v0.8.0-rc0" [[projects]] branch = "cwgoes/update-abci" @@ -342,7 +342,7 @@ "types/priv_validator", "version" ] - revision = "3b8c1ae119da990664f3b98bb2518032f5d837f9" + revision = "3bf9a7dc503b8fd39bda3d64f2d039253afa6f8c" [[projects]] name = "github.com/tendermint/tmlibs" @@ -455,6 +455,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "ad811206ccd65d54f53041f1284d45d3645c1e89b77e1e6843af786630f0b587" + inputs-digest = "473825a42fdba2832156190a00251b6f06aa6f039e5931ec00219b1b7004a89e" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 74569e5082..8dc5a7a7f5 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -66,7 +66,7 @@ [[constraint]] name = "github.com/tendermint/iavl" - branch = "develop" + version = "0.8.0-rc0" [[override]] name = "github.com/tendermint/tendermint" From 99e5c5a18ff056f392462e3924a19bceeb71ffaf Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Tue, 29 May 2018 15:07:03 +0900 Subject: [PATCH 055/128] 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 0959a29c71..6c5bcfd711 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 cbcf5f5e8e..0388467c44 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 6712ea7f3a14d78be83b59eb45c3316ef99314c4 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 08:32:39 +0200 Subject: [PATCH 056/128] Present, not absent --- x/slashing/tick.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/slashing/tick.go b/x/slashing/tick.go index 0d200f5934..8125522741 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -40,11 +40,11 @@ func NewBeginBlocker(sk Keeper) sdk.BeginBlocker { // Iterate over all the validators which *should* have signed this block sk.stakeKeeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { pubkey := validator.GetPubKey() - abs := false + present := true if _, ok := absent[pubkey]; ok { - abs = true + present = false } - sk.handleValidatorSignature(ctx, pubkey, abs) + sk.handleValidatorSignature(ctx, pubkey, present) return false }) From 74e8159c3ff1a9f14cd5eab8ee0289b81ff07028 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 08:49:37 +0200 Subject: [PATCH 057/128] Force update staking store --- x/stake/genesis.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index d45adc3d7f..e8965dcf2f 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -32,11 +32,15 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { k.setPool(ctx, data.Pool) k.setNewParams(ctx, data.Params) for _, validator := range data.Validators { + // Staking assumes bonded validators are already stored, need to force update + validator.PoolShares.Status = sdk.Unbonded k.updateValidator(ctx, validator) } for _, bond := range data.Bonds { k.setDelegation(ctx, bond) } + store := ctx.KVStore(k.storeKey) + k.updateBondedValidatorsFull(ctx, store) } // WriteGenesis - output genesis parameters From 9dfaf1797c89a385107cce7e6b5cd72d6dce928e Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 08:56:53 +0200 Subject: [PATCH 058/128] Staking InitGenesis fix II --- x/stake/genesis.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index e8965dcf2f..e6baa099b5 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -34,6 +34,7 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { for _, validator := range data.Validators { // Staking assumes bonded validators are already stored, need to force update validator.PoolShares.Status = sdk.Unbonded + k.setValidator(ctx, validator) k.updateValidator(ctx, validator) } for _, bond := range data.Bonds { From 3b4aa4d0ae89165609223ad48595c1d829f7ed6b Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 29 May 2018 21:46:38 +0200 Subject: [PATCH 059/128] Minor test fix after merge --- x/slashing/test_common.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 8ce654f338..0228e9498b 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -81,10 +81,7 @@ func newPubKey(pk string) (res crypto.PubKey) { } func testAddr(addr string) sdk.Address { - res, err := sdk.GetAddress(addr) - if err != nil { - panic(err) - } + res := []byte(addr) return res } From 52cd8b8c1fe25dacb6910b84189755bd5bad4a7b Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 30 May 2018 07:42:59 -0700 Subject: [PATCH 060/128] 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 f4686befde..f47cc7ff41 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 6c5bcfd711..289075bc9a 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 079dd003d8..26b508e0d5 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 0388467c44..1eda2ac532 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 2560fcc9f0..2718b3876e 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 061/128] 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 1eda2ac532..41b0fa0852 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 062/128] 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 c8d493d1f6..8c6530dec2 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 41b0fa0852..3e439c2b44 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 2718b3876e..eaf206bf6b 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())) From c8133a0f6a96bfddd3cf2398986b0a503dcf5f53 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 30 May 2018 14:43:22 -0700 Subject: [PATCH 063/128] fix revoke validator bug --- client/context/helpers.go | 2 +- x/stake/keeper.go | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/client/context/helpers.go b/client/context/helpers.go index f4686befde..f47cc7ff41 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/x/stake/keeper.go b/x/stake/keeper.go index d943193a11..a3991a6c60 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -220,8 +220,12 @@ func (k Keeper) updateValidator(ctx sdk.Context, validator Validator) Validator oldValidator, oldFound := k.GetValidator(ctx, ownerAddr) if validator.Revoked && oldValidator.Status() == sdk.Bonded { - validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) - k.setPool(ctx, pool) + k.unbondValidator(ctx, store, validator) + + // need to also clear the cliff validator spot because the revoke has + // opened up a new spot which will be filled when + // updateValidatorsBonded is called + k.clearCliffValidator(ctx) } powerIncreasing := false @@ -674,6 +678,13 @@ func (k Keeper) setCliffValidator(ctx sdk.Context, validator Validator, pool Poo store.Set(ValidatorCliffKey, validator.Owner) } +// clear the current validator and power of the validator on the cliff +func (k Keeper) clearCliffValidator(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Set(ValidatorPowerCliffKey, nil) + store.Set(ValidatorCliffKey, nil) +} + //__________________________________________________________________________ // Implements ValidatorSet From 40526d3e770681fd0109659019df31a3c52d6665 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 30 May 2018 14:52:56 -0700 Subject: [PATCH 064/128] unbond validator return updated validator --- x/stake/keeper.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x/stake/keeper.go b/x/stake/keeper.go index a3991a6c60..c97e7840e1 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -220,7 +220,7 @@ func (k Keeper) updateValidator(ctx sdk.Context, validator Validator) Validator oldValidator, oldFound := k.GetValidator(ctx, ownerAddr) if validator.Revoked && oldValidator.Status() == sdk.Bonded { - k.unbondValidator(ctx, store, validator) + validator = k.unbondValidator(ctx, store, validator) // need to also clear the cliff validator spot because the revoke has // opened up a new spot which will be filled when @@ -430,7 +430,7 @@ func (k Keeper) updateBondedValidatorsFull(ctx sdk.Context, store sdk.KVStore) { } // perform all the store operations for when a validator status becomes unbonded -func (k Keeper) unbondValidator(ctx sdk.Context, store sdk.KVStore, validator Validator) { +func (k Keeper) unbondValidator(ctx sdk.Context, store sdk.KVStore, validator Validator) Validator { pool := k.GetPool(ctx) // sanity check @@ -452,6 +452,7 @@ func (k Keeper) unbondValidator(ctx sdk.Context, store sdk.KVStore, validator Va // also remove from the Bonded Validators Store store.Delete(GetValidatorsBondedKey(validator.PubKey)) + return validator } // perform all the store operations for when a validator status becomes bonded From 4e266013a8ffcbf9a9a9a5545c2f8bbcbd0e2906 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 00:13:13 +0200 Subject: [PATCH 065/128] store.Delete instead of store.Set to nil --- x/stake/keeper.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/stake/keeper.go b/x/stake/keeper.go index c97e7840e1..4f93308c73 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -682,8 +682,8 @@ func (k Keeper) setCliffValidator(ctx sdk.Context, validator Validator, pool Poo // clear the current validator and power of the validator on the cliff func (k Keeper) clearCliffValidator(ctx sdk.Context) { store := ctx.KVStore(k.storeKey) - store.Set(ValidatorPowerCliffKey, nil) - store.Set(ValidatorCliffKey, nil) + store.Delete(ValidatorPowerCliffKey) + store.Delete(ValidatorCliffKey) } //__________________________________________________________________________ From 5f03e370c313d492858615af2d61c9af9c0f4a5d Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 00:19:23 +0200 Subject: [PATCH 066/128] Remove ValidatorByPubKey, don't marshal sdk.Address --- types/stake.go | 11 +++++------ x/slashing/keeper_test.go | 10 +++++----- x/stake/keeper.go | 18 +++--------------- 3 files changed, 13 insertions(+), 26 deletions(-) diff --git a/types/stake.go b/types/stake.go index cd1a68533f..bfcef7fa0c 100644 --- a/types/stake.go +++ b/types/stake.go @@ -56,12 +56,11 @@ type ValidatorSet interface { IterateValidatorsBonded(Context, func(index int64, validator Validator) (stop bool)) - Validator(Context, Address) Validator // get a particular validator by owner address - ValidatorByPubKey(Context, crypto.PubKey) Validator // get a particular validator by public key - TotalPower(Context) Rat // total power of the validator set - Slash(Context, crypto.PubKey, int64, Rat) // slash the validator and delegators of the validator, specifying offence height & slash fraction - Revoke(Context, crypto.PubKey) // revoke a validator - Unrevoke(Context, crypto.PubKey) // unrevoke a validator + Validator(Context, Address) Validator // get a particular validator by owner address + TotalPower(Context) Rat // total power of the validator set + Slash(Context, crypto.PubKey, int64, Rat) // slash the validator and delegators of the validator, specifying offence height & slash fraction + Revoke(Context, crypto.PubKey) // revoke a validator + Unrevoke(Context, crypto.PubKey) // unrevoke a validator } //_______________________________________________________________________________ diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 2fef0c974a..70f42b3243 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -62,7 +62,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, int64(0), info.StartHeight) require.Equal(t, SignedBlocksWindow-50, info.SignedBlocksCounter) // validator should be bonded still - validator := sk.ValidatorByPubKey(ctx, val) + validator, _ := sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) pool := sk.GetPool(ctx) require.Equal(t, int64(100), pool.BondedTokens) @@ -74,7 +74,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, int64(0), info.StartHeight) require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter) // validator should have been revoked - validator = sk.ValidatorByPubKey(ctx, val) + validator, _ = sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Unbonded, validator.GetStatus()) // unrevocation should fail prior to jail expiration got = slh(ctx, NewMsgUnrevoke(addr)) @@ -84,7 +84,7 @@ func TestHandleAbsentValidator(t *testing.T) { got = slh(ctx, NewMsgUnrevoke(addr)) require.True(t, got.IsOK()) // validator should be rebonded now - validator = sk.ValidatorByPubKey(ctx, val) + validator, _ = sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) // validator should have been slashed pool = sk.GetPool(ctx) @@ -98,7 +98,7 @@ func TestHandleAbsentValidator(t *testing.T) { height++ ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, false) - validator = sk.ValidatorByPubKey(ctx, val) + validator, _ = sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) // validator should be revoked again after 100 unsigned blocks nextHeight := height + 100 @@ -106,6 +106,6 @@ func TestHandleAbsentValidator(t *testing.T) { ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, false) } - validator = sk.ValidatorByPubKey(ctx, val) + validator, _ = sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Unbonded, validator.GetStatus()) } diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 4f93308c73..bab1328bed 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -42,12 +42,10 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator Valid // get a single validator by pubkey func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (validator Validator, found bool) { store := ctx.KVStore(k.storeKey) - b := store.Get(GetValidatorByPubKeyKey(pubkey)) - if b == nil { + addr := store.Get(GetValidatorByPubKeyKey(pubkey)) + if addr == nil { return validator, false } - var addr sdk.Address - k.cdc.MustUnmarshalBinary(b, &addr) return k.getValidator(store, addr) } @@ -68,8 +66,7 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) { bz := k.cdc.MustMarshalBinary(validator) store.Set(GetValidatorKey(validator.Owner), bz) // set pointer by pubkey - bz = k.cdc.MustMarshalBinary(validator.Owner) - store.Set(GetValidatorByPubKeyKey(validator.PubKey), bz) + store.Set(GetValidatorByPubKeyKey(validator.PubKey), validator.Owner) } // Get the set of all validators with no limits, used during genesis dump @@ -740,15 +737,6 @@ func (k Keeper) Validator(ctx sdk.Context, addr sdk.Address) sdk.Validator { return val } -// get the sdk.validator for a particular pubkey -func (k Keeper) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) sdk.Validator { - val, found := k.GetValidatorByPubKey(ctx, pubkey) - if !found { - return nil - } - return val -} - // total power from the bond func (k Keeper) TotalPower(ctx sdk.Context) sdk.Rat { pool := k.GetPool(ctx) From 1a3ef511298ef7891ea648e20a23944bb6e75a6b Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 00:21:00 +0200 Subject: [PATCH 067/128] PubKeyKey => PubKeyIndexKey --- x/stake/keeper.go | 6 +++--- x/stake/keeper_keys.go | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/x/stake/keeper.go b/x/stake/keeper.go index bab1328bed..21b58c1feb 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -42,7 +42,7 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator Valid // get a single validator by pubkey func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (validator Validator, found bool) { store := ctx.KVStore(k.storeKey) - addr := store.Get(GetValidatorByPubKeyKey(pubkey)) + addr := store.Get(GetValidatorByPubKeyIndexKey(pubkey)) if addr == nil { return validator, false } @@ -66,7 +66,7 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) { bz := k.cdc.MustMarshalBinary(validator) store.Set(GetValidatorKey(validator.Owner), bz) // set pointer by pubkey - store.Set(GetValidatorByPubKeyKey(validator.PubKey), validator.Owner) + store.Set(GetValidatorByPubKeyIndexKey(validator.PubKey), validator.Owner) } // Get the set of all validators with no limits, used during genesis dump @@ -489,7 +489,7 @@ func (k Keeper) removeValidator(ctx sdk.Context, address sdk.Address) { store := ctx.KVStore(k.storeKey) pool := k.getPool(store) store.Delete(GetValidatorKey(address)) - store.Delete(GetValidatorByPubKeyKey(validator.PubKey)) + store.Delete(GetValidatorByPubKeyIndexKey(validator.PubKey)) store.Delete(GetValidatorsByPowerKey(validator, pool)) // delete from the current and power weighted validator groups if the validator diff --git a/x/stake/keeper_keys.go b/x/stake/keeper_keys.go index e09a47ecab..632a86ec3c 100644 --- a/x/stake/keeper_keys.go +++ b/x/stake/keeper_keys.go @@ -13,17 +13,17 @@ import ( //nolint var ( // Keys for store prefixes - ParamKey = []byte{0x00} // key for parameters relating to staking - PoolKey = []byte{0x01} // key for the staking pools - ValidatorsKey = []byte{0x02} // prefix for each key to a validator - ValidatorsByPubKeyKey = []byte{0x03} // prefix for each key to a validator by pubkey - ValidatorsBondedKey = []byte{0x04} // prefix for each key to bonded/actively validating validators - ValidatorsByPowerKey = []byte{0x05} // prefix for each key to a validator sorted by power - ValidatorCliffKey = []byte{0x06} // key for block-local tx index - ValidatorPowerCliffKey = []byte{0x07} // key for block-local tx index - TendermintUpdatesKey = []byte{0x08} // prefix for each key to a validator which is being updated - DelegationKey = []byte{0x09} // prefix for each key to a delegator's bond - IntraTxCounterKey = []byte{0x10} // key for block-local tx index + ParamKey = []byte{0x00} // key for parameters relating to staking + PoolKey = []byte{0x01} // key for the staking pools + ValidatorsKey = []byte{0x02} // prefix for each key to a validator + ValidatorsByPubKeyIndexKey = []byte{0x03} // prefix for each key to a validator by pubkey + ValidatorsBondedKey = []byte{0x04} // prefix for each key to bonded/actively validating validators + ValidatorsByPowerKey = []byte{0x05} // prefix for each key to a validator sorted by power + ValidatorCliffKey = []byte{0x06} // key for block-local tx index + ValidatorPowerCliffKey = []byte{0x07} // key for block-local tx index + TendermintUpdatesKey = []byte{0x08} // prefix for each key to a validator which is being updated + DelegationKey = []byte{0x09} // prefix for each key to a delegator's bond + IntraTxCounterKey = []byte{0x10} // key for block-local tx index ) const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch @@ -34,8 +34,8 @@ func GetValidatorKey(ownerAddr sdk.Address) []byte { } // get the key for the validator with pubkey -func GetValidatorByPubKeyKey(pubkey crypto.PubKey) []byte { - return append(ValidatorsByPubKeyKey, pubkey.Bytes()...) +func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte { + return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...) } // get the key for the current validator group, ordered like tendermint From 99bed49c8d3e5d695de2e4fe5c7e9199c8e79671 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 00:25:18 +0200 Subject: [PATCH 068/128] Minor wording changes --- x/slashing/errors.go | 6 +----- x/slashing/handler.go | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/x/slashing/errors.go b/x/slashing/errors.go index 8a923f7542..087dc03141 100644 --- a/x/slashing/errors.go +++ b/x/slashing/errors.go @@ -1,3 +1,4 @@ +//nolint package slashing import ( @@ -17,17 +18,12 @@ const ( CodeValidatorJailed CodeType = 202 ) -//nolint func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error { return newError(codespace, CodeInvalidValidator, "That address is not associated with any known validator") } - -//nolint func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { return newError(codespace, CodeInvalidValidator, "Validator does not exist for that address") } - -//nolint func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { return newError(codespace, CodeValidatorJailed, "Validator jailed, cannot yet be unrevoked") } diff --git a/x/slashing/handler.go b/x/slashing/handler.go index cf83a6a992..98e9d30ada 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -16,7 +16,7 @@ func NewHandler(k Keeper) sdk.Handler { } } -// Validators must submit a transaction to unrevoke themselves after +// Validators must submit a transaction to unrevoke itself after // having been revoked (and thus unbonded) for downtime func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { From 004e10ebcdc4228946eaf2b322205216ae527c7c Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 00:32:08 +0200 Subject: [PATCH 069/128] More comments on counter logic --- x/slashing/keeper.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 46ed4591b2..a37c5a07b8 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -62,15 +62,17 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, signInfo.IndexOffset++ // Update signed block bit array & counter + // This counter just tracks the sum of the bit array + // That way we avoid needing to read/write the whole array each time previous := k.getValidatorSigningBitArray(ctx, address, index) if previous == signed { - // No need to update counter + // Array value at this index has not changed, no need to update counter } else if previous && !signed { - // Signed => unsigned, decrement counter + // Array value has changed from signed to unsigned, decrement counter k.setValidatorSigningBitArray(ctx, address, index, false) signInfo.SignedBlocksCounter-- } else if !previous && signed { - // Unsigned => signed, increment counter + // Array value has changed from unsigned to signed, increment counter k.setValidatorSigningBitArray(ctx, address, index, true) signInfo.SignedBlocksCounter++ } From 0324be418951bfe098d4a7d112dc23ca9553b363 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 00:38:20 +0200 Subject: [PATCH 070/128] Clarify comment on removePoolShares --- x/stake/validator.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/x/stake/validator.go b/x/stake/validator.go index 1edb8bb836..729a605a96 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -155,18 +155,20 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, return v, pool } -// Remove & burn pool shares, e.g. when slashing a validator -func (v Validator) removePoolShares(pool Pool, amt sdk.Rat) (Validator, Pool, int64) { +// Remove pool shares +// Returns corresponding tokens, which could be burned (e.g. when slashing +// a validator) or redistributed elsewhere +func (v Validator) removePoolShares(pool Pool, poolShares sdk.Rat) (Validator, Pool, int64) { var tokens int64 switch v.Status() { case sdk.Unbonded: - pool, tokens = pool.removeSharesUnbonded(amt) + pool, tokens = pool.removeSharesUnbonded(poolShares) case sdk.Unbonding: - pool, tokens = pool.removeSharesUnbonding(amt) + pool, tokens = pool.removeSharesUnbonding(poolShares) case sdk.Bonded: - pool, tokens = pool.removeSharesBonded(amt) + pool, tokens = pool.removeSharesBonded(poolShares) } - v.PoolShares.Amount = v.PoolShares.Amount.Sub(amt) + v.PoolShares.Amount = v.PoolShares.Amount.Sub(poolShares) return v, pool, tokens } From 7e9192f513c16d1c1fd93af3bee9a132f88adf50 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 00:41:28 +0200 Subject: [PATCH 071/128] Separate validator pub key index updates --- x/stake/genesis.go | 1 + x/stake/handler.go | 1 + x/stake/keeper.go | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index e6baa099b5..a2cd58bdb5 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -35,6 +35,7 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { // Staking assumes bonded validators are already stored, need to force update validator.PoolShares.Status = sdk.Unbonded k.setValidator(ctx, validator) + k.setValidatorByPubKeyIndex(ctx, validator) k.updateValidator(ctx, validator) } for _, bond := range data.Bonds { diff --git a/x/stake/handler.go b/x/stake/handler.go index 53653557cc..6f2360adf7 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -55,6 +55,7 @@ func handleMsgDeclareCandidacy(ctx sdk.Context, msg MsgDeclareCandidacy, k Keepe validator := NewValidator(msg.ValidatorAddr, msg.PubKey, msg.Description) k.setValidator(ctx, validator) + k.setValidatorByPubKeyIndex(ctx, validator) tags := sdk.NewTags( "action", []byte("declareCandidacy"), "validator", msg.ValidatorAddr.Bytes(), diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 21b58c1feb..b94f392a63 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -65,6 +65,10 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) { // set main store bz := k.cdc.MustMarshalBinary(validator) store.Set(GetValidatorKey(validator.Owner), bz) +} + +func (k Keeper) setValidatorByPubKeyIndex(ctx sdk.Context, validator Validator) { + store := ctx.KVStore(k.storeKey) // set pointer by pubkey store.Set(GetValidatorByPubKeyIndexKey(validator.PubKey), validator.Owner) } From f5f53c0a8df6677f7f215d754c3b139e012d69b3 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 00:55:16 +0200 Subject: [PATCH 072/128] Remove spec changes (now in #1048) --- docs/spec/staking/old/spec.md | 12 ++--- docs/spec/staking/old/spec2.md | 18 +++---- docs/spec/staking/transactions.md | 4 +- docs/spec/staking/valset-changes.md | 80 ++++++++++++----------------- 4 files changed, 51 insertions(+), 63 deletions(-) diff --git a/docs/spec/staking/old/spec.md b/docs/spec/staking/old/spec.md index 1eddc3e33d..bd87ec0285 100644 --- a/docs/spec/staking/old/spec.md +++ b/docs/spec/staking/old/spec.md @@ -297,12 +297,12 @@ type TxProveLive struct { ## Delegator bond Atom holders may delegate coins to validators, under this circumstance their -funds are held in a `Delegation`. It is owned by one delegator, and is +funds are held in a `DelegatorBond`. It is owned by one delegator, and is associated with the shares for one validator. The sender of the transaction is considered to be the owner of the bond, ``` golang -type Delegation struct { +type DelegatorBond struct { Candidate crypto.PubKey Shares rational.Rat AdjustmentFeePool coin.Coins @@ -318,11 +318,11 @@ Description: - AdjustmentRewardPool: Adjustment factor used to passively calculate each bonds entitled fees from `Candidate.ProposerRewardPool`` -Each `Delegation` is individually indexed within the store by delegator +Each `DelegatorBond` is individually indexed within the store by delegator address and candidate pubkey. - key: Delegator and Candidate-Pubkey - - value: Delegation + - value: DelegatorBond ### Delegating @@ -330,7 +330,7 @@ address and candidate pubkey. Delegator bonds are created using the TxDelegate transaction. Within this transaction the validator candidate queried with an amount of coins, whereby given the current exchange rate of candidate's delegator-shares-to-atoms the -candidate will return shares which are assigned in `Delegation.Shares`. +candidate will return shares which are assigned in `DelegatorBond.Shares`. ``` golang type TxDelegate struct { @@ -671,5 +671,5 @@ rate, all commission on fees must be simultaneously withdrawn. `candidate.Adjustment` must be set to the value of `canidate.Count` for the height which the candidate is added on the validator set. - The feePool of a new delegator bond will be 0 for the height at which the bond - was added. This is achieved by setting `Delegation.FeeWithdrawalHeight` to + was added. This is achieved by setting `DelegatorBond.FeeWithdrawalHeight` to the height which the bond was added. diff --git a/docs/spec/staking/old/spec2.md b/docs/spec/staking/old/spec2.md index 68f20703dc..72bb8a2e37 100644 --- a/docs/spec/staking/old/spec2.md +++ b/docs/spec/staking/old/spec2.md @@ -34,7 +34,7 @@ The staking module persists the following to the store: - `GlobalState`, describing the global pools - a `Candidate` for each candidate validator, indexed by public key - a `Candidate` for each candidate validator, indexed by shares in the global pool (ie. ordered) -- a `Delegation` for each delegation to a candidate by a delegator, indexed by delegator and candidate +- a `DelegatorBond` for each delegation to a candidate by a delegator, indexed by delegator and candidate public keys - a `Queue` of unbonding delegations (TODO) @@ -146,15 +146,15 @@ When validators are kicked from the validator set they are removed from this list. -### Delegation +### DelegatorBond Atom holders may delegate coins to validators, under this circumstance their -funds are held in a `Delegation`. It is owned by one delegator, and is +funds are held in a `DelegatorBond`. It is owned by one delegator, and is associated with the shares for one validator. The sender of the transaction is considered to be the owner of the bond, ``` golang -type Delegation struct { +type DelegatorBond struct { Candidate crypto.PubKey Shares rational.Rat AdjustmentFeePool coin.Coins @@ -170,11 +170,11 @@ Description: - AdjustmentRewardPool: Adjustment factor used to passively calculate each bonds entitled fees from `Candidate.ProposerRewardPool`` -Each `Delegation` is individually indexed within the store by delegator +Each `DelegatorBond` is individually indexed within the store by delegator address and candidate pubkey. - key: Delegator and Candidate-Pubkey - - value: Delegation + - value: DelegatorBond ### Unbonding Queue @@ -308,7 +308,7 @@ All bonding, whether self-bonding or delegation, is done via Delegator bonds are created using the TxDelegate transaction. Within this transaction the validator candidate queried with an amount of coins, whereby given the current exchange rate of candidate's delegator-shares-to-atoms the -candidate will return shares which are assigned in `Delegation.Shares`. +candidate will return shares which are assigned in `DelegatorBond.Shares`. ``` golang type TxDelegate struct { @@ -616,7 +616,7 @@ synced past the height of the oldest `powerChange`. This trim procedure will occur on an epoch basis. ```golang -type powerChange struct +type powerChange struct { height int64 // block height at change power rational.Rat // total power at change prevpower rational.Rat // total power at previous height-1 @@ -694,5 +694,5 @@ rate, all commission on fees must be simultaneously withdrawn. `candidate.Adjustment` must be set to the value of `canidate.Count` for the height which the candidate is added on the validator set. - The feePool of a new delegator bond will be 0 for the height at which the bond - was added. This is achieved by setting `Delegation.FeeWithdrawalHeight` to + was added. This is achieved by setting `DelegatorBond.FeeWithdrawalHeight` to the height which the bond was added. diff --git a/docs/spec/staking/transactions.md b/docs/spec/staking/transactions.md index eed082503b..52f324b0f7 100644 --- a/docs/spec/staking/transactions.md +++ b/docs/spec/staking/transactions.md @@ -203,7 +203,7 @@ unbond(tx TxUnbond): return removeShares(candidate Candidate, shares rational.Rat): - globalPoolSharesToRemove = DelegatorShareExRate(candidate) * shares + globalPoolSharesToRemove = delegatorShareExRate(candidate) * shares if candidate.Status == Bonded gs.BondedShares -= globalPoolSharesToRemove @@ -218,7 +218,7 @@ removeShares(candidate Candidate, shares rational.Rat): candidate.IssuedDelegatorShares -= shares return returnedCoins -DelegatorShareExRate(candidate Candidate): +delegatorShareExRate(candidate Candidate): if candidate.IssuedDelegatorShares.IsZero() then return rational.One return candidate.GlobalStakeShares / candidate.IssuedDelegatorShares diff --git a/docs/spec/staking/valset-changes.md b/docs/spec/staking/valset-changes.md index 0e635fd047..bc52b89980 100644 --- a/docs/spec/staking/valset-changes.md +++ b/docs/spec/staking/valset-changes.md @@ -31,8 +31,8 @@ tick(ctx Context): if time > unbondDelegationQueue.head().InitTime + UnbondingPeriod for each element elem in the unbondDelegationQueue where time > elem.InitTime + UnbondingPeriod do - transfer(unbondingQueueAddress, elem.Payout, elem.Tokens) - unbondDelegationQueue.remove(elem) + transfer(unbondingQueueAddress, elem.Payout, elem.Tokens) + unbondDelegationQueue.remove(elem) if time > reDelegationQueue.head().InitTime + UnbondingPeriod for each element elem in the unbondDelegationQueue where time > elem.InitTime + UnbondingPeriod do @@ -55,9 +55,9 @@ nextInflation(hrsPerYr rational.Rat): inflation = gs.Inflation + inflationRateChange if inflation > params.InflationMax then inflation = params.InflationMax - + if inflation < params.InflationMin then inflation = params.InflationMin - + return inflation UpdateValidatorSet(): @@ -71,26 +71,26 @@ UpdateValidatorSet(): updateVotingPower(candidates Candidates): foreach candidate in candidates do - candidate.VotingPower = (candidate.IssuedDelegatorShares - candidate.RedelegatingShares) * DelegatorShareExRate(candidate) - + candidate.VotingPower = (candidate.IssuedDelegatorShares - candidate.RedelegatingShares) * delegatorShareExRate(candidate) + candidates.Sort() - + foreach candidate in candidates do - if candidate is not in the first params.MaxVals - candidate.VotingPower = rational.Zero - if candidate.Status == Bonded then bondedToUnbondedPool(candidate Candidate) - - else if candidate.Status == UnBonded then unbondedToBondedPool(candidate) + if candidate is not in the first params.MaxVals + candidate.VotingPower = rational.Zero + if candidate.Status == Bonded then bondedToUnbondedPool(candidate Candidate) + + else if candidate.Status == UnBonded then unbondedToBondedPool(candidate) - saveCandidate(store, c) - + saveCandidate(store, c) + return candidates unbondedToBondedPool(candidate Candidate): removedTokens = exchangeRate(gs.UnbondedShares, gs.UnbondedPool) * candidate.GlobalStakeShares gs.UnbondedShares -= candidate.GlobalStakeShares gs.UnbondedPool -= removedTokens - + gs.BondedPool += removedTokens issuedShares = removedTokens / exchangeRate(gs.BondedShares, gs.BondedPool) gs.BondedShares += issuedShares @@ -155,48 +155,36 @@ The following information is stored with each validator candidate, and is only n ```go type ValidatorSigningInfo struct { - StartHeight int64 - IndexOffset int64 - JailedUntil int64 - SignedBlocksCounter int64 - SignedBlocksBitArray BitArray + StartHeight int64 + SignedBlocksBitArray BitArray } ``` Where: * `StartHeight` is set to the height that the candidate became an active validator (with non-zero voting power). -* `IndexOffset` is incremented each time the candidate was a bonded validator in a block (and may have signed a precommit or not). -* `JailedUntil` is set whenever the candidate is revoked due to downtime -* `SignedBlocksCounter` is a counter kept to avoid unnecessary array reads. `SignedBlocksBitArray.Sum() == SignedBlocksCounter` always. * `SignedBlocksBitArray` is a bit-array of size `SIGNED_BLOCKS_WINDOW` that records, for each of the last `SIGNED_BLOCKS_WINDOW` blocks, -whether or not this validator was included in the LastCommit. It uses a `1` if the validator was included, and a `0` if it was not. Note it is initialized with all 0s. +whether or not this validator was included in the LastCommit. It uses a `0` if the validator was included, and a `1` if it was not. +Note it is initialized with all 0s. At the beginning of each block, we update the signing info for each validator and check if they should be automatically unbonded: ``` -height := block.Height +h = block.Height +index = h % SIGNED_BLOCKS_WINDOW for val in block.Validators: - signInfo = val.SignInfo - index := signInfo.IndexOffset % SIGNED_BLOCKS_WINDOW - signInfo.IndexOffset++ - previous = signInfo.SignedBlocksBitArray.Get(index) + signInfo = val.SignInfo + if val in block.LastCommit: + signInfo.SignedBlocksBitArray.Set(index, 0) + else + signInfo.SignedBlocksBitArray.Set(index, 1) - // update counter if array has changed - if previous and val in block.AbsentValidators: - signInfo.SignedBlocksBitArray.Set(index, 0) - signInfo.SignedBlocksCounter-- - else if !previous and val not in block.AbsentValidators: - signInfo.SignedBlocksBitArray.Set(index, 1) - signInfo.SignedBlocksCounter++ - // else previous == val not in block.AbsentValidators, no change - - // validator must be active for at least SIGNED_BLOCKS_WINDOW - // before they can be automatically unbonded for failing to be - // included in 50% of the recent LastCommits - minHeight = signInfo.StartHeight + SIGNED_BLOCKS_WINDOW - minSigned = SIGNED_BLOCKS_WINDOW / 2 - if height > minHeight AND signInfo.SignedBlocksCounter < minSigned: - signInfo.JailedUntil = block.Time + DOWNTIME_UNBOND_DURATION - slash & unbond the validator + // validator must be active for at least SIGNED_BLOCKS_WINDOW + // before they can be automatically unbonded for failing to be + // included in 50% of the recent LastCommits + minHeight = signInfo.StartHeight + SIGNED_BLOCKS_WINDOW + minSigned = SIGNED_BLOCKS_WINDOW / 2 + blocksSigned = signInfo.SignedBlocksBitArray.Sum() + if h > minHeight AND blocksSigned < minSigned: + unbond the validator ``` From 604fd4c9a78f7397cf6e0629e6a5829c419c9132 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 01:37:38 +0200 Subject: [PATCH 073/128] Address a few style comments --- x/slashing/keeper_test.go | 4 ++-- x/slashing/signing_info.go | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 70f42b3243..c14e063151 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -16,7 +16,7 @@ func TestHandleDoubleSign(t *testing.T) { addr, val, amt := addrs[0], pks[0], int64(100) got := stake.NewHandler(sk)(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) require.True(t, got.IsOK()) - _ = sk.Tick(ctx) + sk.Tick(ctx) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) keeper.handleDoubleSign(ctx, 0, 0, val) // double sign less than max age @@ -33,7 +33,7 @@ func TestHandleAbsentValidator(t *testing.T) { slh := NewHandler(keeper) got := sh(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) require.True(t, got.IsOK()) - _ = sk.Tick(ctx) + sk.Tick(ctx) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) info, found := keeper.getValidatorSigningInfo(ctx, val.Address()) diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index fcbb0d1c7e..05285b6809 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -12,10 +12,10 @@ func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (i bz := store.Get(validatorSigningInfoKey(address)) if bz == nil { found = false - } else { - k.cdc.MustUnmarshalBinary(bz, &info) - found = true + return } + k.cdc.MustUnmarshalBinary(bz, &info) + found = true return } @@ -33,9 +33,9 @@ func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.Address if bz == nil { // lazy: treat empty key as unsigned signed = false - } else { - k.cdc.MustUnmarshalBinary(bz, &signed) + return } + k.cdc.MustUnmarshalBinary(bz, &signed) return } From 5c4c486e7b0ad51076a8e78f16f0f24a3767ad1d Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 01:39:57 +0200 Subject: [PATCH 074/128] Add newlines to clarify testcase separation --- x/slashing/keeper_test.go | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index c14e063151..3d6da8c232 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -12,6 +12,8 @@ import ( ) func TestHandleDoubleSign(t *testing.T) { + + // initial setup ctx, ck, sk, keeper := createTestInput(t) addr, val, amt := addrs[0], pks[0], int64(100) got := stake.NewHandler(sk)(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) @@ -19,14 +21,20 @@ func TestHandleDoubleSign(t *testing.T) { sk.Tick(ctx) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) - keeper.handleDoubleSign(ctx, 0, 0, val) // double sign less than max age + + // double sign less than max age + keeper.handleDoubleSign(ctx, 0, 0, val) require.Equal(t, sdk.NewRat(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) ctx = ctx.WithBlockHeader(abci.Header{Time: 300}) - keeper.handleDoubleSign(ctx, 0, 0, val) // double sign past max age + + // double sign past max age + keeper.handleDoubleSign(ctx, 0, 0, val) require.Equal(t, sdk.NewRat(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) } func TestHandleAbsentValidator(t *testing.T) { + + // initial setup ctx, ck, sk, keeper := createTestInput(t) addr, val, amt := addrs[0], pks[0], int64(100) sh := stake.NewHandler(sk) @@ -43,7 +51,8 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, int64(0), info.SignedBlocksCounter) require.Equal(t, int64(0), info.JailedUntil) height := int64(0) - // 1000 blocks OK + + // 1000 first blocks OK for ; height < 1000; height++ { ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, true) @@ -52,6 +61,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, SignedBlocksWindow, info.SignedBlocksCounter) + // 50 blocks missed for ; height < 1050; height++ { ctx = ctx.WithBlockHeight(height) @@ -61,11 +71,13 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, SignedBlocksWindow-50, info.SignedBlocksCounter) + // validator should be bonded still validator, _ := sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) pool := sk.GetPool(ctx) require.Equal(t, int64(100), pool.BondedTokens) + // 51st block missed ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, false) @@ -73,33 +85,41 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter) + // validator should have been revoked validator, _ = sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Unbonded, validator.GetStatus()) + // unrevocation should fail prior to jail expiration got = slh(ctx, NewMsgUnrevoke(addr)) require.False(t, got.IsOK()) + // unrevocation should succeed after jail expiration ctx = ctx.WithBlockHeader(abci.Header{Time: int64(86400 * 2)}) got = slh(ctx, NewMsgUnrevoke(addr)) require.True(t, got.IsOK()) + // validator should be rebonded now validator, _ = sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) + // validator should have been slashed pool = sk.GetPool(ctx) require.Equal(t, int64(99), pool.BondedTokens) + // validator start height should have been changed info, found = keeper.getValidatorSigningInfo(ctx, val.Address()) require.True(t, found) require.Equal(t, height, info.StartHeight) require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter) + // validator should not be immediately revoked again height++ ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, false) validator, _ = sk.GetValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) + // validator should be revoked again after 100 unsigned blocks nextHeight := height + 100 for ; height <= nextHeight; height++ { From 3d37d51795454c64c9468908af169505bbaccaf1 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 01:47:24 +0200 Subject: [PATCH 075/128] Switch to evidence type enum --- Gopkg.lock | 5 ++--- Gopkg.toml | 4 ++-- x/slashing/tick.go | 5 ++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 57986c440c..5e76a49cfd 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -267,8 +267,7 @@ "server", "types" ] - revision = "f9dce537281ffba5d1e047e6729429f7e5fb90c9" - version = "v0.11.0-rc0" + revision = "c67bb414c7ee617f18d81a50f8a837318bb6d7dc" [[projects]] branch = "master" @@ -461,6 +460,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "04b888e63be8b6999da76f98c44c12a21920b12186378957d6b874270f300aaf" + inputs-digest = "8f9c58893f04daef93d91512e658560cf076a766fc100c8bc4f718d7abf1ea9c" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index d30953da59..843b3c4618 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -52,9 +52,9 @@ name = "github.com/stretchr/testify" version = "~1.2.1" -[[constraint]] +[[override]] name = "github.com/tendermint/abci" - version = "0.11.0-rc0" + revision = "c67bb414c7ee617f18d81a50f8a837318bb6d7dc" [[constraint]] name = "github.com/tendermint/go-crypto" diff --git a/x/slashing/tick.go b/x/slashing/tick.go index 8125522741..14db48b379 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -1,7 +1,6 @@ package slashing import ( - "bytes" "encoding/binary" "fmt" @@ -21,8 +20,8 @@ func NewBeginBlocker(sk Keeper) sdk.BeginBlocker { for _, evidence := range req.ByzantineValidators { var pk crypto.PubKey sk.cdc.MustUnmarshalBinary(evidence.PubKey, &pk) - switch { - case bytes.Compare(evidence.Type, []byte("doubleSign")) == 0: + switch evidence.Type { + case abci.EvidenceType_DOUBLE_SIGN: sk.handleDoubleSign(ctx, evidence.Height, evidence.Time, pk) default: ctx.Logger().With("module", "x/slashing").Error(fmt.Sprintf("Ignored unknown evidence type: %s", string(evidence.Type))) From 141bc5fb1cffcd7ec191a501656e7ba8d39735ae Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 01:52:07 +0200 Subject: [PATCH 076/128] amino.MarshalJSON instead of json.Marshal --- x/slashing/msg.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/x/slashing/msg.go b/x/slashing/msg.go index 72d2255d61..d2676af81a 100644 --- a/x/slashing/msg.go +++ b/x/slashing/msg.go @@ -1,11 +1,12 @@ package slashing import ( - "encoding/json" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" ) +var cdc = wire.NewCodec() + // name to identify transaction types const MsgType = "slashing" @@ -29,7 +30,7 @@ func (msg MsgUnrevoke) GetSigners() []sdk.Address { return []sdk.Address{msg.Val // get the bytes for the message signer to sign on func (msg MsgUnrevoke) GetSignBytes() []byte { - b, err := json.Marshal(msg) + b, err := cdc.MarshalJSON(msg) if err != nil { panic(err) } From e0b5118fce6726250e6ccd830bea6041fd509093 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 03:00:11 +0200 Subject: [PATCH 077/128] Staking InitGenesis fixes --- x/stake/genesis.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index a2cd58bdb5..cd1c0f9959 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -29,19 +29,20 @@ func DefaultGenesisState() GenesisState { // InitGenesis - store genesis parameters func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { + store := ctx.KVStore(k.storeKey) k.setPool(ctx, data.Pool) k.setNewParams(ctx, data.Params) for _, validator := range data.Validators { - // Staking assumes bonded validators are already stored, need to force update - validator.PoolShares.Status = sdk.Unbonded - k.setValidator(ctx, validator) - k.setValidatorByPubKeyIndex(ctx, validator) k.updateValidator(ctx, validator) + k.setValidatorByPubKeyIndex(ctx, validator) + // manually set validator to bonded if necessary + if validator.Status() == sdk.Bonded { + store.Set(GetValidatorsBondedKey(validator.PubKey), validator.Owner) + } } for _, bond := range data.Bonds { k.setDelegation(ctx, bond) } - store := ctx.KVStore(k.storeKey) k.updateBondedValidatorsFull(ctx, store) } From 81e4a9797bccd4b7b036e9159d16c04919be0ec0 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 30 May 2018 18:28:02 -0700 Subject: [PATCH 078/128] genesis validator index setting --- x/stake/genesis.go | 8 ++++++-- x/stake/keeper.go | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index cd1c0f9959..4887a6002c 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -33,9 +33,13 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { k.setPool(ctx, data.Pool) k.setNewParams(ctx, data.Params) for _, validator := range data.Validators { - k.updateValidator(ctx, validator) + + // set validator + k.setValidator(ctx, validator) + + // manually set indexes for the first time k.setValidatorByPubKeyIndex(ctx, validator) - // manually set validator to bonded if necessary + k.setValidatorByPowerIndex(ctx, validator, data.Pool) if validator.Status() == sdk.Bonded { store.Set(GetValidatorsBondedKey(validator.PubKey), validator.Owner) } diff --git a/x/stake/keeper.go b/x/stake/keeper.go index b94f392a63..9fd902053a 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -73,6 +73,11 @@ func (k Keeper) setValidatorByPubKeyIndex(ctx sdk.Context, validator Validator) store.Set(GetValidatorByPubKeyIndexKey(validator.PubKey), validator.Owner) } +func (k Keeper) setValidatorByPowerIndex(ctx sdk.Context, validator Validator, pool Pool) { + store := ctx.KVStore(k.storeKey) + store.Set(GetValidatorsByPowerKey(validator, pool), validator.Owner) +} + // Get the set of all validators with no limits, used during genesis dump func (k Keeper) getAllValidators(ctx sdk.Context) (validators Validators) { store := ctx.KVStore(k.storeKey) From f32093e9e3f4abf454ce896d2692de05b5f752cd Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 05:43:54 +0200 Subject: [PATCH 079/128] Use evidence type constants from Tendermint --- Gopkg.lock | 10 +++++----- Gopkg.toml | 2 +- x/slashing/tick.go | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 5e76a49cfd..e4ae15af4c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -11,7 +11,7 @@ branch = "master" name = "github.com/btcsuite/btcd" packages = ["btcec"] - revision = "bc0944904505aab55e089371a892be2f87883161" + revision = "86fed781132ac890ee03e906e4ecd5d6fa180c64" [[projects]] branch = "master" @@ -267,7 +267,7 @@ "server", "types" ] - revision = "c67bb414c7ee617f18d81a50f8a837318bb6d7dc" + revision = "f9dce537281ffba5d1e047e6729429f7e5fb90c9" [[projects]] branch = "master" @@ -347,7 +347,7 @@ "types/priv_validator", "version" ] - revision = "3bf9a7dc503b8fd39bda3d64f2d039253afa6f8c" + revision = "9cc39a21ddbe8efd005aa5a001f54055a0d14fca" [[projects]] name = "github.com/tendermint/tmlibs" @@ -393,7 +393,7 @@ "internal/timeseries", "trace" ] - revision = "dfa909b99c79129e1100513e5cd36307665e5723" + revision = "1e491301e022f8f977054da4c2d852decd59571f" [[projects]] branch = "master" @@ -460,6 +460,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "8f9c58893f04daef93d91512e658560cf076a766fc100c8bc4f718d7abf1ea9c" + inputs-digest = "da12d07a753d17b8d9b834bb6b4b61617978c3c515fb38aa5dad10a66a8e78e8" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 843b3c4618..cb8fa2559c 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -54,7 +54,7 @@ [[override]] name = "github.com/tendermint/abci" - revision = "c67bb414c7ee617f18d81a50f8a837318bb6d7dc" + revision = "f9dce537281ffba5d1e047e6729429f7e5fb90c9" [[constraint]] name = "github.com/tendermint/go-crypto" diff --git a/x/slashing/tick.go b/x/slashing/tick.go index 14db48b379..402c8997b8 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" + tmtypes "github.com/tendermint/tendermint/types" ) func NewBeginBlocker(sk Keeper) sdk.BeginBlocker { @@ -20,8 +21,8 @@ func NewBeginBlocker(sk Keeper) sdk.BeginBlocker { for _, evidence := range req.ByzantineValidators { var pk crypto.PubKey sk.cdc.MustUnmarshalBinary(evidence.PubKey, &pk) - switch evidence.Type { - case abci.EvidenceType_DOUBLE_SIGN: + switch string(evidence.Type) { + case tmtypes.DUPLICATE_VOTE: sk.handleDoubleSign(ctx, evidence.Height, evidence.Time, pk) default: ctx.Logger().With("module", "x/slashing").Error(fmt.Sprintf("Ignored unknown evidence type: %s", string(evidence.Type))) From d82683ace581453594a058e244c1025fe01ef830 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 19:54:36 +0200 Subject: [PATCH 080/128] Pin to upstream versions --- Gopkg.lock | 7 ++++--- Gopkg.toml | 18 ++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index e4ae15af4c..9c8b9f0ca3 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -268,6 +268,7 @@ "types" ] revision = "f9dce537281ffba5d1e047e6729429f7e5fb90c9" + version = "v0.11.0-rc0" [[projects]] branch = "master" @@ -307,7 +308,6 @@ version = "v0.8.0-rc0" [[projects]] - branch = "cwgoes/update-abci" name = "github.com/tendermint/tendermint" packages = [ "blockchain", @@ -347,7 +347,8 @@ "types/priv_validator", "version" ] - revision = "9cc39a21ddbe8efd005aa5a001f54055a0d14fca" + revision = "73de99ecab464208f6ea3a96525f4e4b78425e61" + version = "v0.20.0-rc0" [[projects]] name = "github.com/tendermint/tmlibs" @@ -460,6 +461,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "da12d07a753d17b8d9b834bb6b4b61617978c3c515fb38aa5dad10a66a8e78e8" + inputs-digest = "a6a5d886519fa9ca97a23715faa852ee14ecb5337e03641d19ea3d3d1c392fee" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index cb8fa2559c..deabcd6452 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -52,9 +52,9 @@ name = "github.com/stretchr/testify" version = "~1.2.1" -[[override]] +[[constraint]] name = "github.com/tendermint/abci" - revision = "f9dce537281ffba5d1e047e6729429f7e5fb90c9" + version = "0.11.0-rc0" [[constraint]] name = "github.com/tendermint/go-crypto" @@ -68,25 +68,23 @@ name = "github.com/tendermint/iavl" version = "0.8.0-rc0" -[[override]] +[[constraint]] name = "github.com/tendermint/tendermint" - branch = "cwgoes/update-abci" + version = "0.20.0-rc0" [[constraint]] name = "github.com/tendermint/tmlibs" version = "~0.8.3-rc0" + +[[constraint]] + name = "github.com/cosmos/bech32cosmos" + branch = "master" # this got updated and broke, so locked to an old working commit ... [[override]] name = "google.golang.org/genproto" revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200" - [[constraint]] - name = "github.com/cosmos/bech32cosmos" - branch = "master" - - [prune] go-tests = true unused-packages = true - From e9545d69ed0b692fefb19ba7c8f78039d3095f89 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 31 May 2018 11:51:15 -0700 Subject: [PATCH 081/128] Switch the default modules to use wire.codec's MarshalJSON instead of json.Marshal --- x/auth/msgs.go | 4 +--- x/auth/stdtx.go | 6 ++---- x/auth/wire.go | 6 ++++++ x/bank/client/rest/sendtx.go | 9 ++++++++- x/bank/msgs.go | 6 ++---- x/bank/msgs_test.go | 6 ++---- x/bank/wire.go | 8 ++++---- x/stake/msg.go | 15 +++------------ x/stake/params.go | 4 ++-- x/stake/pool.go | 4 ++-- x/stake/wire.go | 6 +++++- 11 files changed, 37 insertions(+), 37 deletions(-) diff --git a/x/auth/msgs.go b/x/auth/msgs.go index c449b837b1..3eb5cc8ba2 100644 --- a/x/auth/msgs.go +++ b/x/auth/msgs.go @@ -1,8 +1,6 @@ package auth import ( - "encoding/json" - sdk "github.com/cosmos/cosmos-sdk/types" crypto "github.com/tendermint/go-crypto" ) @@ -30,7 +28,7 @@ func (msg MsgChangeKey) ValidateBasic() sdk.Error { // Implements Msg. func (msg MsgChangeKey) GetSignBytes() []byte { - b, err := json.Marshal(msg) // XXX: ensure some canonical form + b, err := msgCdc.MarshalJSON(msg) // XXX: ensure some canonical form if err != nil { panic(err) } diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go index bc01b01490..4858ae0b43 100644 --- a/x/auth/stdtx.go +++ b/x/auth/stdtx.go @@ -1,8 +1,6 @@ package auth import ( - "encoding/json" - sdk "github.com/cosmos/cosmos-sdk/types" crypto "github.com/tendermint/go-crypto" ) @@ -70,7 +68,7 @@ func (fee StdFee) Bytes() []byte { if len(fee.Amount) == 0 { fee.Amount = sdk.Coins{} } - bz, err := json.Marshal(fee) // TODO + bz, err := msgCdc.MarshalJSON(fee) // TODO if err != nil { panic(err) } @@ -95,7 +93,7 @@ type StdSignDoc struct { // StdSignBytes returns the bytes to sign for a transaction. // TODO: change the API to just take a chainID and StdTx ? func StdSignBytes(chainID string, sequences []int64, fee StdFee, msg sdk.Msg) []byte { - bz, err := json.Marshal(StdSignDoc{ + bz, err := msgCdc.MarshalJSON(StdSignDoc{ ChainID: chainID, Sequences: sequences, FeeBytes: fee.Bytes(), diff --git a/x/auth/wire.go b/x/auth/wire.go index 42b34b96d5..12778bb39b 100644 --- a/x/auth/wire.go +++ b/x/auth/wire.go @@ -10,3 +10,9 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(&BaseAccount{}, "auth/Account", nil) cdc.RegisterConcrete(MsgChangeKey{}, "auth/ChangeKey", nil) } + +var msgCdc = wire.NewCodec() + +func init() { + RegisterWire(msgCdc) +} diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index 6ce472b6fd..4d957c16f4 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -12,6 +12,7 @@ import ( "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/bank" "github.com/cosmos/cosmos-sdk/x/bank/client" ) @@ -30,6 +31,12 @@ type sendBody struct { Sequence int64 `json:"sequence"` } +var msgCdc = wire.NewCodec() + +func init() { + bank.RegisterWire(msgCdc) +} + // SendRequestHandlerFn - http request handler to send coins to a address func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -44,7 +51,7 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont w.Write([]byte(err.Error())) return } - err = json.Unmarshal(body, &m) + err = msgCdc.UnmarshalJSON(body, &m) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) diff --git a/x/bank/msgs.go b/x/bank/msgs.go index c256b6de61..7836056de0 100644 --- a/x/bank/msgs.go +++ b/x/bank/msgs.go @@ -53,8 +53,7 @@ func (msg MsgSend) ValidateBasic() sdk.Error { // Implements Msg. func (msg MsgSend) GetSignBytes() []byte { - cdc := getCodec() - b, err := cdc.MarshalJSON(msg) // XXX: ensure some canonical form + b, err := msgCdc.MarshalJSON(msg) // XXX: ensure some canonical form if err != nil { panic(err) } @@ -103,8 +102,7 @@ func (msg MsgIssue) ValidateBasic() sdk.Error { // Implements Msg. func (msg MsgIssue) GetSignBytes() []byte { - cdc := getCodec() - b, err := cdc.MarshalJSON(msg) // XXX: ensure some canonical form + b, err := msgCdc.MarshalJSON(msg) // XXX: ensure some canonical form if err != nil { panic(err) } diff --git a/x/bank/msgs_test.go b/x/bank/msgs_test.go index fd1992e3c9..8f9791c8d7 100644 --- a/x/bank/msgs_test.go +++ b/x/bank/msgs_test.go @@ -187,9 +187,8 @@ func TestMsgSendGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - cdc := getCodec() unmarshaledMsg := &MsgSend{} - cdc.UnmarshalJSON(res, unmarshaledMsg) + msgCdc.UnmarshalJSON(res, unmarshaledMsg) assert.Equal(t, &msg, unmarshaledMsg) // TODO bad results @@ -263,9 +262,8 @@ func TestMsgIssueGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - cdc := getCodec() unmarshaledMsg := &MsgIssue{} - cdc.UnmarshalJSON(res, unmarshaledMsg) + msgCdc.UnmarshalJSON(res, unmarshaledMsg) assert.Equal(t, &msg, unmarshaledMsg) // TODO bad results diff --git a/x/bank/wire.go b/x/bank/wire.go index 49511ef0e5..f468d3e530 100644 --- a/x/bank/wire.go +++ b/x/bank/wire.go @@ -10,8 +10,8 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(MsgIssue{}, "cosmos-sdk/Issue", nil) } -func getCodec() *wire.Codec { - cdc := wire.NewCodec() - RegisterWire(cdc) - return cdc +var msgCdc = wire.NewCodec() + +func init() { + RegisterWire(msgCdc) } diff --git a/x/stake/msg.go b/x/stake/msg.go index 0adff84d9b..a4d47c7681 100644 --- a/x/stake/msg.go +++ b/x/stake/msg.go @@ -1,10 +1,7 @@ package stake import ( - "encoding/json" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/wire" crypto "github.com/tendermint/go-crypto" ) @@ -20,12 +17,6 @@ const StakingToken = "steak" //Verify interface at compile time var _, _, _, _ sdk.Msg = &MsgDeclareCandidacy{}, &MsgEditCandidacy{}, &MsgDelegate{}, &MsgUnbond{} -var msgCdc = wire.NewCodec() - -func init() { - wire.RegisterCrypto(msgCdc) -} - //______________________________________________________________________ // MsgDeclareCandidacy - struct for unbonding transactions @@ -94,7 +85,7 @@ func (msg MsgEditCandidacy) GetSigners() []sdk.Address { return []sdk.Address{ms // get the bytes for the message signer to sign on func (msg MsgEditCandidacy) GetSignBytes() []byte { - b, err := json.Marshal(msg) + b, err := msgCdc.MarshalJSON(msg) if err != nil { panic(err) } @@ -136,7 +127,7 @@ func (msg MsgDelegate) GetSigners() []sdk.Address { return []sdk.Address{msg.Del // get the bytes for the message signer to sign on func (msg MsgDelegate) GetSignBytes() []byte { - b, err := json.Marshal(msg) + b, err := msgCdc.MarshalJSON(msg) if err != nil { panic(err) } @@ -183,7 +174,7 @@ func (msg MsgUnbond) GetSigners() []sdk.Address { return []sdk.Address{msg.Deleg // get the bytes for the message signer to sign on func (msg MsgUnbond) GetSignBytes() []byte { - b, err := json.Marshal(msg) + b, err := msgCdc.MarshalJSON(msg) if err != nil { panic(err) } diff --git a/x/stake/params.go b/x/stake/params.go index 32b8c0ae83..d1e623658a 100644 --- a/x/stake/params.go +++ b/x/stake/params.go @@ -18,8 +18,8 @@ type Params struct { } func (p Params) equal(p2 Params) bool { - bz1 := cdcEmpty.MustMarshalBinary(&p) - bz2 := cdcEmpty.MustMarshalBinary(&p2) + bz1 := msgCdc.MustMarshalBinary(&p) + bz2 := msgCdc.MustMarshalBinary(&p2) return bytes.Equal(bz1, bz2) } diff --git a/x/stake/pool.go b/x/stake/pool.go index e2547b0503..44cb24652a 100644 --- a/x/stake/pool.go +++ b/x/stake/pool.go @@ -25,8 +25,8 @@ type Pool struct { } func (p Pool) equal(p2 Pool) bool { - bz1 := cdcEmpty.MustMarshalBinary(&p) - bz2 := cdcEmpty.MustMarshalBinary(&p2) + bz1 := msgCdc.MustMarshalBinary(&p) + bz2 := msgCdc.MustMarshalBinary(&p2) return bytes.Equal(bz1, bz2) } diff --git a/x/stake/wire.go b/x/stake/wire.go index 6e6e382606..b6df323c3c 100644 --- a/x/stake/wire.go +++ b/x/stake/wire.go @@ -12,4 +12,8 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(MsgUnbond{}, "cosmos-sdk/MsgUnbond", nil) } -var cdcEmpty = wire.NewCodec() +var msgCdc = wire.NewCodec() + +func init() { + wire.RegisterCrypto(msgCdc) +} From 037110903920070c9cb19f93d6cf902e92b97d29 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Thu, 31 May 2018 12:55:21 -0700 Subject: [PATCH 082/128] Register crypto on amino codecs, update changelog --- CHANGELOG.md | 1 + x/auth/wire.go | 1 + x/stake/wire.go | 1 + 3 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2f68824ae..96944119e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ FEATURES IMPROVEMENTS * bank module uses go-wire codec instead of 'encoding/json' +* auth module uses go-wire codec instead of 'encoding/json' FIXES diff --git a/x/auth/wire.go b/x/auth/wire.go index 12778bb39b..309464c864 100644 --- a/x/auth/wire.go +++ b/x/auth/wire.go @@ -15,4 +15,5 @@ var msgCdc = wire.NewCodec() func init() { RegisterWire(msgCdc) + wire.RegisterCrypto(msgCdc) } diff --git a/x/stake/wire.go b/x/stake/wire.go index b6df323c3c..fb1a1c8867 100644 --- a/x/stake/wire.go +++ b/x/stake/wire.go @@ -15,5 +15,6 @@ func RegisterWire(cdc *wire.Codec) { var msgCdc = wire.NewCodec() func init() { + RegisterWire(msgCdc) wire.RegisterCrypto(msgCdc) } From 27ae1a14900be62d1980ea4f44af638cd8135ef7 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 31 May 2018 22:19:46 +0200 Subject: [PATCH 083/128] Match UnmarshalBinaryBare/MarshalBinaryBare --- Gopkg.lock | 2 +- x/slashing/tick.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 9c8b9f0ca3..a7aed3194e 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -380,7 +380,7 @@ "ripemd160", "salsa20/salsa" ] - revision = "ab813273cd59e1333f7ae7bff5d027d4aadf528c" + revision = "5ba7f63082460102a45837dbd1827e10f9479ac0" [[projects]] branch = "master" diff --git a/x/slashing/tick.go b/x/slashing/tick.go index 402c8997b8..82f76d802f 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -20,7 +20,7 @@ func NewBeginBlocker(sk Keeper) sdk.BeginBlocker { // Deal with any equivocation evidence for _, evidence := range req.ByzantineValidators { var pk crypto.PubKey - sk.cdc.MustUnmarshalBinary(evidence.PubKey, &pk) + sk.cdc.MustUnmarshalBinaryBare(evidence.PubKey, &pk) switch string(evidence.Type) { case tmtypes.DUPLICATE_VOTE: sk.handleDoubleSign(ctx, evidence.Height, evidence.Time, pk) @@ -33,7 +33,7 @@ func NewBeginBlocker(sk Keeper) sdk.BeginBlocker { absent := make(map[crypto.PubKey]struct{}) for _, pubkey := range req.AbsentValidators { var pk crypto.PubKey - sk.cdc.MustUnmarshalBinary(pubkey, &pk) + sk.cdc.MustUnmarshalBinaryBare(pubkey, &pk) absent[pk] = struct{}{} } From 871574888b5baea46ada824d4a0907f7d9a4f0ae Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Thu, 31 May 2018 04:16:05 -0700 Subject: [PATCH 084/128] Make Execute and GoExecute log better --- cmd/gaia/cli_test/cli_test.go | 37 +++--------- tests/gobash.go | 104 ++++++++++++++++++++++---------- tests/process.go | 109 ++++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 60 deletions(-) create mode 100644 tests/process.go diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 0f549d6d6f..7efe07f91a 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -34,8 +34,8 @@ func TestGaiaCLISend(t *testing.T) { flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID) // start gaiad server - cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) - defer cmd.Process.Kill() + proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) + defer proc.Stop(false) fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json") @@ -83,8 +83,8 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID) // start gaiad server - cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) - defer cmd.Process.Kill() + proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) + defer proc.Stop(false) fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json") @@ -115,7 +115,7 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { declStr += fmt.Sprintf(" --validator-address=%v", bechVal) declStr += fmt.Sprintf(" --amount=%v", "3steak") declStr += fmt.Sprintf(" --moniker=%v", "bar-vally") - fmt.Printf("debug declStr: %v\n", declStr) + t.Log(fmt.Sprintf("debug declStr: %v\n", declStr)) executeWrite(t, declStr, pass) time.Sleep(time.Second) // waiting for some blocks to pass barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) @@ -132,7 +132,7 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { //unbondStr += fmt.Sprintf(" --address-delegator=%v", barAddr) //unbondStr += fmt.Sprintf(" --shares=%v", "1") //unbondStr += fmt.Sprintf(" --sequence=%v", "1") - //fmt.Printf("debug unbondStr: %v\n", unbondStr) + //t.Log(fmt.Sprintf("debug unbondStr: %v\n", unbondStr)) //executeWrite(t, unbondStr, pass) //time.Sleep(time.Second * 3) // waiting for some blocks to pass //barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) @@ -142,32 +142,13 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { } func executeWrite(t *testing.T, cmdStr string, writes ...string) { - cmd, wc, _ := tests.GoExecuteT(t, cmdStr) + proc := tests.GoExecuteT(t, cmdStr) for _, write := range writes { - _, err := wc.Write([]byte(write + "\n")) - if err != nil { - fmt.Println(err) - } + _, err := proc.StdinPipe.Write([]byte(write + "\n")) require.NoError(t, err) } - fmt.Printf("debug waiting cmdStr: %v\n", cmdStr) - cmd.Wait() -} - -func executeWritePrint(t *testing.T, cmdStr string, writes ...string) { - cmd, wc, rc := tests.GoExecuteT(t, cmdStr) - - for _, write := range writes { - _, err := wc.Write([]byte(write + "\n")) - require.NoError(t, err) - } - fmt.Printf("debug waiting cmdStr: %v\n", cmdStr) - cmd.Wait() - - bz := make([]byte, 100000) - rc.Read(bz) - fmt.Printf("debug read: %v\n", string(bz)) + proc.Wait() } func executeInit(t *testing.T, cmdStr string) (chainID string) { diff --git a/tests/gobash.go b/tests/gobash.go index baa84f417f..f46bad3c1c 100644 --- a/tests/gobash.go +++ b/tests/gobash.go @@ -1,51 +1,91 @@ package tests import ( - "io" - "os/exec" "strings" "testing" - "time" "github.com/stretchr/testify/require" + cmn "github.com/tendermint/tmlibs/common" ) -func getCmd(t *testing.T, command string) *exec.Cmd { +// Execute the command, return stdout, logging stdout/err to t. +func ExecuteT(t *testing.T, cmd string) (out string) { + t.Log("Running", cmn.Cyan(cmd)) - //split command into command and args - split := strings.Split(command, " ") + // Split cmd to name and args. + split := strings.Split(cmd, " ") require.True(t, len(split) > 0, "no command provided") - - var cmd *exec.Cmd - if len(split) == 1 { - cmd = exec.Command(split[0]) - } else { - cmd = exec.Command(split[0], split[1:]...) + name, args := split[0], []string(nil) + if len(split) > 1 { + args = split[1:] } - return cmd -} -// Execute the command, return standard output and error, try a few times if requested -func ExecuteT(t *testing.T, command string) (out string) { - cmd := getCmd(t, command) - bz, err := cmd.CombinedOutput() - if err != nil { - panic(err) + // Start process and wait. + proc, err := StartProcess("", name, args, nil, nil) + require.NoError(t, err) + proc.Wait() + + // Get the output. + outbz := proc.StdoutBuffer.Bytes() + errbz := proc.StderrBuffer.Bytes() + + // Log output. + if len(outbz) > 0 { + t.Log("Stdout:", cmn.Green(string(outbz))) } - require.NoError(t, err, string(bz)) - out = strings.Trim(string(bz), "\n") //trim any new lines - time.Sleep(time.Second) + if len(errbz) > 0 { + t.Log("Stderr:", cmn.Red(string(errbz))) + } + + // Collect STDOUT output. + out = strings.Trim(string(outbz), "\n") //trim any new lines return out } -// Asynchronously execute the command, return standard output and error -func GoExecuteT(t *testing.T, command string) (cmd *exec.Cmd, pipeIn io.WriteCloser, pipeOut io.ReadCloser) { - cmd = getCmd(t, command) - pipeIn, err := cmd.StdinPipe() +// Execute the command, launch goroutines to log stdout/err to t. +// Caller should wait for .Wait() or .Stop() to terminate. +func GoExecuteT(t *testing.T, cmd string) (proc *Process) { + t.Log("Running", cmn.Cyan(cmd)) + + // Split cmd to name and args. + split := strings.Split(cmd, " ") + require.True(t, len(split) > 0, "no command provided") + name, args := split[0], []string(nil) + if len(split) > 1 { + args = split[1:] + } + + // Start process. + proc, err := StartProcess("", name, args, nil, nil) require.NoError(t, err) - pipeOut, err = cmd.StdoutPipe() - require.NoError(t, err) - cmd.Start() - time.Sleep(time.Second) - return cmd, pipeIn, pipeOut + + // Run goroutines to log stdout. + go func() { + buf := make([]byte, 10240) // TODO Document the effects. + for { + n, err := proc.StdoutBuffer.Read(buf) + if err != nil { + return + } + if n > 0 { + t.Log("Stdout:", cmn.Green(string(buf[:n]))) + } + } + }() + + // Run goroutines to log stderr. + go func() { + buf := make([]byte, 10240) // TODO Document the effects. + for { + n, err := proc.StderrBuffer.Read(buf) + if err != nil { + return + } + if n > 0 { + t.Log("Stderr:", cmn.Red(string(buf[:n]))) + } + } + }() + + return proc } diff --git a/tests/process.go b/tests/process.go new file mode 100644 index 0000000000..fcc6e3e0ea --- /dev/null +++ b/tests/process.go @@ -0,0 +1,109 @@ +package tests + +import ( + "bytes" + "io" + "os" + "os/exec" + "time" +) + +type Process struct { + ExecPath string + Args []string + Pid int + StartTime time.Time + EndTime time.Time + Cmd *exec.Cmd `json:"-"` + ExitState *os.ProcessState `json:"-"` + WaitCh chan struct{} `json:"-"` + StdinPipe io.WriteCloser `json:"-"` + StdoutBuffer *bytes.Buffer `json:"-"` + StderrBuffer *bytes.Buffer `json:"-"` +} + +// dir: The working directory. If "", os.Getwd() is used. +// name: Command name +// args: Args to command. (should not include name) +// outFile, errFile: If not nil, will use, otherwise new Buffers will be +// allocated. Either way, Process.Cmd.StdoutPipe and Process.Cmd.StderrPipe will be nil +// respectively. +func StartProcess(dir string, name string, args []string, outFile, errFile io.WriteCloser) (*Process, error) { + var cmd = exec.Command(name, args...) // is not yet started. + // cmd dir + if dir == "" { + pwd, err := os.Getwd() + if err != nil { + panic(err) + } + cmd.Dir = pwd + } else { + cmd.Dir = dir + } + // cmd stdin + stdin, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + // cmd stdout, stderr + var outBuffer, errBuffer *bytes.Buffer + if outFile != nil { + cmd.Stdout = outFile + } else { + outBuffer = bytes.NewBuffer(nil) + cmd.Stdout = outBuffer + } + if errFile != nil { + cmd.Stderr = errFile + } else { + errBuffer = bytes.NewBuffer(nil) + cmd.Stderr = errBuffer + } + // cmd start + if err := cmd.Start(); err != nil { + return nil, err + } + proc := &Process{ + ExecPath: name, + Args: args, + Pid: cmd.Process.Pid, + StartTime: time.Now(), + Cmd: cmd, + ExitState: nil, + WaitCh: make(chan struct{}), + StdinPipe: stdin, + } + if outBuffer != nil { + proc.StdoutBuffer = outBuffer + } + if errBuffer != nil { + proc.StderrBuffer = errBuffer + } + go func() { + err := proc.Cmd.Wait() + if err != nil { + // fmt.Printf("Process exit: %v\n", err) + if exitError, ok := err.(*exec.ExitError); ok { + proc.ExitState = exitError.ProcessState + } + } + proc.ExitState = proc.Cmd.ProcessState + proc.EndTime = time.Now() // TODO make this goroutine-safe + close(proc.WaitCh) + }() + return proc, nil +} + +func (proc *Process) Stop(kill bool) error { + if kill { + // fmt.Printf("Killing process %v\n", proc.Cmd.Process) + return proc.Cmd.Process.Kill() + } else { + // fmt.Printf("Stopping process %v\n", proc.Cmd.Process) + return proc.Cmd.Process.Signal(os.Interrupt) + } +} + +func (proc *Process) Wait() { + <-proc.WaitCh +} From 94e78e060288a2296b890bcabfb9490ecb35b0ef Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 11:00:54 -0700 Subject: [PATCH 085/128] cech32 fixes for TestGaiaCLISend --- cmd/gaia/cli_test/cli_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 7efe07f91a..c76221c2d7 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -48,10 +48,11 @@ func TestGaiaCLISend(t *testing.T) { if err != nil { t.Error(err) } + time.Sleep(time.Second * 5) // Wait for RPC server to start. fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooBech, flags)) assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak")) - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barAddr), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barBech), pass) time.Sleep(time.Second * 3) // waiting for some blocks to pass barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barBech, flags)) @@ -60,7 +61,7 @@ func TestGaiaCLISend(t *testing.T) { assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak")) // test autosequencing - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barAddr), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barBech), pass) time.Sleep(time.Second * 3) // waiting for some blocks to pass barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barBech, flags)) From afc2bbfe091a46154e271083369768d8032e9bba Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 12:10:12 -0700 Subject: [PATCH 086/128] working through cli --- client/keys/utils.go | 2 +- cmd/gaia/cli_test/cli_test.go | 118 +++++++++++++++++----------------- cmd/gaia/cmd/gaiacli/main.go | 4 +- x/stake/client/cli/tx.go | 4 +- 4 files changed, 65 insertions(+), 63 deletions(-) diff --git a/client/keys/utils.go b/client/keys/utils.go index 1a358cfc9c..7224294290 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -76,7 +76,7 @@ func printInfo(info keys.Info) { fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") printKeyOutput(ko) case "json": - out, err := json.MarshalIndent(ko, "", "\t") + out, err := MarshalJSON(ko) if err != nil { panic(err) } diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index c76221c2d7..8d98486d72 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -36,41 +36,37 @@ func TestGaiaCLISend(t *testing.T) { // start gaiad server proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) defer proc.Stop(false) + time.Sleep(time.Second * 5) // Wait for RPC server to start. fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") + fooCech, err := sdk.Bech32CosmosifyAcc(fooAddr) + require.NoError(t, err) barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json") + barCech, err := sdk.Bech32CosmosifyAcc(barAddr) + require.NoError(t, err) - fooBech, err := sdk.Bech32CosmosifyAcc(fooAddr) - if err != nil { - t.Error(err) - } - barBech, err := sdk.Bech32CosmosifyAcc(barAddr) - if err != nil { - t.Error(err) - } - time.Sleep(time.Second * 5) // Wait for RPC server to start. - fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooBech, flags)) + fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak")) - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barBech), pass) - time.Sleep(time.Second * 3) // waiting for some blocks to pass + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) + time.Sleep(time.Second * 2) // waiting for some blocks to pass - barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barBech, flags)) + barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak")) - fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooBech, flags)) + fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak")) // test autosequencing - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barBech), pass) - time.Sleep(time.Second * 3) // waiting for some blocks to pass + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) + time.Sleep(time.Second * 2) // waiting for some blocks to pass - barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barBech, flags)) + barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) assert.Equal(t, int64(20), barAcc.GetCoins().AmountOf("steak")) - fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooBech, flags)) + fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) assert.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak")) } -func TestGaiaCLIDeclareCandidacy(t *testing.T) { +func TestGaiaCLICreateValidator(t *testing.T) { tests.ExecuteT(t, "gaiad unsafe_reset_all") pass := "1234567890" @@ -86,62 +82,67 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { // start gaiad server proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) defer proc.Stop(false) + time.Sleep(time.Second * 5) // Wait for RPC server to start. fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") - barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json") + fooCech, err := sdk.Bech32CosmosifyAcc(fooAddr) + require.NoError(t, err) + barAddr, barPubKey := executeGetAddrPK(t, "gaiacli keys show bar --output=json") + barCech, err := sdk.Bech32CosmosifyAcc(barAddr) + require.NoError(t, err) + barCeshPubKey, err := sdk.Bech32CosmosifyValPub(barPubKey) + require.NoError(t, err) - fooBech, err := sdk.Bech32CosmosifyAcc(fooAddr) - if err != nil { - t.Error(err) - } - barBech, err := sdk.Bech32CosmosifyAcc(barAddr) - if err != nil { - t.Error(err) - } - valPrivkey := crypto.GenPrivKeyEd25519() - valAddr := sdk.Address((valPrivkey.PubKey().Address())) - bechVal, err := sdk.Bech32CosmosifyVal(valAddr) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) + time.Sleep(time.Second * 2) // waiting for some blocks to pass - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barBech), pass) - time.Sleep(time.Second * 3) // waiting for some blocks to pass - - fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooBech, flags)) - assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak")) - barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barBech, flags)) + barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak")) + fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) + assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak")) + + //valPrivkey := crypto.GenPrivKeyEd25519() + //valAddr := sdk.Address((valPrivkey.PubKey().Address())) + //bechVal, err := sdk.Bech32CosmosifyVal(valAddr) // declare candidacy - declStr := fmt.Sprintf("gaiacli create-validator %v", flags) - declStr += fmt.Sprintf(" --name=%v", "bar") - declStr += fmt.Sprintf(" --validator-address=%v", bechVal) - declStr += fmt.Sprintf(" --amount=%v", "3steak") - declStr += fmt.Sprintf(" --moniker=%v", "bar-vally") - t.Log(fmt.Sprintf("debug declStr: %v\n", declStr)) - executeWrite(t, declStr, pass) - time.Sleep(time.Second) // waiting for some blocks to pass - barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) + cvStr := fmt.Sprintf("gaiacli create-validator %v", flags) + cvStr += fmt.Sprintf(" --name=%v", "bar") + cvStr += fmt.Sprintf(" --validator-address=%v", barCech) + cvStr += fmt.Sprintf(" --pubkey=%v", barCeshPubKey) + cvStr += fmt.Sprintf(" --amount=%v", "3steak") + cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally") + + executeWrite(t, cvStr, pass) + time.Sleep(time.Second * 5) // waiting for some blocks to pass + + barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) assert.Equal(t, int64(7), barAcc.GetCoins().AmountOf("steak")) - candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr)) - assert.Equal(t, candidate.Owner.String(), barAddr) - assert.Equal(t, int64(3), candidate.PoolShares) + + validator := executeGetValidator(t, fmt.Sprintf("gaiacli validator %v %v", barCech, flags)) + assert.Equal(t, validator.Owner.String(), barCech) + assert.Equal(t, int64(3), validator.PoolShares) // TODO timeout issues if not connected to the internet // unbond a single share //unbondStr := fmt.Sprintf("gaiacli unbond %v", flags) //unbondStr += fmt.Sprintf(" --name=%v", "bar") - //unbondStr += fmt.Sprintf(" --address-candidate=%v", barAddr) - //unbondStr += fmt.Sprintf(" --address-delegator=%v", barAddr) + //unbondStr += fmt.Sprintf(" --address-validator=%v", barCech) + //unbondStr += fmt.Sprintf(" --address-delegator=%v", barCech) //unbondStr += fmt.Sprintf(" --shares=%v", "1") //unbondStr += fmt.Sprintf(" --sequence=%v", "1") //t.Log(fmt.Sprintf("debug unbondStr: %v\n", unbondStr)) //executeWrite(t, unbondStr, pass) //time.Sleep(time.Second * 3) // waiting for some blocks to pass - //barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) + //barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) //assert.Equal(t, int64(99998), barAcc.GetCoins().AmountOf("steak")) - //candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr)) - //assert.Equal(t, int64(2), candidate.BondedShares.Evaluate()) + //validator = executeGetValidator(t, fmt.Sprintf("gaiacli validator %v --address-validator=%v", flags, barCech)) + //assert.Equal(t, int64(2), validator.BondedShares.Evaluate()) } +//___________________________________________________________________________________ +// executors + func executeWrite(t *testing.T, cmdStr string, writes ...string) { proc := tests.GoExecuteT(t, cmdStr) @@ -169,6 +170,7 @@ func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.Address, crypto.PubKey) out := tests.ExecuteT(t, cmdStr) var ko keys.KeyOutput keys.UnmarshalJSON([]byte(out), &ko) + return ko.Address, ko.PubKey } @@ -186,11 +188,11 @@ func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount { return acc } -func executeGetCandidate(t *testing.T, cmdStr string) stake.Validator { +func executeGetValidator(t *testing.T, cmdStr string) stake.Validator { out := tests.ExecuteT(t, cmdStr) - var candidate stake.Validator + var validator stake.Validator cdc := app.MakeCodec() - err := cdc.UnmarshalJSON([]byte(out), &candidate) + err := cdc.UnmarshalJSON([]byte(out), &validator) require.NoError(t, err, "out %v, err %v", out, err) - return candidate + return validator } diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index 2f36201b2f..51dab68e28 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -55,8 +55,8 @@ func main() { bankcmd.SendTxCmd(cdc), ibccmd.IBCTransferCmd(cdc), ibccmd.IBCRelayCmd(cdc), - stakecmd.GetCmdDeclareCandidacy(cdc), - stakecmd.GetCmdEditCandidacy(cdc), + stakecmd.GetCmdCreateValidator(cdc), + stakecmd.GetCmdEditValidator(cdc), stakecmd.GetCmdDelegate(cdc), stakecmd.GetCmdUnbond(cdc), )...) diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index dc88bfc209..5cd2656b62 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -14,7 +14,7 @@ import ( ) // create declare candidacy command -func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command { +func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "create-validator", Short: "create new validator initialized with a self-delegation to it", @@ -68,7 +68,7 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command { } // create edit candidacy command -func GetCmdEditCandidacy(cdc *wire.Codec) *cobra.Command { +func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "edit-validator", Short: "edit and existing validator account", From 952aedc4f19c25cc92c5abc8fe7744341d0872d0 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 12:22:46 -0700 Subject: [PATCH 087/128] get rid of candidacy references --- CHANGELOG.md | 4 +- cmd/gaia/app/app_test.go | 12 +++--- cmd/gaia/cli_test/cli_test.go | 2 +- examples/basecoin/cmd/basecli/main.go | 4 +- examples/democoin/x/simplestake/msgs.go | 4 +- x/slashing/keeper_test.go | 4 +- x/slashing/test_common.go | 4 +- x/stake/client/cli/tx.go | 12 +++--- x/stake/errors.go | 4 +- x/stake/handler.go | 24 +++++------ x/stake/handler_test.go | 54 ++++++++++++------------- x/stake/msg.go | 40 +++++++++--------- x/stake/msg_test.go | 16 ++++---- x/stake/test_common.go | 4 +- x/stake/wire.go | 4 +- 15 files changed, 96 insertions(+), 96 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f12eaa4203..8a0bed5b18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,7 +100,7 @@ FEATURES * [gaiacli] Support queries for candidates, delegator-bonds * [gaiad] Added `gaiad export` command to export current state to JSON * [x/bank] Tx tags with sender/recipient for indexing & later retrieval -* [x/stake] Tx tags with delegator/candidate for delegation & unbonding, and candidate info for declare candidate / edit candidacy +* [x/stake] Tx tags with delegator/candidate for delegation & unbonding, and candidate info for declare candidate / edit validator IMPROVEMENTS @@ -134,7 +134,7 @@ BREAKING CHANGES FEATURES: -* Gaia stake commands include, DeclareCandidacy, EditCandidacy, Delegate, Unbond +* Gaia stake commands include, CreateValidator, EditValidator, Delegate, Unbond * MountStoreWithDB without providing a custom store works. * Repo is now lint compliant / GoMetaLinter with tendermint-lint integrated into CI * Better key output, pubkey go-amino hex bytes now output by default diff --git a/cmd/gaia/app/app_test.go b/cmd/gaia/app/app_test.go index b6f1c9e03c..13ffdc33b7 100644 --- a/cmd/gaia/app/app_test.go +++ b/cmd/gaia/app/app_test.go @@ -394,13 +394,13 @@ func TestStakeMsgs(t *testing.T) { require.Equal(t, acc1, res1) require.Equal(t, acc2, res2) - // Declare Candidacy + // Create Validator description := stake.NewDescription("foo_moniker", "", "", "") - declareCandidacyMsg := stake.NewMsgDeclareCandidacy( + createValidatorMsg := stake.NewMsgCreateValidator( addr1, priv1.PubKey(), bondCoin, description, ) - SignCheckDeliver(t, gapp, declareCandidacyMsg, []int64{0}, true, priv1) + SignCheckDeliver(t, gapp, createValidatorMsg, []int64{0}, true, priv1) ctxDeliver := gapp.BaseApp.NewContext(false, abci.Header{}) res1 = gapp.accountMapper.GetAccount(ctxDeliver, addr1) @@ -415,13 +415,13 @@ func TestStakeMsgs(t *testing.T) { bond, found := gapp.stakeKeeper.GetDelegation(ctxDeliver, addr1, addr1) require.True(sdk.RatEq(t, sdk.NewRat(10), bond.Shares)) - // Edit Candidacy + // Edit Validator description = stake.NewDescription("bar_moniker", "", "", "") - editCandidacyMsg := stake.NewMsgEditCandidacy( + editValidatorMsg := stake.NewMsgEditValidator( addr1, description, ) - SignDeliver(t, gapp, editCandidacyMsg, []int64{1}, true, priv1) + SignDeliver(t, gapp, editValidatorMsg, []int64{1}, true, priv1) validator, found = gapp.stakeKeeper.GetValidator(ctxDeliver, addr1) require.True(t, found) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 8d98486d72..79deaeb983 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -105,7 +105,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { //valAddr := sdk.Address((valPrivkey.PubKey().Address())) //bechVal, err := sdk.Bech32CosmosifyVal(valAddr) - // declare candidacy + // create validator cvStr := fmt.Sprintf("gaiacli create-validator %v", flags) cvStr += fmt.Sprintf(" --name=%v", "bar") cvStr += fmt.Sprintf(" --validator-address=%v", barCech) diff --git a/examples/basecoin/cmd/basecli/main.go b/examples/basecoin/cmd/basecli/main.go index f5385b5596..6540af38aa 100644 --- a/examples/basecoin/cmd/basecli/main.go +++ b/examples/basecoin/cmd/basecli/main.go @@ -59,8 +59,8 @@ func main() { bankcmd.SendTxCmd(cdc), ibccmd.IBCTransferCmd(cdc), ibccmd.IBCRelayCmd(cdc), - stakecmd.GetCmdDeclareCandidacy(cdc), - stakecmd.GetCmdEditCandidacy(cdc), + stakecmd.GetCmdCreateValidator(cdc), + stakecmd.GetCmdEditValidator(cdc), stakecmd.GetCmdDelegate(cdc), stakecmd.GetCmdUnbond(cdc), )...) diff --git a/examples/democoin/x/simplestake/msgs.go b/examples/democoin/x/simplestake/msgs.go index 01797a65bf..605f6f4e23 100644 --- a/examples/democoin/x/simplestake/msgs.go +++ b/examples/democoin/x/simplestake/msgs.go @@ -26,7 +26,7 @@ func NewMsgBond(addr sdk.Address, stake sdk.Coin, pubKey crypto.PubKey) MsgBond } //nolint -func (msg MsgBond) Type() string { return moduleName } //TODO update "stake/declarecandidacy" +func (msg MsgBond) Type() string { return moduleName } //TODO update "stake/createvalidator" func (msg MsgBond) GetSigners() []sdk.Address { return []sdk.Address{msg.Address} } // basic validation of the bond message @@ -65,7 +65,7 @@ func NewMsgUnbond(addr sdk.Address) MsgUnbond { } //nolint -func (msg MsgUnbond) Type() string { return moduleName } //TODO update "stake/declarecandidacy" +func (msg MsgUnbond) Type() string { return moduleName } //TODO update "stake/createvalidator" func (msg MsgUnbond) GetSigners() []sdk.Address { return []sdk.Address{msg.Address} } func (msg MsgUnbond) ValidateBasic() sdk.Error { return nil } diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 3d6da8c232..a385627737 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -16,7 +16,7 @@ func TestHandleDoubleSign(t *testing.T) { // initial setup ctx, ck, sk, keeper := createTestInput(t) addr, val, amt := addrs[0], pks[0], int64(100) - got := stake.NewHandler(sk)(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) + got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) require.True(t, got.IsOK()) sk.Tick(ctx) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) @@ -39,7 +39,7 @@ func TestHandleAbsentValidator(t *testing.T) { addr, val, amt := addrs[0], pks[0], int64(100) sh := stake.NewHandler(sk) slh := NewHandler(keeper) - got := sh(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) + got := sh(ctx, newTestMsgCreateValidator(addr, val, amt)) require.True(t, got.IsOK()) sk.Tick(ctx) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 0228e9498b..c76eaadde7 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -85,8 +85,8 @@ func testAddr(addr string) sdk.Address { return res } -func newTestMsgDeclareCandidacy(address sdk.Address, pubKey crypto.PubKey, amt int64) stake.MsgDeclareCandidacy { - return stake.MsgDeclareCandidacy{ +func newTestMsgCreateValidator(address sdk.Address, pubKey crypto.PubKey, amt int64) stake.MsgCreateValidator { + return stake.MsgCreateValidator{ Description: stake.Description{}, ValidatorAddr: address, PubKey: pubKey, diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 5cd2656b62..3abd366ece 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -13,7 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/stake" ) -// create declare candidacy command +// create create validator command func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "create-validator", @@ -47,7 +47,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { Website: viper.GetString(FlagWebsite), Details: viper.GetString(FlagDetails), } - msg := stake.NewMsgDeclareCandidacy(validatorAddr, pk, amount, description) + msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description) // build and sign the transaction, then broadcast to Tendermint res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, msg, cdc) @@ -67,7 +67,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { return cmd } -// create edit candidacy command +// create edit validator command func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "edit-validator", @@ -84,7 +84,7 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { Website: viper.GetString(FlagWebsite), Details: viper.GetString(FlagDetails), } - msg := stake.NewMsgEditCandidacy(validatorAddr, description) + msg := stake.NewMsgEditValidator(validatorAddr, description) // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) @@ -104,7 +104,7 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { return cmd } -// create edit candidacy command +// create edit validator command func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "delegate", @@ -142,7 +142,7 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { return cmd } -// create edit candidacy command +// create edit validator command func GetCmdUnbond(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "unbond", diff --git a/x/stake/errors.go b/x/stake/errors.go index 77090d9dc3..0ae57530ad 100644 --- a/x/stake/errors.go +++ b/x/stake/errors.go @@ -73,10 +73,10 @@ func ErrBadDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { return newError(codespace, CodeInvalidValidator, "Delegator does not exist for that address") } func ErrValidatorExistsAddr(codespace sdk.CodespaceType) sdk.Error { - return newError(codespace, CodeInvalidValidator, "Validator already exist, cannot re-declare candidacy") + return newError(codespace, CodeInvalidValidator, "Validator already exist, cannot re-create validator") } func ErrValidatorRevoked(codespace sdk.CodespaceType) sdk.Error { - return newError(codespace, CodeInvalidValidator, "Candidacy for this address is currently revoked") + return newError(codespace, CodeInvalidValidator, "Validator for this address is currently revoked") } func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error { return newError(codespace, CodeInvalidValidator, "Missing signature") diff --git a/x/stake/handler.go b/x/stake/handler.go index 6f2360adf7..b1c6a95b59 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -11,10 +11,10 @@ func NewHandler(k Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { // NOTE msg already has validate basic run switch msg := msg.(type) { - case MsgDeclareCandidacy: - return handleMsgDeclareCandidacy(ctx, msg, k) - case MsgEditCandidacy: - return handleMsgEditCandidacy(ctx, msg, k) + case MsgCreateValidator: + return handleMsgCreateValidator(ctx, msg, k) + case MsgEditValidator: + return handleMsgEditValidator(ctx, msg, k) case MsgDelegate: return handleMsgDelegate(ctx, msg, k) case MsgUnbond: @@ -39,7 +39,7 @@ func NewEndBlocker(k Keeper) sdk.EndBlocker { // These functions assume everything has been authenticated, // now we just perform action and save -func handleMsgDeclareCandidacy(ctx sdk.Context, msg MsgDeclareCandidacy, k Keeper) sdk.Result { +func handleMsgCreateValidator(ctx sdk.Context, msg MsgCreateValidator, k Keeper) sdk.Result { // check to see if the pubkey or sender has been registered before _, found := k.GetValidator(ctx, msg.ValidatorAddr) @@ -57,7 +57,7 @@ func handleMsgDeclareCandidacy(ctx sdk.Context, msg MsgDeclareCandidacy, k Keepe k.setValidator(ctx, validator) k.setValidatorByPubKeyIndex(ctx, validator) tags := sdk.NewTags( - "action", []byte("declareCandidacy"), + "action", []byte("createValidator"), "validator", msg.ValidatorAddr.Bytes(), "moniker", []byte(msg.Description.Moniker), "identity", []byte(msg.Description.Identity), @@ -75,7 +75,7 @@ func handleMsgDeclareCandidacy(ctx sdk.Context, msg MsgDeclareCandidacy, k Keepe } } -func handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy, k Keeper) sdk.Result { +func handleMsgEditValidator(ctx sdk.Context, msg MsgEditValidator, k Keeper) sdk.Result { // validator must already be registered validator, found := k.GetValidator(ctx, msg.ValidatorAddr) @@ -95,7 +95,7 @@ func handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy, k Keeper) sdk k.updateValidator(ctx, validator) tags := sdk.NewTags( - "action", []byte("editCandidacy"), + "action", []byte("editValidator"), "validator", msg.ValidatorAddr.Bytes(), "moniker", []byte(msg.Description.Moniker), "identity", []byte(msg.Description.Identity), @@ -207,14 +207,14 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result { bond.Shares = bond.Shares.Sub(delShares) // remove the bond - revokeCandidacy := false + revokeValidator := false if bond.Shares.IsZero() { // if the bond is the owner of the validator then - // trigger a revoke candidacy + // trigger a revoke validator if bytes.Equal(bond.DelegatorAddr, validator.Owner) && validator.Revoked == false { - revokeCandidacy = true + revokeValidator = true } k.removeDelegation(ctx, bond) @@ -233,7 +233,7 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result { ///////////////////////////////////// // revoke validator if necessary - if revokeCandidacy { + if revokeValidator { validator.Revoked = true } diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 19848e8e6d..0c086f06db 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -14,8 +14,8 @@ import ( //______________________________________________________________________ -func newTestMsgDeclareCandidacy(address sdk.Address, pubKey crypto.PubKey, amt int64) MsgDeclareCandidacy { - return MsgDeclareCandidacy{ +func newTestMsgCreateValidator(address sdk.Address, pubKey crypto.PubKey, amt int64) MsgCreateValidator { + return MsgCreateValidator{ Description: Description{}, ValidatorAddr: address, PubKey: pubKey, @@ -33,13 +33,13 @@ func newTestMsgDelegate(delegatorAddr, validatorAddr sdk.Address, amt int64) Msg //______________________________________________________________________ -func TestDuplicatesMsgDeclareCandidacy(t *testing.T) { +func TestDuplicatesMsgCreateValidator(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 1000) validatorAddr := addrs[0] pk := pks[0] - msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pk, 10) - got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper) + msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pk, 10) + got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) assert.True(t, got.IsOK(), "%v", got) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -51,8 +51,8 @@ func TestDuplicatesMsgDeclareCandidacy(t *testing.T) { assert.Equal(t, Description{}, validator.Description) // one validator cannot bond twice - msgDeclareCandidacy.PubKey = pks[1] - got = handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper) + msgCreateValidator.PubKey = pks[1] + got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) assert.False(t, got.IsOK(), "%v", got) } @@ -64,10 +64,10 @@ func TestIncrementsMsgDelegate(t *testing.T) { bondAmount := int64(10) validatorAddr, delegatorAddr := addrs[0], addrs[1] - // first declare candidacy - msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], bondAmount) - got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper) - assert.True(t, got.IsOK(), "expected declare candidacy msg to be ok, got %v", got) + // first create validator + msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], bondAmount) + got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + assert.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -134,12 +134,12 @@ func TestIncrementsMsgUnbond(t *testing.T) { ctx, accMapper, keeper := createTestInput(t, false, initBond) params := keeper.GetParams(ctx) - // declare candidacy, delegate + // create validator, delegate validatorAddr, delegatorAddr := addrs[0], addrs[1] - msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], initBond) - got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper) - assert.True(t, got.IsOK(), "expected declare-candidacy to be ok, got %v", got) + msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], initBond) + got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + assert.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, initBond) got = handleMsgDelegate(ctx, msgDelegate, keeper) @@ -216,7 +216,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { "got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgUnbond, unbondSharesStr, leftBonded) } -func TestMultipleMsgDeclareCandidacy(t *testing.T) { +func TestMultipleMsgCreateValidator(t *testing.T) { initBond := int64(1000) ctx, accMapper, keeper := createTestInput(t, false, initBond) params := keeper.GetParams(ctx) @@ -224,8 +224,8 @@ func TestMultipleMsgDeclareCandidacy(t *testing.T) { // bond them all for i, validatorAddr := range validatorAddrs { - msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[i], 10) - got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper) + msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[i], 10) + got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) //Check that the account is bonded @@ -266,8 +266,8 @@ func TestMultipleMsgDelegate(t *testing.T) { validatorAddr, delegatorAddrs := addrs[0], addrs[1:] //first make a validator - msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], 10) - got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper) + msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], 10) + got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) // delegate multiple parties @@ -294,14 +294,14 @@ func TestMultipleMsgDelegate(t *testing.T) { } } -func TestVoidCandidacy(t *testing.T) { +func TestRevokeValidator(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 1000) validatorAddr, delegatorAddr := addrs[0], addrs[1] // create the validator - msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], 10) - got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgDeclareCandidacy") + msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], 10) + got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // bond a delegator msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, 10) @@ -311,7 +311,7 @@ func TestVoidCandidacy(t *testing.T) { // unbond the validators bond portion msgUnbondValidator := NewMsgUnbond(validatorAddr, validatorAddr, "10") got = handleMsgUnbond(ctx, msgUnbondValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgDeclareCandidacy") + require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) require.True(t, validator.Revoked) @@ -323,9 +323,9 @@ func TestVoidCandidacy(t *testing.T) { // test that the delegator can still withdraw their bonds msgUnbondDelegator := NewMsgUnbond(delegatorAddr, validatorAddr, "10") got = handleMsgUnbond(ctx, msgUnbondDelegator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgDeclareCandidacy") + require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // verify that the pubkey can now be reused - got = handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper) + got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) assert.True(t, got.IsOK(), "expected ok, got %v", got) } diff --git a/x/stake/msg.go b/x/stake/msg.go index 67d9597cac..40bf609eec 100644 --- a/x/stake/msg.go +++ b/x/stake/msg.go @@ -15,21 +15,21 @@ const MsgType = "stake" const StakingToken = "steak" //Verify interface at compile time -var _, _, _, _ sdk.Msg = &MsgDeclareCandidacy{}, &MsgEditCandidacy{}, &MsgDelegate{}, &MsgUnbond{} +var _, _, _, _ sdk.Msg = &MsgCreateValidator{}, &MsgEditValidator{}, &MsgDelegate{}, &MsgUnbond{} //______________________________________________________________________ -// MsgDeclareCandidacy - struct for unbonding transactions -type MsgDeclareCandidacy struct { +// MsgCreateValidator - struct for unbonding transactions +type MsgCreateValidator struct { Description ValidatorAddr sdk.Address `json:"address"` PubKey crypto.PubKey `json:"pubkey"` Bond sdk.Coin `json:"bond"` } -func NewMsgDeclareCandidacy(validatorAddr sdk.Address, pubkey crypto.PubKey, - bond sdk.Coin, description Description) MsgDeclareCandidacy { - return MsgDeclareCandidacy{ +func NewMsgCreateValidator(validatorAddr sdk.Address, pubkey crypto.PubKey, + bond sdk.Coin, description Description) MsgCreateValidator { + return MsgCreateValidator{ Description: description, ValidatorAddr: validatorAddr, PubKey: pubkey, @@ -38,18 +38,18 @@ func NewMsgDeclareCandidacy(validatorAddr sdk.Address, pubkey crypto.PubKey, } //nolint -func (msg MsgDeclareCandidacy) Type() string { return MsgType } //TODO update "stake/declarecandidacy" -func (msg MsgDeclareCandidacy) GetSigners() []sdk.Address { +func (msg MsgCreateValidator) Type() string { return MsgType } +func (msg MsgCreateValidator) GetSigners() []sdk.Address { return []sdk.Address{msg.ValidatorAddr} } // get the bytes for the message signer to sign on -func (msg MsgDeclareCandidacy) GetSignBytes() []byte { +func (msg MsgCreateValidator) GetSignBytes() []byte { return msgCdc.MustMarshalBinary(msg) } // quick validity check -func (msg MsgDeclareCandidacy) ValidateBasic() sdk.Error { +func (msg MsgCreateValidator) ValidateBasic() sdk.Error { if msg.ValidatorAddr == nil { return ErrValidatorEmpty(DefaultCodespace) } @@ -68,27 +68,27 @@ func (msg MsgDeclareCandidacy) ValidateBasic() sdk.Error { //______________________________________________________________________ -// MsgEditCandidacy - struct for editing a validator -type MsgEditCandidacy struct { +// MsgEditValidator - struct for editing a validator +type MsgEditValidator struct { Description ValidatorAddr sdk.Address `json:"address"` } -func NewMsgEditCandidacy(validatorAddr sdk.Address, description Description) MsgEditCandidacy { - return MsgEditCandidacy{ +func NewMsgEditValidator(validatorAddr sdk.Address, description Description) MsgEditValidator { + return MsgEditValidator{ Description: description, ValidatorAddr: validatorAddr, } } //nolint -func (msg MsgEditCandidacy) Type() string { return MsgType } //TODO update "stake/msgeditcandidacy" -func (msg MsgEditCandidacy) GetSigners() []sdk.Address { +func (msg MsgEditValidator) Type() string { return MsgType } +func (msg MsgEditValidator) GetSigners() []sdk.Address { return []sdk.Address{msg.ValidatorAddr} } // get the bytes for the message signer to sign on -func (msg MsgEditCandidacy) GetSignBytes() []byte { +func (msg MsgEditValidator) GetSignBytes() []byte { b, err := msgCdc.MarshalJSON(msg) if err != nil { panic(err) @@ -97,7 +97,7 @@ func (msg MsgEditCandidacy) GetSignBytes() []byte { } // quick validity check -func (msg MsgEditCandidacy) ValidateBasic() sdk.Error { +func (msg MsgEditValidator) ValidateBasic() sdk.Error { if msg.ValidatorAddr == nil { return ErrValidatorEmpty(DefaultCodespace) } @@ -126,7 +126,7 @@ func NewMsgDelegate(delegatorAddr, validatorAddr sdk.Address, bond sdk.Coin) Msg } //nolint -func (msg MsgDelegate) Type() string { return MsgType } //TODO update "stake/msgeditcandidacy" +func (msg MsgDelegate) Type() string { return MsgType } func (msg MsgDelegate) GetSigners() []sdk.Address { return []sdk.Address{msg.DelegatorAddr} } @@ -175,7 +175,7 @@ func NewMsgUnbond(delegatorAddr, validatorAddr sdk.Address, shares string) MsgUn } //nolint -func (msg MsgUnbond) Type() string { return MsgType } //TODO update "stake/msgeditcandidacy" +func (msg MsgUnbond) Type() string { return MsgType } func (msg MsgUnbond) GetSigners() []sdk.Address { return []sdk.Address{msg.DelegatorAddr} } // get the bytes for the message signer to sign on diff --git a/x/stake/msg_test.go b/x/stake/msg_test.go index 03a5fbf62f..863613a039 100644 --- a/x/stake/msg_test.go +++ b/x/stake/msg_test.go @@ -18,8 +18,8 @@ var ( coinNegNotAtoms = sdk.Coin{"foo", -10000} ) -// test ValidateBasic for MsgDeclareCandidacy -func TestMsgDeclareCandidacy(t *testing.T) { +// test ValidateBasic for MsgCreateValidator +func TestMsgCreateValidator(t *testing.T) { tests := []struct { name, moniker, identity, website, details string validatorAddr sdk.Address @@ -40,7 +40,7 @@ func TestMsgDeclareCandidacy(t *testing.T) { for _, tc := range tests { description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details) - msg := NewMsgDeclareCandidacy(tc.validatorAddr, tc.pubkey, tc.bond, description) + msg := NewMsgCreateValidator(tc.validatorAddr, tc.pubkey, tc.bond, description) if tc.expectPass { assert.Nil(t, msg.ValidateBasic(), "test: %v", tc.name) } else { @@ -49,8 +49,8 @@ func TestMsgDeclareCandidacy(t *testing.T) { } } -// test ValidateBasic for MsgEditCandidacy -func TestMsgEditCandidacy(t *testing.T) { +// test ValidateBasic for MsgEditValidator +func TestMsgEditValidator(t *testing.T) { tests := []struct { name, moniker, identity, website, details string validatorAddr sdk.Address @@ -64,7 +64,7 @@ func TestMsgEditCandidacy(t *testing.T) { for _, tc := range tests { description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details) - msg := NewMsgEditCandidacy(tc.validatorAddr, description) + msg := NewMsgEditValidator(tc.validatorAddr, description) if tc.expectPass { assert.Nil(t, msg.ValidateBasic(), "test: %v", tc.name) } else { @@ -139,8 +139,8 @@ func TestMsgUnbond(t *testing.T) { //tests := []struct { //tx sdk.Msg //}{ -//{NewMsgDeclareCandidacy(addrs[0], pks[0], bond, Description{})}, -//{NewMsgEditCandidacy(addrs[0], Description{})}, +//{NewMsgCreateValidator(addrs[0], pks[0], bond, Description{})}, +//{NewMsgEditValidator(addrs[0], Description{})}, //{NewMsgDelegate(addrs[0], addrs[1], bond)}, //{NewMsgUnbond(addrs[0], addrs[1], strconv.Itoa(bondAmt))}, //} diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 9f52ad8de9..ae4adf4d8f 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -68,8 +68,8 @@ func makeTestCodec() *wire.Codec { cdc.RegisterInterface((*sdk.Msg)(nil), nil) cdc.RegisterConcrete(bank.MsgSend{}, "test/stake/Send", nil) cdc.RegisterConcrete(bank.MsgIssue{}, "test/stake/Issue", nil) - cdc.RegisterConcrete(MsgDeclareCandidacy{}, "test/stake/DeclareCandidacy", nil) - cdc.RegisterConcrete(MsgEditCandidacy{}, "test/stake/EditCandidacy", nil) + cdc.RegisterConcrete(MsgCreateValidator{}, "test/stake/CreateValidator", nil) + cdc.RegisterConcrete(MsgEditValidator{}, "test/stake/EditValidator", nil) cdc.RegisterConcrete(MsgUnbond{}, "test/stake/Unbond", nil) // Register AppAccount diff --git a/x/stake/wire.go b/x/stake/wire.go index fb1a1c8867..c0b0be71fa 100644 --- a/x/stake/wire.go +++ b/x/stake/wire.go @@ -6,8 +6,8 @@ import ( // Register concrete types on wire codec func RegisterWire(cdc *wire.Codec) { - cdc.RegisterConcrete(MsgDeclareCandidacy{}, "cosmos-sdk/MsgDeclareCandidacy", nil) - cdc.RegisterConcrete(MsgEditCandidacy{}, "cosmos-sdk/MsgEditCandidacy", nil) + cdc.RegisterConcrete(MsgCreateValidator{}, "cosmos-sdk/MsgCreateValidator", nil) + cdc.RegisterConcrete(MsgEditValidator{}, "cosmos-sdk/MsgEditValidator", nil) cdc.RegisterConcrete(MsgDelegate{}, "cosmos-sdk/MsgDelegate", nil) cdc.RegisterConcrete(MsgUnbond{}, "cosmos-sdk/MsgUnbond", nil) } From 17a861da43a0c2b06271bd936d494a55226098ea Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 12:29:39 -0700 Subject: [PATCH 088/128] key utils output with cdc --- client/keys/utils.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/keys/utils.go b/client/keys/utils.go index 7224294290..3d6d9807ba 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -1,7 +1,6 @@ package keys import ( - "encoding/json" "fmt" "path/filepath" @@ -77,6 +76,7 @@ func printInfo(info keys.Info) { printKeyOutput(ko) case "json": out, err := MarshalJSON(ko) + //out, err := json.MarshalIndent(kos, "", "\t") if err != nil { panic(err) } @@ -93,7 +93,8 @@ func printInfos(infos []keys.Info) { printKeyOutput(ko) } case "json": - out, err := json.MarshalIndent(kos, "", "\t") + out, err := MarshalJSON(ko) + //out, err := json.MarshalIndent(kos, "", "\t") if err != nil { panic(err) } From 1f1097c4d3fa33d17b0eececd81ac9e06203929b Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 13:33:52 -0700 Subject: [PATCH 089/128] cli test bugs --- client/keys/utils.go | 2 +- cmd/gaia/cli_test/cli_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/keys/utils.go b/client/keys/utils.go index 3d6d9807ba..f9990bf16d 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -93,7 +93,7 @@ func printInfos(infos []keys.Info) { printKeyOutput(ko) } case "json": - out, err := MarshalJSON(ko) + out, err := MarshalJSON(kos) //out, err := json.MarshalIndent(kos, "", "\t") if err != nil { panic(err) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 79deaeb983..17d14d053b 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -108,7 +108,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { // create validator cvStr := fmt.Sprintf("gaiacli create-validator %v", flags) cvStr += fmt.Sprintf(" --name=%v", "bar") - cvStr += fmt.Sprintf(" --validator-address=%v", barCech) + cvStr += fmt.Sprintf(" --address-validator=%v", barCech) cvStr += fmt.Sprintf(" --pubkey=%v", barCeshPubKey) cvStr += fmt.Sprintf(" --amount=%v", "3steak") cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally") @@ -117,7 +117,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { time.Sleep(time.Second * 5) // waiting for some blocks to pass barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) - assert.Equal(t, int64(7), barAcc.GetCoins().AmountOf("steak")) + require.Equal(t, int64(7), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc) validator := executeGetValidator(t, fmt.Sprintf("gaiacli validator %v %v", barCech, flags)) assert.Equal(t, validator.Owner.String(), barCech) From 0b6aa3c047b5d88d580831e6f6845dbbee0c63c5 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 14:45:07 -0700 Subject: [PATCH 090/128] add test_cli to ci --- .circleci/config.yml | 19 +++++++++++++++++++ cmd/gaia/cli_test/cli_test.go | 14 +++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cd930d52ba..c8dc0b20ba 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -85,6 +85,22 @@ jobs: export PATH="$GOBIN:$PATH" make test_unit + test_cli: + <<: *defaults + parallelism: 1 + steps: + - attach_workspace: + at: /tmp/workspace + - restore_cache: + key: v1-pkg-cache + - restore_cache: + key: v1-tree-{{ .Environment.CIRCLE_SHA1 }} + - run: + name: Test cli + command: | + export PATH="$GOBIN:$PATH" + make test_cli + test_cover: <<: *defaults parallelism: 4 @@ -141,6 +157,9 @@ workflows: - test_unit: requires: - setup_dependencies + - test_cli: + requires: + - setup_dependencies - test_cover: requires: - setup_dependencies diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 17d14d053b..1e47572b14 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -110,18 +110,18 @@ func TestGaiaCLICreateValidator(t *testing.T) { cvStr += fmt.Sprintf(" --name=%v", "bar") cvStr += fmt.Sprintf(" --address-validator=%v", barCech) cvStr += fmt.Sprintf(" --pubkey=%v", barCeshPubKey) - cvStr += fmt.Sprintf(" --amount=%v", "3steak") + cvStr += fmt.Sprintf(" --amount=%v", "1steak") cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally") executeWrite(t, cvStr, pass) - time.Sleep(time.Second * 5) // waiting for some blocks to pass + time.Sleep(time.Second * 3) // waiting for some blocks to pass barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) - require.Equal(t, int64(7), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc) + require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc) - validator := executeGetValidator(t, fmt.Sprintf("gaiacli validator %v %v", barCech, flags)) - assert.Equal(t, validator.Owner.String(), barCech) - assert.Equal(t, int64(3), validator.PoolShares) + validator := executeGetValidator(t, fmt.Sprintf("gaiacli validator --output=json %v %v", barCech, flags)) + assert.Equal(t, validator.Owner, barAddr) + assert.Equal(t, "1/1", validator.PoolShares.Amount.String()) // TODO timeout issues if not connected to the internet // unbond a single share @@ -193,6 +193,6 @@ func executeGetValidator(t *testing.T, cmdStr string) stake.Validator { var validator stake.Validator cdc := app.MakeCodec() err := cdc.UnmarshalJSON([]byte(out), &validator) - require.NoError(t, err, "out %v, err %v", out, err) + require.NoError(t, err, "out %v\n, err %v", out, err) return validator } From 6f7cabf779152ab452bec3e7d10291383b6437e5 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 14:59:03 -0700 Subject: [PATCH 091/128] fix tests/process.go lint --- tests/process.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/process.go b/tests/process.go index fcc6e3e0ea..d2459a0b5b 100644 --- a/tests/process.go +++ b/tests/process.go @@ -8,6 +8,7 @@ import ( "time" ) +// execution process type Process struct { ExecPath string Args []string @@ -94,16 +95,16 @@ func StartProcess(dir string, name string, args []string, outFile, errFile io.Wr return proc, nil } +// stop the process func (proc *Process) Stop(kill bool) error { if kill { // fmt.Printf("Killing process %v\n", proc.Cmd.Process) return proc.Cmd.Process.Kill() - } else { - // fmt.Printf("Stopping process %v\n", proc.Cmd.Process) - return proc.Cmd.Process.Signal(os.Interrupt) } + return proc.Cmd.Process.Signal(os.Interrupt) } +// wait for the process func (proc *Process) Wait() { <-proc.WaitCh } From 4150fe5ec955da3d7eeb0fe46ee31ab01de281de Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 15:02:24 -0700 Subject: [PATCH 092/128] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a0bed5b18..037cf63078 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ IMPROVEMENTS * auth module uses go-wire codec instead of 'encoding/json' FIXES +* [cli] fixed cli-bash tests +* [ci] added cli-bash tests ## 0.18.1 From 89df36e1d4d30813c3f7f9808c3be4a628b182dd Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 15:39:42 -0700 Subject: [PATCH 093/128] ... --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c8dc0b20ba..5545ae4d3f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,4 @@ -version: 2 +tersion: 2 defaults: &defaults working_directory: /go/src/github.com/cosmos/cosmos-sdk @@ -154,10 +154,10 @@ workflows: - lint: requires: - setup_dependencies - - test_unit: + - test_cli: requires: - setup_dependencies - - test_cli: + - test_unit: requires: - setup_dependencies - test_cover: From a4e1e497cd6e30117182768a0f05701cb24e9a33 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 15:49:18 -0700 Subject: [PATCH 094/128] cwgoes comments --- client/keys/utils.go | 2 -- cmd/gaia/cli_test/cli_test.go | 41 ++++++++++++++++------------------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/client/keys/utils.go b/client/keys/utils.go index f9990bf16d..34e2ebcf37 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -76,7 +76,6 @@ func printInfo(info keys.Info) { printKeyOutput(ko) case "json": out, err := MarshalJSON(ko) - //out, err := json.MarshalIndent(kos, "", "\t") if err != nil { panic(err) } @@ -94,7 +93,6 @@ func printInfos(infos []keys.Info) { } case "json": out, err := MarshalJSON(kos) - //out, err := json.MarshalIndent(kos, "", "\t") if err != nil { panic(err) } diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 1e47572b14..f506a0d870 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -101,43 +101,40 @@ func TestGaiaCLICreateValidator(t *testing.T) { fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak")) - //valPrivkey := crypto.GenPrivKeyEd25519() - //valAddr := sdk.Address((valPrivkey.PubKey().Address())) - //bechVal, err := sdk.Bech32CosmosifyVal(valAddr) - // create validator cvStr := fmt.Sprintf("gaiacli create-validator %v", flags) cvStr += fmt.Sprintf(" --name=%v", "bar") cvStr += fmt.Sprintf(" --address-validator=%v", barCech) cvStr += fmt.Sprintf(" --pubkey=%v", barCeshPubKey) - cvStr += fmt.Sprintf(" --amount=%v", "1steak") + cvStr += fmt.Sprintf(" --amount=%v", "2steak") cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally") executeWrite(t, cvStr, pass) time.Sleep(time.Second * 3) // waiting for some blocks to pass barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) - require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc) + require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc) - validator := executeGetValidator(t, fmt.Sprintf("gaiacli validator --output=json %v %v", barCech, flags)) + validator := executeGetValidator(t, fmt.Sprintf("gaiacli validator %v --output=json %v", barCech, flags)) assert.Equal(t, validator.Owner, barAddr) - assert.Equal(t, "1/1", validator.PoolShares.Amount.String()) + assert.Equal(t, "2/1", validator.PoolShares.Amount.String()) - // TODO timeout issues if not connected to the internet // unbond a single share - //unbondStr := fmt.Sprintf("gaiacli unbond %v", flags) - //unbondStr += fmt.Sprintf(" --name=%v", "bar") - //unbondStr += fmt.Sprintf(" --address-validator=%v", barCech) - //unbondStr += fmt.Sprintf(" --address-delegator=%v", barCech) - //unbondStr += fmt.Sprintf(" --shares=%v", "1") - //unbondStr += fmt.Sprintf(" --sequence=%v", "1") - //t.Log(fmt.Sprintf("debug unbondStr: %v\n", unbondStr)) - //executeWrite(t, unbondStr, pass) - //time.Sleep(time.Second * 3) // waiting for some blocks to pass - //barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) - //assert.Equal(t, int64(99998), barAcc.GetCoins().AmountOf("steak")) - //validator = executeGetValidator(t, fmt.Sprintf("gaiacli validator %v --address-validator=%v", flags, barCech)) - //assert.Equal(t, int64(2), validator.BondedShares.Evaluate()) + unbondStr := fmt.Sprintf("gaiacli unbond %v", flags) + unbondStr += fmt.Sprintf(" --name=%v", "bar") + unbondStr += fmt.Sprintf(" --address-validator=%v", barCech) + unbondStr += fmt.Sprintf(" --address-delegator=%v", barCech) + unbondStr += fmt.Sprintf(" --shares=%v", "1") + unbondStr += fmt.Sprintf(" --sequence=%v", "1") + t.Log(fmt.Sprintf("debug unbondStr: %v\n", unbondStr)) + + executeWrite(t, unbondStr, pass) + time.Sleep(time.Second * 3) // waiting for some blocks to pass + + barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) + require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc) + validator = executeGetValidator(t, fmt.Sprintf("gaiacli validator %v --output=json %v", barCech, flags)) + assert.Equal(t, "1/1", validator.PoolShares.Amount.String()) } //___________________________________________________________________________________ From 5515b60b0a1f64fc8fd414d2366a45c159353442 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 18:46:25 -0700 Subject: [PATCH 095/128] better tooling for cli, couple lsd fixes --- client/lcd/lcd_test.go | 10 ++++-- cmd/gaia/cli_test/cli_test.go | 13 +++++--- server/start_test.go | 8 +++-- server/test_helpers.go | 13 +++++--- tests/tests.go | 7 ++-- tests/util.go | 61 +++++++++++++++++------------------ 6 files changed, 63 insertions(+), 49 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 8c6530dec2..7a9cdbc254 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -34,6 +34,7 @@ import ( client "github.com/cosmos/cosmos-sdk/client" keys "github.com/cosmos/cosmos-sdk/client/keys" gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app" + "github.com/cosmos/cosmos-sdk/server" tests "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -51,7 +52,7 @@ var ( // XXX bad globals name = "test" password = "0123456789" - port string // XXX: but it's the int ... + port string seed string sendAddr string ) @@ -456,8 +457,11 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { genDoc.AppStateJSON = appState // LCD listen address - port = fmt.Sprintf("%d", 17377) // XXX - listenAddr := fmt.Sprintf("tcp://localhost:%s", port) // XXX + var listenAddr string + listenAddr, port, err = server.FreeTCPAddr() + if err != nil { + return nil, nil, err + } // XXX: need to set this so LCD knows the tendermint node address! viper.Set(client.FlagNode, config.RPC.ListenAddress) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index f506a0d870..9c42d5cf2f 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -21,6 +21,7 @@ import ( ) func TestGaiaCLISend(t *testing.T) { + fmt.Println("wackydebugoutput TestGaiaCLISend 0") tests.ExecuteT(t, "gaiad unsafe_reset_all") pass := "1234567890" @@ -30,13 +31,14 @@ func TestGaiaCLISend(t *testing.T) { executeWrite(t, "gaiacli keys add bar", pass) // get a free port, also setup some common flags - servAddr := server.FreeTCPAddr(t) + servAddr, port, err := server.FreeTCPAddr() + require.NoError(t, err) flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID) // start gaiad server proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) defer proc.Stop(false) - time.Sleep(time.Second * 5) // Wait for RPC server to start. + tests.WaitForStart(port) fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") fooCech, err := sdk.Bech32CosmosifyAcc(fooAddr) @@ -49,6 +51,8 @@ func TestGaiaCLISend(t *testing.T) { assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak")) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) + fmt.Println("wackydebugoutput TestGaiaCLISend 1") + fmt.Println("wackydebugoutput TestGaiaCLISend 2") time.Sleep(time.Second * 2) // waiting for some blocks to pass barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) @@ -76,13 +80,14 @@ func TestGaiaCLICreateValidator(t *testing.T) { executeWrite(t, "gaiacli keys add bar", pass) // get a free port, also setup some common flags - servAddr := server.FreeTCPAddr(t) + servAddr, port, err := server.FreeTCPAddr() + require.NoError(t, err) flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID) // start gaiad server proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) defer proc.Stop(false) - time.Sleep(time.Second * 5) // Wait for RPC server to start. + tests.WaitForStart(port) fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") fooCech, err := sdk.Bech32CosmosifyAcc(fooAddr) diff --git a/server/start_test.go b/server/start_test.go index 3bf2eac7e4..454f2d4922 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -37,7 +37,9 @@ func TestStartStandAlone(t *testing.T) { app, err := mock.NewApp(home, logger) require.Nil(t, err) - svr, err := server.NewServer(FreeTCPAddr(t), "socket", app) + svrAddr, _, err := FreeTCPAddr() + require.Nil(t, err) + svr, err := server.NewServer(svrAddr, "socket", app) require.Nil(t, err, "Error creating listener") svr.SetLogger(logger.With("module", "abci-server")) svr.Start() @@ -69,7 +71,9 @@ func TestStartWithTendermint(t *testing.T) { // set up app and start up viper.Set(flagWithTendermint, true) startCmd := StartCmd(ctx, mock.NewApp) - startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address + svrAddr, _, err := FreeTCPAddr() + require.NoError(t, err) + startCmd.Flags().Set(flagAddress, svrAddr) // set to a new free address timeout := time.Duration(5) * time.Second close(RunOrTimeout(startCmd, timeout, t)) diff --git a/server/test_helpers.go b/server/test_helpers.go index 382c778787..b1050bc6f3 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -16,14 +16,17 @@ import ( // Get a free address for a test tendermint server // protocol is either tcp, http, etc -func FreeTCPAddr(t *testing.T) string { +func FreeTCPAddr() (addr, port string, err error) { l, err := net.Listen("tcp", "0.0.0.0:0") defer l.Close() - require.Nil(t, err) + if err != nil { + return "", "", err + } - port := l.Addr().(*net.TCPAddr).Port - addr := fmt.Sprintf("tcp://0.0.0.0:%d", port) - return addr + portI := l.Addr().(*net.TCPAddr).Port + port = fmt.Sprintf("%d", portI) + addr = fmt.Sprintf("tcp://0.0.0.0:%s", port) + return } // setupViper creates a homedir to run inside, diff --git a/tests/tests.go b/tests/tests.go index 845ac69259..b4435659b3 100644 --- a/tests/tests.go +++ b/tests/tests.go @@ -9,7 +9,6 @@ import ( "path" "path/filepath" "strings" - //"strings" "testing" "time" @@ -239,7 +238,9 @@ func StartNodeServerForTest(t *testing.T, home string) *exec.Cmd { // expects TestInitBaseCoin to have been run func StartLCDServerForTest(t *testing.T, home, chainID string) (cmd *exec.Cmd, port string) { cmdName := whereIsBasecli() - port = strings.Split(server.FreeTCPAddr(t), ":")[2] + var err error + _, port, err = server.FreeTCPAddr() + require.NoError(t, err) cmdArgs := []string{ "rest-server", "--home", @@ -252,7 +253,7 @@ func StartLCDServerForTest(t *testing.T, home, chainID string) (cmd *exec.Cmd, p cmd = exec.Command(cmdName, cmdArgs...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - err := cmd.Start() + err = cmd.Start() require.Nil(t, err) time.Sleep(time.Second * 2) // TODO: LOL return cmd, port diff --git a/tests/util.go b/tests/util.go index a6f026f242..292cbab060 100644 --- a/tests/util.go +++ b/tests/util.go @@ -11,16 +11,22 @@ import ( rpcclient "github.com/tendermint/tendermint/rpc/lib/client" ) -// TODO: these functions just print to Stdout. -// consider using the logger. - // Uses localhost func WaitForHeight(height int64, port string) { for { - var resultBlock ctypes.ResultBlock - url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest") - res, err := http.Get(url) + url := fmt.Sprintf("http://localhost:%v/blocks/latest", port) + + // get url, try a few times + var res *http.Response + var err error + for i := 0; i < 5; i++ { + res, err = http.Get(url) + if err == nil { + break + } + time.Sleep(time.Second) + } if err != nil { panic(err) } @@ -31,6 +37,7 @@ func WaitForHeight(height int64, port string) { } res.Body.Close() + var resultBlock ctypes.ResultBlock err = cdc.UnmarshalJSON([]byte(body), &resultBlock) if err != nil { fmt.Println("RES", res) @@ -45,45 +52,35 @@ func WaitForHeight(height int64, port string) { } } -// wait for 2 blocks. -// uses localhost +// wait for tendermint to start func WaitForStart(port string) { - waitHeight := int64(2) - for { + var err error + for i := 0; i < 5; i++ { time.Sleep(time.Second) - url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest") - res, err := http.Get(url) - if err != nil { - panic(err) + url := fmt.Sprintf("http://localhost:%v/blocks/latest", port) + + // get url, try a few times + var res *http.Response + res, err = http.Get(url) + if err == nil || res == nil { + continue } // waiting for server to start ... if res.StatusCode != http.StatusOK { res.Body.Close() - continue - } - - body, err := ioutil.ReadAll(res.Body) - if err != nil { - panic(err) - } - res.Body.Close() - - resultBlock := new(ctypes.ResultBlock) - err = cdc.UnmarshalJSON([]byte(body), &resultBlock) - if err != nil { - fmt.Println("RES", res) - fmt.Println("BODY", string(body)) - panic(err) - } - - if resultBlock.Block.Height >= waitHeight { return } } + if err != nil { + panic(err) + } } +// TODO: these functions just print to Stdout. +// consider using the logger. + // Wait for the RPC server to respond to /status func WaitForRPC(laddr string) { fmt.Println("LADDR", laddr) From ba44bf7c81c1988cdaab10f7cae73758d7d1ef7e Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 31 May 2018 18:54:14 -0700 Subject: [PATCH 096/128] rm debug output --- cmd/gaia/cli_test/cli_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 9c42d5cf2f..8fa0ad71ec 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -21,7 +21,6 @@ import ( ) func TestGaiaCLISend(t *testing.T) { - fmt.Println("wackydebugoutput TestGaiaCLISend 0") tests.ExecuteT(t, "gaiad unsafe_reset_all") pass := "1234567890" @@ -51,8 +50,6 @@ func TestGaiaCLISend(t *testing.T) { assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak")) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) - fmt.Println("wackydebugoutput TestGaiaCLISend 1") - fmt.Println("wackydebugoutput TestGaiaCLISend 2") time.Sleep(time.Second * 2) // waiting for some blocks to pass barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) From 7de746127e024433d8d9b4d836201ed6b36ea78c Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 1 Jun 2018 04:03:40 +0200 Subject: [PATCH 097/128] Fix minor typo --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5545ae4d3f..ceb9e78a8d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,4 @@ -tersion: 2 +version: 2 defaults: &defaults working_directory: /go/src/github.com/cosmos/cosmos-sdk From cde91bd229440142382dae1da1efd05738c795a6 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 1 Jun 2018 03:02:10 +0200 Subject: [PATCH 098/128] gaiacli unrevoke --- cmd/gaia/cmd/gaiacli/main.go | 2 ++ x/slashing/client/cli/flags.go | 6 ++++ x/slashing/client/cli/query.go | 57 +++++++++++++++++++++++++++++++++ x/slashing/client/cli/tx.go | 42 ++++++++++++++++++++++++ x/slashing/signing_info.go | 26 +++++++++------ x/slashing/signing_info_test.go | 2 +- 6 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 x/slashing/client/cli/flags.go create mode 100644 x/slashing/client/cli/query.go create mode 100644 x/slashing/client/cli/tx.go diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index 51dab68e28..32df02ce5e 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -14,6 +14,7 @@ import ( authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli" ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli" + slashingcmd "github.com/cosmos/cosmos-sdk/x/slashing/client/cli" stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli" "github.com/cosmos/cosmos-sdk/cmd/gaia/app" @@ -59,6 +60,7 @@ func main() { stakecmd.GetCmdEditValidator(cdc), stakecmd.GetCmdDelegate(cdc), stakecmd.GetCmdUnbond(cdc), + slashingcmd.GetCmdUnrevoke(cdc), )...) // add proxy, version and key info diff --git a/x/slashing/client/cli/flags.go b/x/slashing/client/cli/flags.go new file mode 100644 index 0000000000..43f8fa90a2 --- /dev/null +++ b/x/slashing/client/cli/flags.go @@ -0,0 +1,6 @@ +package cli + +// nolint +const ( + FlagAddressValidator = "address-validator" +) diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go new file mode 100644 index 0000000000..968e626a99 --- /dev/null +++ b/x/slashing/client/cli/query.go @@ -0,0 +1,57 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/tendermint/tmlibs/cli" + + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" // XXX fix + "github.com/cosmos/cosmos-sdk/x/slashing" +) + +// get the command to query signing info +func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "signing_info [owner-addr]", + Short: "Query a validator's signing information", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + + addr, err := sdk.GetAccAddressBech32Cosmos(args[0]) + if err != nil { + return err + } + key := slashing.GetValidatorSigningInfoKey(addr) + ctx := context.NewCoreContextFromViper() + res, err := ctx.Query(key, storeName) + if err != nil { + return err + } + signingInfo := new(slashing.ValidatorSigningInfo) + cdc.MustUnmarshalBinary(res, signingInfo) + + switch viper.Get(cli.OutputFlag) { + + case "text": + human := signingInfo.HumanReadableString() + fmt.Println(human) + + case "json": + // parse out the signing info + output, err := wire.MarshalJSONIndent(cdc, signingInfo) + if err != nil { + return err + } + fmt.Println(string(output)) + } + + return nil + }, + } + + return cmd +} diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go new file mode 100644 index 0000000000..13a5cb666f --- /dev/null +++ b/x/slashing/client/cli/tx.go @@ -0,0 +1,42 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + "github.com/cosmos/cosmos-sdk/x/slashing" +) + +// create unrevoke command +func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "unrevoke", + Args: cobra.ExactArgs(1), + Short: "unrevoke validator previously revoked for downtime", + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) + + validatorAddr, err := sdk.GetAccAddressBech32Cosmos(args[0]) + if err != nil { + return err + } + + msg := slashing.NewMsgUnrevoke(validatorAddr) + + // build and sign the transaction, then broadcast to Tendermint + res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, msg, cdc) + if err != nil { + return err + } + + fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) + return nil + }, + } + return cmd +} diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index 05285b6809..a2df0505a7 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -2,14 +2,15 @@ package slashing import ( "encoding/binary" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" ) // Stored by *validator* address (not owner address) -func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (info validatorSigningInfo, found bool) { +func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (info ValidatorSigningInfo, found bool) { store := ctx.KVStore(k.storeKey) - bz := store.Get(validatorSigningInfoKey(address)) + bz := store.Get(GetValidatorSigningInfoKey(address)) if bz == nil { found = false return @@ -20,16 +21,16 @@ func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (i } // Stored by *validator* address (not owner address) -func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.Address, info validatorSigningInfo) { +func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.Address, info ValidatorSigningInfo) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(info) - store.Set(validatorSigningInfoKey(address), bz) + store.Set(GetValidatorSigningInfoKey(address), bz) } // Stored by *validator* address (not owner address) func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64) (signed bool) { store := ctx.KVStore(k.storeKey) - bz := store.Get(validatorSigningBitArrayKey(address, index)) + bz := store.Get(GetValidatorSigningBitArrayKey(address, index)) if bz == nil { // lazy: treat empty key as unsigned signed = false @@ -43,23 +44,30 @@ func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.Address func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64, signed bool) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(signed) - store.Set(validatorSigningBitArrayKey(address, index), bz) + store.Set(GetValidatorSigningBitArrayKey(address, index), bz) } -type validatorSigningInfo struct { +// Signing info for a validator +type ValidatorSigningInfo struct { StartHeight int64 `json:"start_height"` // height at which validator was first a candidate OR was unrevoked IndexOffset int64 `json:"index_offset"` // index offset into signed block bit array JailedUntil int64 `json:"jailed_until"` // timestamp validator cannot be unrevoked until SignedBlocksCounter int64 `json:"signed_blocks_counter"` // signed blocks counter (to avoid scanning the array every time) } +// Return human readable signing info +func (i ValidatorSigningInfo) HumanReadableString() string { + return fmt.Sprintf("Start height: %d, index offset: %d, jailed until: %d, signed blocks counter: %d", + i.StartHeight, i.IndexOffset, i.JailedUntil, i.SignedBlocksCounter) +} + // Stored by *validator* address (not owner address) -func validatorSigningInfoKey(v sdk.Address) []byte { +func GetValidatorSigningInfoKey(v sdk.Address) []byte { return append([]byte{0x01}, v.Bytes()...) } // Stored by *validator* address (not owner address) -func validatorSigningBitArrayKey(v sdk.Address, i int64) []byte { +func GetValidatorSigningBitArrayKey(v sdk.Address, i int64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, uint64(i)) return append([]byte{0x02}, append(v.Bytes(), b...)...) diff --git a/x/slashing/signing_info_test.go b/x/slashing/signing_info_test.go index 8000d67450..26113e7153 100644 --- a/x/slashing/signing_info_test.go +++ b/x/slashing/signing_info_test.go @@ -10,7 +10,7 @@ func TestGetSetValidatorSigningInfo(t *testing.T) { ctx, _, _, keeper := createTestInput(t) info, found := keeper.getValidatorSigningInfo(ctx, addrs[0]) require.False(t, found) - newInfo := validatorSigningInfo{ + newInfo := ValidatorSigningInfo{ StartHeight: int64(4), IndexOffset: int64(3), JailedUntil: int64(2), From 9fa4a55012a4717ce7bbc412361a1cb4183b7f0d Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 1 Jun 2018 04:25:45 +0200 Subject: [PATCH 099/128] Add 'gaiacli signing_info' --- cmd/gaia/cmd/gaiacli/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index 32df02ce5e..08663f6215 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -50,6 +50,7 @@ func main() { stakecmd.GetCmdQueryValidators("stake", cdc), stakecmd.GetCmdQueryDelegation("stake", cdc), stakecmd.GetCmdQueryDelegations("stake", cdc), + slashingcmd.GetCmdQuerySigningInfo("slashing", cdc), )...) rootCmd.AddCommand( client.PostCommands( From c7a9b53fae0808b50c0165dba7a71ca9fa51c4f7 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 1 Jun 2018 04:30:45 +0200 Subject: [PATCH 100/128] Use valpk.Address() --- x/slashing/client/cli/query.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 968e626a99..3354d62c14 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -21,11 +21,11 @@ func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command { Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - addr, err := sdk.GetAccAddressBech32Cosmos(args[0]) + pk, err := sdk.GetValPubKeyBech32Cosmos(args[0]) if err != nil { return err } - key := slashing.GetValidatorSigningInfoKey(addr) + key := slashing.GetValidatorSigningInfoKey(pk.Address()) ctx := context.NewCoreContextFromViper() res, err := ctx.Query(key, storeName) if err != nil { From 7ff6eebb32098d40d53744f147532254fa72bdd5 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 1 Jun 2018 04:54:17 +0200 Subject: [PATCH 101/128] Fix command documentation --- x/slashing/client/cli/query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 3354d62c14..42c02cab03 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -16,7 +16,7 @@ import ( // get the command to query signing info func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "signing_info [owner-addr]", + Use: "signing_info [validator-pubkey]", Short: "Query a validator's signing information", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { From 083ca8234bd6717130da5d68b97ac73f1c606917 Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Mon, 28 May 2018 15:00:37 -0700 Subject: [PATCH 102/128] Refactored gaiacli and gaiad commands into subcommands --- client/rpc/block.go | 2 +- client/rpc/root.go | 2 -- client/rpc/validators.go | 2 +- cmd/gaia/cmd/gaiacli/main.go | 60 ++++++++++++++++++++++++++++++------ cmd/gaia/cmd/gaiad/main.go | 1 + server/util.go | 19 ++++++++++-- 6 files changed, 70 insertions(+), 16 deletions(-) diff --git a/client/rpc/block.go b/client/rpc/block.go index 3547270197..36327a722a 100644 --- a/client/rpc/block.go +++ b/client/rpc/block.go @@ -16,7 +16,7 @@ const ( flagSelect = "select" ) -func blockCommand() *cobra.Command { +func BlockCommand() *cobra.Command { cmd := &cobra.Command{ Use: "block [height]", Short: "Get verified data for a the block at given height", diff --git a/client/rpc/root.go b/client/rpc/root.go index f779bd7292..e89972c3c7 100644 --- a/client/rpc/root.go +++ b/client/rpc/root.go @@ -26,8 +26,6 @@ func AddCommands(cmd *cobra.Command) { cmd.AddCommand( initClientCommand(), statusCommand(), - blockCommand(), - validatorCommand(), ) } diff --git a/client/rpc/validators.go b/client/rpc/validators.go index 892d131ac3..bfd8a9582b 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -14,7 +14,7 @@ import ( // TODO these next two functions feel kinda hacky based on their placement -func validatorCommand() *cobra.Command { +func ValidatorCommand() *cobra.Command { cmd := &cobra.Command{ Use: "validatorset [height]", Short: "Get the full validator set at given height", diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index 51dab68e28..4f82d58ad3 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -35,31 +35,73 @@ func main() { // the below functions and eliminate global vars, like we do // with the cdc - // add standard rpc, and tx commands + // add standard rpc commands rpc.AddCommands(rootCmd) rootCmd.AddCommand(client.LineBreak) - tx.AddCommands(rootCmd, cdc) - rootCmd.AddCommand(client.LineBreak) - // add query/post commands (custom to binary) + //Add state commands + stateCmd := &cobra.Command{ + Use: "state", + Short: "State querying subcommands (validators, blocks, transactions)", + } + stateCmd.AddCommand( + rpc.BlockCommand(), + rpc.ValidatorCommand(), + ) + tx.AddCommands(stateCmd, cdc) rootCmd.AddCommand( + stateCmd, + client.LineBreak, + ) + + //Add stake commands + stakeCmd := &cobra.Command{ + Use: "stake", + Short: "Stake and validation subcommands", + } + stakeCmd.AddCommand( client.GetCommands( - authcmd.GetAccountCmd("acc", cdc, authcmd.GetAccountDecoder(cdc)), stakecmd.GetCmdQueryValidator("stake", cdc), stakecmd.GetCmdQueryValidators("stake", cdc), stakecmd.GetCmdQueryDelegation("stake", cdc), stakecmd.GetCmdQueryDelegations("stake", cdc), )...) - rootCmd.AddCommand( + stakeCmd.AddCommand( client.PostCommands( - bankcmd.SendTxCmd(cdc), - ibccmd.IBCTransferCmd(cdc), - ibccmd.IBCRelayCmd(cdc), stakecmd.GetCmdCreateValidator(cdc), stakecmd.GetCmdEditValidator(cdc), stakecmd.GetCmdDelegate(cdc), stakecmd.GetCmdUnbond(cdc), )...) + rootCmd.AddCommand( + stakeCmd, + client.LineBreak, + ) + + //Add IBC commands + ibcCmd := &cobra.Command{ + Use: "ibc", + Short: "Inter-Blockchain Communication subcommands", + } + ibcCmd.AddCommand( + client.PostCommands( + ibccmd.IBCTransferCmd(cdc), + ibccmd.IBCRelayCmd(cdc), + )...) + rootCmd.AddCommand( + ibcCmd, + client.LineBreak, + ) + + //Add auth and bank commands + rootCmd.AddCommand( + client.GetCommands( + authcmd.GetAccountCmd("acc", cdc, authcmd.GetAccountDecoder(cdc)), + )...) + rootCmd.AddCommand( + client.PostCommands( + bankcmd.SendTxCmd(cdc), + )...) // add proxy, version and key info rootCmd.AddCommand( diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index f64498d850..30cb276ee1 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -17,6 +17,7 @@ import ( func main() { cdc := app.MakeCodec() ctx := server.NewDefaultContext() + cobra.EnableCommandSorting = false rootCmd := &cobra.Command{ Use: "gaiad", Short: "Gaia Daemon (server)", diff --git a/server/util.go b/server/util.go index f44cc2d728..da43dabbb1 100644 --- a/server/util.go +++ b/server/util.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/wire" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" @@ -72,13 +73,25 @@ func AddCommands( rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level") - rootCmd.AddCommand( - InitCmd(ctx, cdc, appInit), - StartCmd(ctx, appCreator), + tendCmd := &cobra.Command{ + Use: "tendermint", + Short: "Tendermint subcommands", + } + + tendCmd.AddCommand( UnsafeResetAllCmd(ctx), ShowNodeIDCmd(ctx), ShowValidatorCmd(ctx), + ) + + rootCmd.AddCommand( + InitCmd(ctx, cdc, appInit), + StartCmd(ctx, appCreator), + client.LineBreak, + tendCmd, + client.LineBreak, ExportCmd(ctx, cdc, appExport), + client.LineBreak, version.VersionCmd, ) } From a032386e876cb652a27b5b5563afcea16f5b6e0f Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Mon, 28 May 2018 15:50:07 -0700 Subject: [PATCH 103/128] Added comments to newly exported functions --- client/rpc/block.go | 1 + client/rpc/validators.go | 1 + 2 files changed, 2 insertions(+) diff --git a/client/rpc/block.go b/client/rpc/block.go index 36327a722a..693298bb86 100644 --- a/client/rpc/block.go +++ b/client/rpc/block.go @@ -16,6 +16,7 @@ const ( flagSelect = "select" ) +//BlockCommand returns the verified block data for a given heights func BlockCommand() *cobra.Command { cmd := &cobra.Command{ Use: "block [height]", diff --git a/client/rpc/validators.go b/client/rpc/validators.go index bfd8a9582b..e05d1c4348 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -14,6 +14,7 @@ import ( // TODO these next two functions feel kinda hacky based on their placement +//ValidatorCommand returns the validator set for a given height func ValidatorCommand() *cobra.Command { cmd := &cobra.Command{ Use: "validatorset [height]", From 744f78573ea90873a8f24cda9c0cb1f55049a81e Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Thu, 31 May 2018 18:38:15 -0700 Subject: [PATCH 104/128] small fixes --- client/rpc/validators.go | 2 +- cmd/gaia/cmd/gaiacli/main.go | 43 +++++++++++++++++++----------------- server/util.go | 6 ++--- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/client/rpc/validators.go b/client/rpc/validators.go index e05d1c4348..27b7fce99e 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -18,7 +18,7 @@ import ( func ValidatorCommand() *cobra.Command { cmd := &cobra.Command{ Use: "validatorset [height]", - Short: "Get the full validator set at given height", + Short: "Get the full tendermint validator set at given height", Args: cobra.MaximumNArgs(1), RunE: printValidators, } diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index 4f82d58ad3..136260c760 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -37,7 +37,6 @@ func main() { // add standard rpc commands rpc.AddCommands(rootCmd) - rootCmd.AddCommand(client.LineBreak) //Add state commands stateCmd := &cobra.Command{ @@ -49,8 +48,30 @@ func main() { rpc.ValidatorCommand(), ) tx.AddCommands(stateCmd, cdc) - rootCmd.AddCommand( + + //Add IBC commands + ibcCmd := &cobra.Command{ + Use: "ibc", + Short: "Inter-Blockchain Communication subcommands", + } + ibcCmd.AddCommand( + client.PostCommands( + ibccmd.IBCTransferCmd(cdc), + ibccmd.IBCRelayCmd(cdc), + )...) + + advancedCmd := &cobra.Command{ + Use: "advanced", + Short: "Advanced subcommands", + } + + advancedCmd.AddCommand( stateCmd, + ibcCmd, + lcd.ServeCommand(cdc), + ) + rootCmd.AddCommand( + advancedCmd, client.LineBreak, ) @@ -75,22 +96,6 @@ func main() { )...) rootCmd.AddCommand( stakeCmd, - client.LineBreak, - ) - - //Add IBC commands - ibcCmd := &cobra.Command{ - Use: "ibc", - Short: "Inter-Blockchain Communication subcommands", - } - ibcCmd.AddCommand( - client.PostCommands( - ibccmd.IBCTransferCmd(cdc), - ibccmd.IBCRelayCmd(cdc), - )...) - rootCmd.AddCommand( - ibcCmd, - client.LineBreak, ) //Add auth and bank commands @@ -105,8 +110,6 @@ func main() { // add proxy, version and key info rootCmd.AddCommand( - client.LineBreak, - lcd.ServeCommand(cdc), keys.Commands(), client.LineBreak, version.VersionCmd, diff --git a/server/util.go b/server/util.go index da43dabbb1..93dc73469f 100644 --- a/server/util.go +++ b/server/util.go @@ -73,12 +73,12 @@ func AddCommands( rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level") - tendCmd := &cobra.Command{ + tendermintCmd := &cobra.Command{ Use: "tendermint", Short: "Tendermint subcommands", } - tendCmd.AddCommand( + tendermintCmd.AddCommand( UnsafeResetAllCmd(ctx), ShowNodeIDCmd(ctx), ShowValidatorCmd(ctx), @@ -88,7 +88,7 @@ func AddCommands( InitCmd(ctx, cdc, appInit), StartCmd(ctx, appCreator), client.LineBreak, - tendCmd, + tendermintCmd, client.LineBreak, ExportCmd(ctx, cdc, appExport), client.LineBreak, From aa41cefb1ee73dc7aede05879fbb3698d6a07c33 Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Thu, 31 May 2018 18:51:06 -0700 Subject: [PATCH 105/128] renamed state subcommand to tendermint --- cmd/gaia/cmd/gaiacli/main.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index 136260c760..049c07b364 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -39,15 +39,15 @@ func main() { rpc.AddCommands(rootCmd) //Add state commands - stateCmd := &cobra.Command{ - Use: "state", - Short: "State querying subcommands (validators, blocks, transactions)", + tendermintCmd := &cobra.Command{ + Use: "tendermint", + Short: "Tendermint state querying subcommands", } - stateCmd.AddCommand( + tendermintCmd.AddCommand( rpc.BlockCommand(), rpc.ValidatorCommand(), ) - tx.AddCommands(stateCmd, cdc) + tx.AddCommands(tendermintCmd, cdc) //Add IBC commands ibcCmd := &cobra.Command{ @@ -66,7 +66,7 @@ func main() { } advancedCmd.AddCommand( - stateCmd, + tendermintCmd, ibcCmd, lcd.ServeCommand(cdc), ) From a03638d14af144ef252239e7175c31e425bf2040 Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Thu, 31 May 2018 22:06:13 -0700 Subject: [PATCH 106/128] changed commands in cli_test to match refactor --- cmd/gaia/cli_test/cli_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 8fa0ad71ec..3ed5a1f4bc 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -22,7 +22,7 @@ import ( func TestGaiaCLISend(t *testing.T) { - tests.ExecuteT(t, "gaiad unsafe_reset_all") + tests.ExecuteT(t, "gaiad tendermint unsafe_reset_all") pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete bar", pass) @@ -69,7 +69,7 @@ func TestGaiaCLISend(t *testing.T) { func TestGaiaCLICreateValidator(t *testing.T) { - tests.ExecuteT(t, "gaiad unsafe_reset_all") + tests.ExecuteT(t, "gaiad tendermint unsafe_reset_all") pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete bar", pass) @@ -104,7 +104,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak")) // create validator - cvStr := fmt.Sprintf("gaiacli create-validator %v", flags) + cvStr := fmt.Sprintf("gaiacli stake create-validator %v", flags) cvStr += fmt.Sprintf(" --name=%v", "bar") cvStr += fmt.Sprintf(" --address-validator=%v", barCech) cvStr += fmt.Sprintf(" --pubkey=%v", barCeshPubKey) @@ -117,12 +117,12 @@ func TestGaiaCLICreateValidator(t *testing.T) { barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc) - validator := executeGetValidator(t, fmt.Sprintf("gaiacli validator %v --output=json %v", barCech, flags)) + validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %v --output=json %v", barCech, flags)) assert.Equal(t, validator.Owner, barAddr) assert.Equal(t, "2/1", validator.PoolShares.Amount.String()) // unbond a single share - unbondStr := fmt.Sprintf("gaiacli unbond %v", flags) + unbondStr := fmt.Sprintf("gaiacli stake unbond %v", flags) unbondStr += fmt.Sprintf(" --name=%v", "bar") unbondStr += fmt.Sprintf(" --address-validator=%v", barCech) unbondStr += fmt.Sprintf(" --address-delegator=%v", barCech) @@ -135,7 +135,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc) - validator = executeGetValidator(t, fmt.Sprintf("gaiacli validator %v --output=json %v", barCech, flags)) + validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %v --output=json %v", barCech, flags)) assert.Equal(t, "1/1", validator.PoolShares.Amount.String()) } From 7ce9e000b62403cc58b00ac98f465658153c7d52 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 1 Jun 2018 00:53:54 -0700 Subject: [PATCH 107/128] update changelog, minor update --- CHANGELOG.md | 1 + server/util.go | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 037cf63078..e23165799f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Pending BREAKING CHANGES +* [cli] rearranged commands under subcommands FEATURES diff --git a/server/util.go b/server/util.go index 93dc73469f..9c251aa4ce 100644 --- a/server/util.go +++ b/server/util.go @@ -89,7 +89,6 @@ func AddCommands( StartCmd(ctx, appCreator), client.LineBreak, tendermintCmd, - client.LineBreak, ExportCmd(ctx, cdc, appExport), client.LineBreak, version.VersionCmd, From 34686e8d61d25c04e82c46d57e433879e8091945 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 1 Jun 2018 01:35:39 -0700 Subject: [PATCH 108/128] unsafe_reset_all back to root --- server/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/util.go b/server/util.go index 9c251aa4ce..9e705f8792 100644 --- a/server/util.go +++ b/server/util.go @@ -79,7 +79,6 @@ func AddCommands( } tendermintCmd.AddCommand( - UnsafeResetAllCmd(ctx), ShowNodeIDCmd(ctx), ShowValidatorCmd(ctx), ) @@ -87,6 +86,7 @@ func AddCommands( rootCmd.AddCommand( InitCmd(ctx, cdc, appInit), StartCmd(ctx, appCreator), + UnsafeResetAllCmd(ctx), client.LineBreak, tendermintCmd, ExportCmd(ctx, cdc, appExport), From 823814dfce1c4e7051a7dbc470cc4f5de348cfc1 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 1 Jun 2018 01:47:44 -0700 Subject: [PATCH 109/128] fix cli test --- cmd/gaia/cli_test/cli_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 3ed5a1f4bc..f6dc50d43b 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -22,7 +22,7 @@ import ( func TestGaiaCLISend(t *testing.T) { - tests.ExecuteT(t, "gaiad tendermint unsafe_reset_all") + tests.ExecuteT(t, "gaiad unsafe_reset_all") pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete bar", pass) @@ -69,7 +69,7 @@ func TestGaiaCLISend(t *testing.T) { func TestGaiaCLICreateValidator(t *testing.T) { - tests.ExecuteT(t, "gaiad tendermint unsafe_reset_all") + tests.ExecuteT(t, "gaiad unsafe_reset_all") pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete bar", pass) From e1d9f00d2de4aa9c24111975b2538be753b9ac5e Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 1 Jun 2018 01:57:21 -0700 Subject: [PATCH 110/128] ... --- cmd/gaia/cli_test/cli_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index f6dc50d43b..a591c9903f 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -96,7 +96,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { require.NoError(t, err) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) - time.Sleep(time.Second * 2) // waiting for some blocks to pass + time.Sleep(time.Second * 3) // waiting for some blocks to pass barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak")) From ce850dca3b025e0625ad73faf605a53650638abc Mon Sep 17 00:00:00 2001 From: Zaki Manian Date: Fri, 1 Jun 2018 16:23:58 +0200 Subject: [PATCH 111/128] Switch from bech32cosmos to bech32 --- Gopkg.lock | 16 ++++++------ Gopkg.toml | 8 ++---- client/keys/utils.go | 4 +-- cmd/gaia/cli_test/cli_test.go | 10 ++++---- server/tm_cmds.go | 4 +-- types/account.go | 46 +++++++++++++++++------------------ x/auth/client/cli/account.go | 2 +- x/bank/client/cli/sendtx.go | 2 +- x/stake/client/cli/query.go | 7 +++--- x/stake/client/cli/tx.go | 14 +++++------ x/stake/delegation.go | 4 +-- x/stake/test_common.go | 24 +++++++++--------- x/stake/validator.go | 4 +-- 13 files changed, 71 insertions(+), 74 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index a7aed3194e..eefc701b02 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -15,9 +15,9 @@ [[projects]] branch = "master" - name = "github.com/cosmos/bech32cosmos" - packages = ["go"] - revision = "c12e4b6ed52acc1d35fea49acec35f980914dc95" + name = "github.com/btcsuite/btcutil" + packages = ["bech32"] + revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4" [[projects]] name = "github.com/davecgh/go-spew" @@ -351,9 +351,11 @@ version = "v0.20.0-rc0" [[projects]] + branch = "develop" name = "github.com/tendermint/tmlibs" packages = [ "autofile", + "bech32", "cli", "cli/flags", "clist", @@ -361,10 +363,10 @@ "db", "flowrate", "log", - "merkle" + "merkle", + "merkle/tmhash" ] - revision = "d970af87248a4e162590300dbb74e102183a417d" - version = "v0.8.3" + revision = "44f1bdb0d55cc6527e38d0a7aab406e2580f56a4" [[projects]] branch = "master" @@ -461,6 +463,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "a6a5d886519fa9ca97a23715faa852ee14ecb5337e03641d19ea3d3d1c392fee" + inputs-digest = "c8d0282dfa5b2bb7a0eb54fc24f42021e63f282265332678593658119bf5023b" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index deabcd6452..8c3f5131d0 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -72,14 +72,10 @@ name = "github.com/tendermint/tendermint" version = "0.20.0-rc0" -[[constraint]] +[[override]] name = "github.com/tendermint/tmlibs" - version = "~0.8.3-rc0" + branch = "develop" -[[constraint]] - name = "github.com/cosmos/bech32cosmos" - branch = "master" - # this got updated and broke, so locked to an old working commit ... [[override]] name = "google.golang.org/genproto" diff --git a/client/keys/utils.go b/client/keys/utils.go index 34e2ebcf37..1c1fd0979a 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -101,11 +101,11 @@ func printInfos(infos []keys.Info) { } func printKeyOutput(ko KeyOutput) { - bechAccount, err := sdk.Bech32CosmosifyAcc(ko.Address) + bechAccount, err := sdk.Bech32ifyAcc(ko.Address) if err != nil { panic(err) } - bechPubKey, err := sdk.Bech32CosmosifyAccPub(ko.PubKey) + bechPubKey, err := sdk.Bech32ifyAccPub(ko.PubKey) if err != nil { panic(err) } diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index a591c9903f..ae46a623cd 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -40,10 +40,10 @@ func TestGaiaCLISend(t *testing.T) { tests.WaitForStart(port) fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") - fooCech, err := sdk.Bech32CosmosifyAcc(fooAddr) + fooCech, err := sdk.Bech32ifyAcc(fooAddr) require.NoError(t, err) barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json") - barCech, err := sdk.Bech32CosmosifyAcc(barAddr) + barCech, err := sdk.Bech32ifyAcc(barAddr) require.NoError(t, err) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) @@ -87,12 +87,12 @@ func TestGaiaCLICreateValidator(t *testing.T) { tests.WaitForStart(port) fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") - fooCech, err := sdk.Bech32CosmosifyAcc(fooAddr) + fooCech, err := sdk.Bech32ifyAcc(fooAddr) require.NoError(t, err) barAddr, barPubKey := executeGetAddrPK(t, "gaiacli keys show bar --output=json") - barCech, err := sdk.Bech32CosmosifyAcc(barAddr) + barCech, err := sdk.Bech32ifyAcc(barAddr) require.NoError(t, err) - barCeshPubKey, err := sdk.Bech32CosmosifyValPub(barPubKey) + barCeshPubKey, err := sdk.Bech32ifyValPub(barPubKey) require.NoError(t, err) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) diff --git a/server/tm_cmds.go b/server/tm_cmds.go index fcec57f090..60eb5a2fa6 100644 --- a/server/tm_cmds.go +++ b/server/tm_cmds.go @@ -53,11 +53,11 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command { fmt.Println(string(pubKeyJSONBytes)) return nil } - addr, err := sdk.Bech32CosmosifyValPub(valPubKey) + pubkey, err := sdk.Bech32ifyValPub(valPubKey) if err != nil { return err } - fmt.Println(addr) + fmt.Println(pubkey) return nil }, } diff --git a/types/account.go b/types/account.go index b593dfb539..ad0c58231f 100644 --- a/types/account.go +++ b/types/account.go @@ -5,8 +5,8 @@ import ( "errors" "fmt" - bech32cosmos "github.com/cosmos/bech32cosmos/go" crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tmlibs/bech32" cmn "github.com/tendermint/tmlibs/common" ) @@ -21,24 +21,24 @@ const ( Bech32PrefixValPub = "cosmosvalpub" ) -// Bech32CosmosifyAcc takes Address and returns the Bech32Cosmos encoded string -func Bech32CosmosifyAcc(addr Address) (string, error) { - return bech32cosmos.ConvertAndEncode(Bech32PrefixAccAddr, addr.Bytes()) +// Bech32ifyAcc takes Address and returns the bech32 encoded string +func Bech32ifyAcc(addr Address) (string, error) { + return bech32.ConvertAndEncode(Bech32PrefixAccAddr, addr.Bytes()) } -// Bech32CosmosifyAccPub takes AccountPubKey and returns the Bech32Cosmos encoded string -func Bech32CosmosifyAccPub(pub crypto.PubKey) (string, error) { - return bech32cosmos.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes()) +// Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string +func Bech32ifyAccPub(pub crypto.PubKey) (string, error) { + return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes()) } -// Bech32CosmosifyVal returns the Bech32Cosmos encoded string for a validator address -func Bech32CosmosifyVal(addr Address) (string, error) { - return bech32cosmos.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes()) +// Bech32ifyVal returns the bech32 encoded string for a validator address +func bech32ifyVal(addr Address) (string, error) { + return bech32.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes()) } -// Bech32CosmosifyValPub returns the Bech32Cosmos encoded string for a validator pubkey -func Bech32CosmosifyValPub(pub crypto.PubKey) (string, error) { - return bech32cosmos.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes()) +// Bech32ifyValPub returns the bech32 encoded string for a validator pubkey +func Bech32ifyValPub(pub crypto.PubKey) (string, error) { + return bech32.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes()) } // create an Address from a string @@ -54,8 +54,8 @@ func GetAccAddressHex(address string) (addr Address, err error) { } // create an Address from a string -func GetAccAddressBech32Cosmos(address string) (addr Address, err error) { - bz, err := getFromBech32Cosmos(address, Bech32PrefixAccAddr) +func GetAccAddressBech32(address string) (addr Address, err error) { + bz, err := getFromBech32(address, Bech32PrefixAccAddr) if err != nil { return nil, err } @@ -74,9 +74,9 @@ func GetValAddressHex(address string) (addr Address, err error) { return Address(bz), nil } -// create an Address from a bech32cosmos string -func GetValAddressBech32Cosmos(address string) (addr Address, err error) { - bz, err := getFromBech32Cosmos(address, Bech32PrefixValAddr) +// create an Address from a bech32 string +func GetValAddressBech32(address string) (addr Address, err error) { + bz, err := getFromBech32(address, Bech32PrefixValAddr) if err != nil { return nil, err } @@ -84,8 +84,8 @@ func GetValAddressBech32Cosmos(address string) (addr Address, err error) { } //Decode a validator publickey into a public key -func GetValPubKeyBech32Cosmos(pubkey string) (pk crypto.PubKey, err error) { - bz, err := getFromBech32Cosmos(pubkey, Bech32PrefixValPub) +func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) { + bz, err := getFromBech32(pubkey, Bech32PrefixValPub) if err != nil { return nil, err } @@ -98,11 +98,11 @@ func GetValPubKeyBech32Cosmos(pubkey string) (pk crypto.PubKey, err error) { return pk, nil } -func getFromBech32Cosmos(bech32, prefix string) ([]byte, error) { - if len(bech32) == 0 { +func getFromBech32(bech32str, prefix string) ([]byte, error) { + if len(bech32str) == 0 { return nil, errors.New("must provide non-empty string") } - hrp, bz, err := bech32cosmos.DecodeAndConvert(bech32) + hrp, bz, err := bech32.DecodeAndConvert(bech32str) if err != nil { return nil, err } diff --git a/x/auth/client/cli/account.go b/x/auth/client/cli/account.go index 4006baa149..b5af6a686a 100644 --- a/x/auth/client/cli/account.go +++ b/x/auth/client/cli/account.go @@ -40,7 +40,7 @@ func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecode // find the key to look up the account addr := args[0] - key, err := sdk.GetAccAddressBech32Cosmos(addr) + key, err := sdk.GetAccAddressBech32(addr) if err != nil { return err } diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index 5ed56a85b4..817c9a1747 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -34,7 +34,7 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command { toStr := viper.GetString(flagTo) - to, err := sdk.GetAccAddressBech32Cosmos(toStr) + to, err := sdk.GetAccAddressBech32(toStr) if err != nil { return err } diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index 84ce9886aa..eac39b9efc 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -21,7 +21,7 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command { Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - addr, err := sdk.GetAccAddressBech32Cosmos(args[0]) + addr, err := sdk.GetAccAddressBech32(args[0]) if err != nil { return err } @@ -80,7 +80,6 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command { validators = append(validators, validator) } - switch viper.Get(cli.OutputFlag) { case "text": for _, validator := range validators { @@ -113,7 +112,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { Short: "Query a delegations bond based on address and validator address", RunE: func(cmd *cobra.Command, args []string) error { - addr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator)) + addr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err } @@ -166,7 +165,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command { Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - delegatorAddr, err := sdk.GetAccAddressBech32Cosmos(args[0]) + delegatorAddr, err := sdk.GetAccAddressBech32(args[0]) if err != nil { return err } diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 3abd366ece..daa4dd9ef7 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -25,7 +25,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { if err != nil { return err } - validatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator)) + validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err } @@ -34,7 +34,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { if len(pkStr) == 0 { return fmt.Errorf("must use --pubkey flag") } - pk, err := sdk.GetValPubKeyBech32Cosmos(pkStr) + pk, err := sdk.GetValPubKeyBech32(pkStr) if err != nil { return err } @@ -74,7 +74,7 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { Short: "edit and existing validator account", RunE: func(cmd *cobra.Command, args []string) error { - validatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator)) + validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err } @@ -115,8 +115,8 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { return err } - delegatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressDelegator)) - validatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator)) + delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator)) + validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err } @@ -163,8 +163,8 @@ func GetCmdUnbond(cdc *wire.Codec) *cobra.Command { } } - delegatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressDelegator)) - validatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator)) + delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator)) + validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err } diff --git a/x/stake/delegation.go b/x/stake/delegation.go index 6877034d71..dedac03e58 100644 --- a/x/stake/delegation.go +++ b/x/stake/delegation.go @@ -35,11 +35,11 @@ func (b Delegation) GetBondShares() sdk.Rat { return b.Shares } //Human Friendly pretty printer func (b Delegation) HumanReadableString() (string, error) { - bechAcc, err := sdk.Bech32CosmosifyAcc(b.DelegatorAddr) + bechAcc, err := sdk.Bech32ifyAcc(b.DelegatorAddr) if err != nil { return "", err } - bechVal, err := sdk.Bech32CosmosifyAcc(b.ValidatorAddr) + bechVal, err := sdk.Bech32ifyAcc(b.ValidatorAddr) if err != nil { return "", err } diff --git a/x/stake/test_common.go b/x/stake/test_common.go index ae4adf4d8f..d06ac8d0af 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -22,16 +22,16 @@ import ( // dummy addresses used for testing var ( addrs = []sdk.Address{ - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctqyxjnwh"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6162", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctzhrnsa6"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6163", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctr2489qg"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6164", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctytvs4pd"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6165", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ct9k6yqul"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6166", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctxcf3kjq"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6167", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ct89l9r0j"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6168", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctg6jkls2"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6169", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctf8yz2dc"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160", "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctqyxjnwh"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161", "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6162", "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctzhrnsa6"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6163", "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctr2489qg"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6164", "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctytvs4pd"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6165", "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ct9k6yqul"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6166", "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctxcf3kjq"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6167", "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ct89l9r0j"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6168", "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctg6jkls2"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6169", "cosmosaccaddr15ky9du8a2wlstz6fpx3p4mqpjyrm5ctf8yz2dc"), } // dummy pubkeys used for testing @@ -144,7 +144,7 @@ func testAddr(addr string, bech string) sdk.Address { if err != nil { panic(err) } - bechexpected, err := sdk.Bech32CosmosifyAcc(res) + bechexpected, err := sdk.Bech32ifyAcc(res) if err != nil { panic(err) } @@ -152,7 +152,7 @@ func testAddr(addr string, bech string) sdk.Address { panic("Bech encoding doesn't match reference") } - bechres, err := sdk.GetAccAddressBech32Cosmos(bech) + bechres, err := sdk.GetAccAddressBech32(bech) if err != nil { panic(err) } diff --git a/x/stake/validator.go b/x/stake/validator.go index 729a605a96..1d9957d990 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -258,11 +258,11 @@ func (v Validator) GetBondHeight() int64 { return v.BondHeight } //Human Friendly pretty printer func (v Validator) HumanReadableString() (string, error) { - bechOwner, err := sdk.Bech32CosmosifyAcc(v.Owner) + bechOwner, err := sdk.Bech32ifyAcc(v.Owner) if err != nil { return "", err } - bechVal, err := sdk.Bech32CosmosifyValPub(v.PubKey) + bechVal, err := sdk.Bech32ifyValPub(v.PubKey) if err != nil { return "", err } From ad48f1b4a21b345389f96d52ad4433ccdde4538e Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Fri, 1 Jun 2018 12:32:26 -0700 Subject: [PATCH 112/128] fix for slashing with bech32 change --- x/slashing/client/cli/query.go | 2 +- x/slashing/client/cli/tx.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 42c02cab03..35f99d2fa3 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -21,7 +21,7 @@ func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command { Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - pk, err := sdk.GetValPubKeyBech32Cosmos(args[0]) + pk, err := sdk.GetValPubKeyBech32(args[0]) if err != nil { return err } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 13a5cb666f..19b1225bad 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -21,7 +21,7 @@ func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - validatorAddr, err := sdk.GetAccAddressBech32Cosmos(args[0]) + validatorAddr, err := sdk.GetAccAddressBech32(args[0]) if err != nil { return err } From 0ef3259a399f1cda30c38486233f4474d2ef683e Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 1 Jun 2018 14:24:48 -0700 Subject: [PATCH 113/128] revised use of EndBlock/BeginBlock, basecoin updated for staking/slashing --- .github/PULL_REQUEST_TEMPLATE.md | 1 + CHANGELOG.md | 3 + cmd/gaia/app/app.go | 24 +++++- cmd/gaia/app/app_test.go | 27 +------ cmd/gaia/app/genesis.go | 2 +- examples/basecoin/app/app.go | 52 ++++++++++--- examples/basecoin/app/app_test.go | 86 +++++++++++++++------ examples/basecoin/types/account.go | 4 +- x/slashing/client/cli/query.go | 2 +- x/slashing/client/cli/tx.go | 2 +- x/slashing/keeper_test.go | 4 +- x/slashing/tick.go | 76 +++++++++--------- x/stake/handler.go | 26 +++++-- x/stake/{tick.go => inflation.go} | 25 ------ x/stake/{tick_test.go => inflation_test.go} | 0 x/stake/keeper.go | 4 +- 16 files changed, 194 insertions(+), 144 deletions(-) rename x/stake/{tick.go => inflation.go} (74%) rename x/stake/{tick_test.go => inflation_test.go} (100%) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 902469b41c..3ddec8d336 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,3 +4,4 @@ * [ ] Updated all code comments where relevant * [ ] Wrote tests * [ ] Updated CHANGELOG.md +* [ ] Updated Basecoin / other examples diff --git a/CHANGELOG.md b/CHANGELOG.md index e23165799f..86a344654e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,16 +4,19 @@ BREAKING CHANGES * [cli] rearranged commands under subcommands +* [stake] remove Tick and add EndBlocker FEATURES IMPROVEMENTS * bank module uses go-wire codec instead of 'encoding/json' * auth module uses go-wire codec instead of 'encoding/json' +* revised use of endblock and beginblock FIXES * [cli] fixed cli-bash tests * [ci] added cli-bash tests +* [basecoin] updated basecoin for stake and slashing ## 0.18.1 diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 4fdb6a6c92..f8e71be293 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -85,8 +85,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { // initialize BaseApp app.SetInitChainer(app.initChainer) - app.SetBeginBlocker(slashing.NewBeginBlocker(app.slashingKeeper)) - app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper)) + app.SetBeginBlocker(app.BeginBlocker) + app.SetEndBlocker(app.EndBlocker) app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing) err := app.LoadLatestVersion(app.keyMain) @@ -110,6 +110,24 @@ func MakeCodec() *wire.Codec { return cdc } +// application updates every end block +func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { + tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper) + + return abci.ResponseBeginBlock{ + Tags: tags.ToKVPairs(), + } +} + +// application updates every end block +func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { + validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper) + + return abci.ResponseEndBlock{ + ValidatorUpdates: validatorUpdates, + } +} + // custom logic for gaia initialization func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { stateJSON := req.GenesisBytes @@ -134,7 +152,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci return abci.ResponseInitChain{} } -// export the state of gaia for a genesis f +// export the state of gaia for a genesis file func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) { ctx := app.NewContext(true, abci.Header{}) diff --git a/cmd/gaia/app/app_test.go b/cmd/gaia/app/app_test.go index 13ffdc33b7..7ba9752361 100644 --- a/cmd/gaia/app/app_test.go +++ b/cmd/gaia/app/app_test.go @@ -1,7 +1,6 @@ package app import ( - "encoding/json" "fmt" "os" "testing" @@ -139,30 +138,6 @@ func TestMsgs(t *testing.T) { } } -func setGenesisAccounts(gapp *GaiaApp, accs ...*auth.BaseAccount) error { - genaccs := make([]GenesisAccount, len(accs)) - for i, acc := range accs { - genaccs[i] = NewGenesisAccount(acc) - } - - genesisState := GenesisState{ - Accounts: genaccs, - StakeData: stake.DefaultGenesisState(), - } - - stateBytes, err := json.MarshalIndent(genesisState, "", "\t") - if err != nil { - return err - } - - // Initialize the chain - vals := []abci.Validator{} - gapp.InitChain(abci.RequestInitChain{vals, stateBytes}) - gapp.Commit() - - return nil -} - func TestGenesis(t *testing.T) { logger, dbs := loggerAndDB() gapp := NewGaiaApp(logger, dbs) @@ -178,7 +153,7 @@ func TestGenesis(t *testing.T) { } err = setGenesis(gapp, baseAcc) - assert.Nil(t, err) + require.Nil(t, err) // A checkTx context ctx := gapp.BaseApp.NewContext(true, abci.Header{}) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 4f76d6073b..813796c0d8 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -95,7 +95,7 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( return nil, nil, tmtypes.GenesisValidator{}, errors.New("Must specify --name (validator moniker)") } - var addr sdk.Address + var addr sdk.Address var secret string addr, secret, err = server.GenerateSaveCoinKey(clientRoot, name, "1234567890", overwrite) if err != nil { diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index a0b1f86ad6..f079010923 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/examples/basecoin/types" @@ -29,10 +30,11 @@ type BasecoinApp struct { cdc *wire.Codec // keys to access the substores - keyMain *sdk.KVStoreKey - keyAccount *sdk.KVStoreKey - keyIBC *sdk.KVStoreKey - keyStake *sdk.KVStoreKey + keyMain *sdk.KVStoreKey + keyAccount *sdk.KVStoreKey + keyIBC *sdk.KVStoreKey + keyStake *sdk.KVStoreKey + keySlashing *sdk.KVStoreKey // Manage getting and setting accounts accountMapper auth.AccountMapper @@ -40,6 +42,7 @@ type BasecoinApp struct { coinKeeper bank.Keeper ibcMapper ibc.Mapper stakeKeeper stake.Keeper + slashingKeeper slashing.Keeper } func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { @@ -49,12 +52,13 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { // Create your application object. var app = &BasecoinApp{ - BaseApp: bam.NewBaseApp(appName, cdc, logger, db), - cdc: cdc, - keyMain: sdk.NewKVStoreKey("main"), - keyAccount: sdk.NewKVStoreKey("acc"), - keyIBC: sdk.NewKVStoreKey("ibc"), - keyStake: sdk.NewKVStoreKey("stake"), + BaseApp: bam.NewBaseApp(appName, cdc, logger, db), + cdc: cdc, + keyMain: sdk.NewKVStoreKey("main"), + keyAccount: sdk.NewKVStoreKey("acc"), + keyIBC: sdk.NewKVStoreKey("ibc"), + keyStake: sdk.NewKVStoreKey("stake"), + keySlashing: sdk.NewKVStoreKey("slashing"), } // Define the accountMapper. @@ -68,6 +72,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { app.coinKeeper = bank.NewKeeper(app.accountMapper) app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace)) app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace)) + app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.RegisterCodespace(slashing.DefaultCodespace)) // register message routes app.Router(). @@ -78,8 +83,10 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { // Initialize BaseApp. app.SetInitChainer(app.initChainer) - app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake) + app.SetBeginBlocker(app.BeginBlocker) + app.SetEndBlocker(app.EndBlocker) app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) + app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing) err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) @@ -94,6 +101,7 @@ func MakeCodec() *wire.Codec { sdk.RegisterWire(cdc) // Register Msgs bank.RegisterWire(cdc) stake.RegisterWire(cdc) + slashing.RegisterWire(cdc) ibc.RegisterWire(cdc) // register custom AppAccount @@ -102,6 +110,24 @@ func MakeCodec() *wire.Codec { return cdc } +// application updates every end block +func (app *BasecoinApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { + tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper) + + return abci.ResponseBeginBlock{ + Tags: tags.ToKVPairs(), + } +} + +// application updates every end block +func (app *BasecoinApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { + validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper) + + return abci.ResponseEndBlock{ + ValidatorUpdates: validatorUpdates, + } +} + // Custom logic for basecoin initialization func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { stateJSON := req.GenesisBytes @@ -121,6 +147,10 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) } app.accountMapper.SetAccount(ctx, acc) } + + // load the initial stake information + stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData) + return abci.ResponseInitChain{} } diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index e297288d3f..4d445bda1d 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -11,9 +11,11 @@ import ( "github.com/cosmos/cosmos-sdk/examples/basecoin/types" 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/bank" "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/stake" abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" @@ -85,28 +87,18 @@ var ( } ) -func loggerAndDB() (log.Logger, dbm.DB) { - logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app") - db := dbm.NewMemDB() - return logger, db -} - -func newBasecoinApp() *BasecoinApp { - logger, db := loggerAndDB() - return NewBasecoinApp(logger, db) -} - -func setGenesisAccounts(bapp *BasecoinApp, accs ...auth.BaseAccount) error { +func setGenesis(bapp *BasecoinApp, accs ...auth.BaseAccount) error { genaccs := make([]*types.GenesisAccount, len(accs)) for i, acc := range accs { genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, accName}) } genesisState := types.GenesisState{ - Accounts: genaccs, + Accounts: genaccs, + StakeData: stake.DefaultGenesisState(), } - stateBytes, err := json.MarshalIndent(genesisState, "", "\t") + stateBytes, err := wire.MarshalJSONIndent(bapp.cdc, genesisState) if err != nil { return err } @@ -119,10 +111,46 @@ func setGenesisAccounts(bapp *BasecoinApp, accs ...auth.BaseAccount) error { return nil } +func loggerAndDB() (log.Logger, dbm.DB) { + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app") + db := dbm.NewMemDB() + return logger, db +} + +func newBasecoinApp() *BasecoinApp { + logger, db := loggerAndDB() + return NewBasecoinApp(logger, db) +} + +//func setGenesisAccounts(bapp *BasecoinApp, accs ...auth.BaseAccount) error { +//genaccs := make([]*types.GenesisAccount, len(accs)) +//for i, acc := range accs { +//genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, accName}) +//} + +//genesisState := types.GenesisState{ +//Accounts: genaccs, +//StakeData: stake.DefaultGenesisState(), +//} + +//stateBytes, err := json.MarshalIndent(genesisState, "", "\t") +//if err != nil { +//return err +//} + +//// Initialize the chain +//vals := []abci.Validator{} +//bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) +//bapp.Commit() + +//return nil +//} + //_______________________________________________________________________ func TestMsgs(t *testing.T) { bapp := newBasecoinApp() + require.Nil(t, setGenesis(bapp)) msgs := []struct { msg sdk.Msg @@ -193,8 +221,8 @@ func TestGenesis(t *testing.T) { } acc := &types.AppAccount{baseAcc, "foobart"} - err = setGenesisAccounts(bapp, baseAcc) - assert.Nil(t, err) + err = setGenesis(bapp, baseAcc) + require.Nil(t, err) // A checkTx context ctx := bapp.BaseApp.NewContext(true, abci.Header{}) @@ -222,8 +250,9 @@ func TestMsgChangePubKey(t *testing.T) { } // Construct genesis state - err = setGenesisAccounts(bapp, baseAcc) - assert.Nil(t, err) + err = setGenesis(bapp, baseAcc) + require.Nil(t, err) + // A checkTx context (true) ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{}) res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1) @@ -276,8 +305,9 @@ func TestMsgSendWithAccounts(t *testing.T) { } // Construct genesis state - err = setGenesisAccounts(bapp, baseAcc) - assert.Nil(t, err) + err = setGenesis(bapp, baseAcc) + require.Nil(t, err) + // A checkTx context (true) ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{}) res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1) @@ -320,8 +350,9 @@ func TestMsgSendMultipleOut(t *testing.T) { Coins: genCoins, } - err = setGenesisAccounts(bapp, acc1, acc2) - assert.Nil(t, err) + // Construct genesis state + err = setGenesis(bapp, acc1, acc2) + require.Nil(t, err) // Simulate a Block SignCheckDeliver(t, bapp, sendMsg2, []int64{0}, true, priv1) @@ -353,7 +384,7 @@ func TestSengMsgMultipleInOut(t *testing.T) { Coins: genCoins, } - err = setGenesisAccounts(bapp, acc1, acc2, acc4) + err = setGenesis(bapp, acc1, acc2, acc4) assert.Nil(t, err) // CheckDeliver @@ -377,7 +408,11 @@ func TestMsgSendDependent(t *testing.T) { Coins: genCoins, } - err = setGenesisAccounts(bapp, acc1) + // Construct genesis state + err = setGenesis(bapp, acc1) + require.Nil(t, err) + + err = setGenesis(bapp, acc1) assert.Nil(t, err) // CheckDeliver @@ -438,8 +473,9 @@ func TestIBCMsgs(t *testing.T) { } acc1 := &types.AppAccount{baseAcc, "foobart"} - err := setGenesisAccounts(bapp, baseAcc) + err := setGenesis(bapp, baseAcc) assert.Nil(t, err) + // A checkTx context (true) ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{}) res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1) diff --git a/examples/basecoin/types/account.go b/examples/basecoin/types/account.go index 223e0b9eb1..43a8e2e389 100644 --- a/examples/basecoin/types/account.go +++ b/examples/basecoin/types/account.go @@ -4,6 +4,7 @@ import ( 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 _ auth.Account = (*AppAccount)(nil) @@ -41,7 +42,8 @@ func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder { // State to Unmarshal type GenesisState struct { - Accounts []*GenesisAccount `json:"accounts"` + Accounts []*GenesisAccount `json:"accounts"` + StakeData stake.GenesisState `json:"stake"` } // GenesisAccount doesn't need pubkey or sequence diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 42c02cab03..35f99d2fa3 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -21,7 +21,7 @@ func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command { Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - pk, err := sdk.GetValPubKeyBech32Cosmos(args[0]) + pk, err := sdk.GetValPubKeyBech32(args[0]) if err != nil { return err } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 13a5cb666f..19b1225bad 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -21,7 +21,7 @@ func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) - validatorAddr, err := sdk.GetAccAddressBech32Cosmos(args[0]) + validatorAddr, err := sdk.GetAccAddressBech32(args[0]) if err != nil { return err } diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index a385627737..25ae1686d6 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -18,7 +18,7 @@ func TestHandleDoubleSign(t *testing.T) { addr, val, amt := addrs[0], pks[0], int64(100) got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) require.True(t, got.IsOK()) - sk.Tick(ctx) + stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) @@ -41,7 +41,7 @@ func TestHandleAbsentValidator(t *testing.T) { slh := NewHandler(keeper) got := sh(ctx, newTestMsgCreateValidator(addr, val, amt)) require.True(t, got.IsOK()) - sk.Tick(ctx) + stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) info, found := keeper.getValidatorSigningInfo(ctx, val.Address()) diff --git a/x/slashing/tick.go b/x/slashing/tick.go index 82f76d802f..c77e968871 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -10,49 +10,45 @@ import ( tmtypes "github.com/tendermint/tendermint/types" ) -func NewBeginBlocker(sk Keeper) sdk.BeginBlocker { - return func(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { - // Tag the height - heightBytes := make([]byte, 8) - binary.LittleEndian.PutUint64(heightBytes, uint64(req.Header.Height)) - tags := sdk.NewTags("height", heightBytes) +// slash begin blocker functionality +func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags sdk.Tags) { - // Deal with any equivocation evidence - for _, evidence := range req.ByzantineValidators { - var pk crypto.PubKey - sk.cdc.MustUnmarshalBinaryBare(evidence.PubKey, &pk) - switch string(evidence.Type) { - case tmtypes.DUPLICATE_VOTE: - sk.handleDoubleSign(ctx, evidence.Height, evidence.Time, pk) - default: - ctx.Logger().With("module", "x/slashing").Error(fmt.Sprintf("Ignored unknown evidence type: %s", string(evidence.Type))) - } - } + // Tag the height + heightBytes := make([]byte, 8) + binary.LittleEndian.PutUint64(heightBytes, uint64(req.Header.Height)) - // Figure out which validators were absent - absent := make(map[crypto.PubKey]struct{}) - for _, pubkey := range req.AbsentValidators { - var pk crypto.PubKey - sk.cdc.MustUnmarshalBinaryBare(pubkey, &pk) - absent[pk] = struct{}{} - } + // TODO Add some more tags so clients can track slashing events + tags = sdk.NewTags("height", heightBytes) - // Iterate over all the validators which *should* have signed this block - sk.stakeKeeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { - pubkey := validator.GetPubKey() - present := true - if _, ok := absent[pubkey]; ok { - present = false - } - sk.handleValidatorSignature(ctx, pubkey, present) - return false - }) - - // Return the begin block response - // TODO Return something composable, so other modules can also have BeginBlockers - // TODO Add some more tags so clients can track slashing events - return abci.ResponseBeginBlock{ - Tags: tags.ToKVPairs(), + // Deal with any equivocation evidence + for _, evidence := range req.ByzantineValidators { + var pk crypto.PubKey + sk.cdc.MustUnmarshalBinaryBare(evidence.PubKey, &pk) + switch string(evidence.Type) { + case tmtypes.DUPLICATE_VOTE: + sk.handleDoubleSign(ctx, evidence.Height, evidence.Time, pk) + default: + ctx.Logger().With("module", "x/slashing").Error(fmt.Sprintf("Ignored unknown evidence type: %s", string(evidence.Type))) } } + + // Figure out which validators were absent + absent := make(map[crypto.PubKey]struct{}) + for _, pubkey := range req.AbsentValidators { + var pk crypto.PubKey + sk.cdc.MustUnmarshalBinaryBare(pubkey, &pk) + absent[pk] = struct{}{} + } + + // Iterate over all the validators which *should* have signed this block + sk.stakeKeeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { + pubkey := validator.GetPubKey() + present := true + if _, ok := absent[pubkey]; ok { + present = false + } + sk.handleValidatorSignature(ctx, pubkey, present) + return false + }) + return } diff --git a/x/stake/handler.go b/x/stake/handler.go index b1c6a95b59..f366989b62 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -25,13 +25,27 @@ func NewHandler(k Keeper) sdk.Handler { } } -// NewEndBlocker generates sdk.EndBlocker -// Performs tick functionality -func NewEndBlocker(k Keeper) sdk.EndBlocker { - return func(ctx sdk.Context, req abci.RequestEndBlock) (res abci.ResponseEndBlock) { - res.ValidatorUpdates = k.Tick(ctx) - return +// Called every block, process inflation, update validator set +func EndBlocker(ctx sdk.Context, k Keeper) (ValidatorUpdates []abci.Validator) { + pool := k.GetPool(ctx) + + // Process Validator Provisions + blockTime := ctx.BlockHeader().Time // XXX assuming in seconds, confirm + if pool.InflationLastTime+blockTime >= 3600 { + pool.InflationLastTime = blockTime + pool = k.processProvisions(ctx) } + + // save the params + k.setPool(ctx, pool) + + // reset the intra-transaction counter + k.setIntraTxCounter(ctx, 0) + + // calculate validator set changes + ValidatorUpdates = k.getTendermintUpdates(ctx) + k.clearTendermintUpdates(ctx) + return } //_____________________________________________________________________ diff --git a/x/stake/tick.go b/x/stake/inflation.go similarity index 74% rename from x/stake/tick.go rename to x/stake/inflation.go index a8d9457347..f385e9d82c 100644 --- a/x/stake/tick.go +++ b/x/stake/inflation.go @@ -2,7 +2,6 @@ package stake import ( sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/abci/types" ) const ( @@ -12,30 +11,6 @@ const ( var hrsPerYrRat = sdk.NewRat(hrsPerYr) // as defined by a julian year of 365.25 days -// Tick - called at the end of every block -func (k Keeper) Tick(ctx sdk.Context) (change []abci.Validator) { - p := k.GetPool(ctx) - - // Process Validator Provisions - blockTime := ctx.BlockHeader().Time // XXX assuming in seconds, confirm - if p.InflationLastTime+blockTime >= 3600 { - p.InflationLastTime = blockTime - p = k.processProvisions(ctx) - } - - // save the params - k.setPool(ctx, p) - - // reset the intra-transaction counter - k.setIntraTxCounter(ctx, 0) - - // calculate validator set changes - change = k.getTendermintUpdates(ctx) - k.clearTendermintUpdates(ctx) - - return change -} - // process provisions for an hour period func (k Keeper) processProvisions(ctx sdk.Context) Pool { diff --git a/x/stake/tick_test.go b/x/stake/inflation_test.go similarity index 100% rename from x/stake/tick_test.go rename to x/stake/inflation_test.go diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 9fd902053a..9f554c764f 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -636,9 +636,9 @@ func (k Keeper) getPool(store sdk.KVStore) (pool Pool) { return } -func (k Keeper) setPool(ctx sdk.Context, p Pool) { +func (k Keeper) setPool(ctx sdk.Context, pool Pool) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinary(p) + b := k.cdc.MustMarshalBinary(pool) store.Set(PoolKey, b) } From f2cf0bee14626211104b2f20371245b169e32a57 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 1 Jun 2018 23:45:30 +0200 Subject: [PATCH 114/128] Remove commented-out testcode --- examples/basecoin/app/app_test.go | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index 4d445bda1d..8054baab27 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -122,30 +122,6 @@ func newBasecoinApp() *BasecoinApp { return NewBasecoinApp(logger, db) } -//func setGenesisAccounts(bapp *BasecoinApp, accs ...auth.BaseAccount) error { -//genaccs := make([]*types.GenesisAccount, len(accs)) -//for i, acc := range accs { -//genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, accName}) -//} - -//genesisState := types.GenesisState{ -//Accounts: genaccs, -//StakeData: stake.DefaultGenesisState(), -//} - -//stateBytes, err := json.MarshalIndent(genesisState, "", "\t") -//if err != nil { -//return err -//} - -//// Initialize the chain -//vals := []abci.Validator{} -//bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) -//bapp.Commit() - -//return nil -//} - //_______________________________________________________________________ func TestMsgs(t *testing.T) { From 024eaf6ac041c46a144b52756c58a54ab0b989cf Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Sat, 2 Jun 2018 00:27:37 +0200 Subject: [PATCH 115/128] Swap x/slashing to sdk.ValidatorSet --- x/slashing/handler.go | 4 ++-- x/slashing/keeper.go | 23 +++++++++++------------ x/slashing/tick.go | 2 +- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/x/slashing/handler.go b/x/slashing/handler.go index 98e9d30ada..5994bb8f19 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -21,7 +21,7 @@ func NewHandler(k Keeper) sdk.Handler { func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { // Validator must exist - validator := k.stakeKeeper.Validator(ctx, msg.ValidatorAddr) + validator := k.validatorSet.Validator(ctx, msg.ValidatorAddr) if validator == nil { return ErrNoValidatorForAddress(k.codespace).Result() } @@ -48,7 +48,7 @@ func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { k.setValidatorSigningInfo(ctx, addr, info) // Unrevoke the validator - k.stakeKeeper.Unrevoke(ctx, validator.GetPubKey()) + k.validatorSet.Unrevoke(ctx, validator.GetPubKey()) tags := sdk.NewTags("action", []byte("unrevoke"), "validator", msg.ValidatorAddr.Bytes()) diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index a37c5a07b8..d558cc04b0 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -5,27 +5,26 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" - "github.com/cosmos/cosmos-sdk/x/stake" crypto "github.com/tendermint/go-crypto" ) // Keeper of the slashing store type Keeper struct { - storeKey sdk.StoreKey - cdc *wire.Codec - stakeKeeper stake.Keeper + storeKey sdk.StoreKey + cdc *wire.Codec + validatorSet sdk.ValidatorSet // codespace codespace sdk.CodespaceType } // NewKeeper creates a slashing keeper -func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, sk stake.Keeper, codespace sdk.CodespaceType) Keeper { +func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, codespace sdk.CodespaceType) Keeper { keeper := Keeper{ - storeKey: key, - cdc: cdc, - stakeKeeper: sk, - codespace: codespace, + storeKey: key, + cdc: cdc, + validatorSet: vs, + codespace: codespace, } return keeper } @@ -43,7 +42,7 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, height int64, timestamp int64, // Double sign confirmed logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge)) - k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDoubleSign) + k.validatorSet.Slash(ctx, pubkey, height, SlashFractionDoubleSign) } // handle a validator signature, must be called once per validator per block @@ -81,8 +80,8 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { // Downtime confirmed, slash, revoke, and jail the validator logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, MinSignedPerWindow)) - k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDowntime) - k.stakeKeeper.Revoke(ctx, pubkey) + k.validatorSet.Slash(ctx, pubkey, height, SlashFractionDowntime) + k.validatorSet.Revoke(ctx, pubkey) signInfo.JailedUntil = ctx.BlockHeader().Time + DowntimeUnbondDuration } diff --git a/x/slashing/tick.go b/x/slashing/tick.go index c77e968871..d7bb79e272 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -41,7 +41,7 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags } // Iterate over all the validators which *should* have signed this block - sk.stakeKeeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { + sk.validatorSet.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { pubkey := validator.GetPubKey() present := true if _, ok := absent[pubkey]; ok { From 17ab868af55ca6ac537c41b948333d73a75c0742 Mon Sep 17 00:00:00 2001 From: Adrian Brink Date: Fri, 1 Jun 2018 22:50:41 -0700 Subject: [PATCH 116/128] Correct graphviz command in Makefile --- .gitignore | 5 ++++- Makefile | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b0684f2070..494e724528 100644 --- a/.gitignore +++ b/.gitignore @@ -19,8 +19,11 @@ baseapp/data/* coverage.txt profile.out -### Vagrant ### +# Vagrant .vagrant/ *.box *.log vagrant + +# Graphviz +dependency-graph.png \ No newline at end of file diff --git a/Makefile b/Makefile index 7d2d23ad63..f7e2083c76 100644 --- a/Makefile +++ b/Makefile @@ -70,7 +70,7 @@ get_vendor_deps: draw_deps: @# requires brew install graphviz or apt-get install graphviz go get github.com/RobotsAndPencils/goviz - @goviz -i github.com/tendermint/tendermint/cmd/tendermint -d 3 | dot -Tpng -o dependency-graph.png + @goviz -i github.com/cosmos/cosmos-sdk/cmd/gaia/cmd/gaiad -d 2 | dot -Tpng -o dependency-graph.png ######################################## From 5d2e7e94e5cedc3fc0386524fcf8afc99417dfad Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sat, 2 Jun 2018 04:41:34 -0700 Subject: [PATCH 117/128] Run CLI tests --- Makefile | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 7d2d23ad63..5cc9072304 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,4 @@ PACKAGES=$(shell go list ./... | grep -v '/vendor/') -PACKAGES_NOCLITEST=$(shell go list ./... | grep -v '/vendor/' | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test) COMMIT_HASH := $(shell git rev-parse --short HEAD) BUILD_FLAGS = -ldflags "-X github.com/cosmos/cosmos-sdk/version.GitCommit=${COMMIT_HASH}" @@ -86,11 +85,11 @@ godocs: test: test_unit -test_cli: - @go test -count 1 -p 1 `go list github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test` - test_unit: - @go test $(PACKAGES_NOCLITEST) + @GOCACHE=off go test -p 1 $(PACKAGES) + +test100: + @for i in {1..100}; do make test; done test_cover: @bash tests/test_cover.sh @@ -99,7 +98,7 @@ test_lint: gometalinter --disable-all --enable='golint' --vendor ./... benchmark: - @go test -bench=. $(PACKAGES_NOCLITEST) + @go test -bench=. $(PACKAGES) ######################################## From b0c58c0b37bd3ba51f1842e84566adb785d0710c Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sat, 2 Jun 2018 04:49:46 -0700 Subject: [PATCH 118/128] Revert "Run CLI tests" This reverts commit 5d2e7e94e5cedc3fc0386524fcf8afc99417dfad. --- Makefile | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 5cc9072304..7d2d23ad63 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ PACKAGES=$(shell go list ./... | grep -v '/vendor/') +PACKAGES_NOCLITEST=$(shell go list ./... | grep -v '/vendor/' | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test) COMMIT_HASH := $(shell git rev-parse --short HEAD) BUILD_FLAGS = -ldflags "-X github.com/cosmos/cosmos-sdk/version.GitCommit=${COMMIT_HASH}" @@ -85,11 +86,11 @@ godocs: test: test_unit -test_unit: - @GOCACHE=off go test -p 1 $(PACKAGES) +test_cli: + @go test -count 1 -p 1 `go list github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test` -test100: - @for i in {1..100}; do make test; done +test_unit: + @go test $(PACKAGES_NOCLITEST) test_cover: @bash tests/test_cover.sh @@ -98,7 +99,7 @@ test_lint: gometalinter --disable-all --enable='golint' --vendor ./... benchmark: - @go test -bench=. $(PACKAGES) + @go test -bench=. $(PACKAGES_NOCLITEST) ######################################## From 781975d6a0f546b7ef3599709affbea6a51c492c Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 4 Jun 2018 17:39:28 +0200 Subject: [PATCH 119/128] Feedback on REST server start (closes #973) --- client/lcd/root.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client/lcd/root.go b/client/lcd/root.go index df8be897c3..5071343021 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -56,6 +56,7 @@ func startRESTServerFn(cdc *wire.Codec) func(cmd *cobra.Command, args []string) if err != nil { return err } + logger.Info("REST server started") // Wait forever and cleanup cmn.TrapSignal(func() { From b9888d64ba005420f1065b458467f9aa3e5389ea Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 4 Jun 2018 21:04:17 +0200 Subject: [PATCH 120/128] Update PR checkboxes --- .github/PULL_REQUEST_TEMPLATE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3ddec8d336..9d234c3262 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,3 +5,4 @@ * [ ] Wrote tests * [ ] Updated CHANGELOG.md * [ ] Updated Basecoin / other examples +* [ ] Squashed related commits and prefixed with PR number per [coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr) From 3f4b041d0beaae6b2fcca456e8cfefc143c89ed0 Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Mon, 4 Jun 2018 12:33:09 -0700 Subject: [PATCH 121/128] changed to new cli commands in docs --- docs/sdk/lcd-rest-api.yaml | 20 ++++++++++---------- docs/staking/intro.rst | 24 ++++++++++++------------ docs/staking/testnet.rst | 6 +++--- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/sdk/lcd-rest-api.yaml b/docs/sdk/lcd-rest-api.yaml index 34ccaa0ac8..408b2a792b 100644 --- a/docs/sdk/lcd-rest-api.yaml +++ b/docs/sdk/lcd-rest-api.yaml @@ -2,9 +2,9 @@ swagger: '2.0' info: version: '1.1.0' title: Light client daemon to interface with Cosmos baseserver via REST - description: Specification for the LCD provided by `gaiacli rest-server` + description: Specification for the LCD provided by `gaiacli advanced rest-server` + - securityDefinitions: kms: type: basic @@ -58,7 +58,7 @@ paths: responses: 200: description: '"true" or "false"' - + /keys: get: summary: List of accounts stored locally @@ -199,7 +199,7 @@ paths: # description: Tx was send and will probably be added to the next block # 400: # description: The Tx was malformated - + /accounts/{address}: parameters: - in: path @@ -545,7 +545,7 @@ paths: # description: Tx was send and will probably be added to the next block # 400: # description: The Tx was malformated - + definitions: Address: type: string @@ -630,7 +630,7 @@ definitions: Sig: type: string default: '' - Pubkey: + Pubkey: type: string default: '' TxSigned: @@ -704,17 +704,17 @@ definitions: properties: header: type: object - properties: + properties: chain_id: type: string example: gaia-2 - height: + height: type: number example: 1 - time: + time: type: string example: '2017-12-30T05:53:09.287+01:00' - num_txs: + num_txs: type: number example: 0 last_block_id: diff --git a/docs/staking/intro.rst b/docs/staking/intro.rst index 7b5acb9863..5f7cdd950e 100644 --- a/docs/staking/intro.rst +++ b/docs/staking/intro.rst @@ -203,7 +203,7 @@ where the ``--sequence`` flag is to be incremented for each transaction, the ``- :: - Please enter passphrase for alice: + Please enter passphrase for alice: { "check_tx": { "gas": 30 @@ -250,7 +250,7 @@ First, we need the pub_key data: :: - cat $HOME/.gaia2/priv_validator.json + cat $HOME/.gaia2/priv_validator.json the first part will look like: @@ -264,13 +264,13 @@ Now ``bob`` can declare candidacy to that pubkey: :: - gaiacli declare-candidacy --amount=10mycoin --name=bob --pubkey= --moniker=bobby + gaiacli stake create-validator --amount=10mycoin --name=bob --pubkey= --moniker=bobby with an output like: :: - Please enter passphrase for bob: + Please enter passphrase for bob: { "check_tx": { "gas": 30 @@ -285,7 +285,7 @@ We should see ``bob``'s account balance decrease by 10 mycoin: :: - gaiacli account 5D93A6059B6592833CBC8FA3DA90EE0382198985 + gaiacli account 5D93A6059B6592833CBC8FA3DA90EE0382198985 To confirm for certain the new validator is active, ask the tendermint node: @@ -306,19 +306,19 @@ First let's have ``alice`` send some coins to ``charlie``: :: - gaiacli tx --amount=1000mycoin --sequence=2 --name=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF + gaiacli send --amount=1000mycoin --sequence=2 --name=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF Then ``charlie`` will delegate some mycoin to ``bob``: :: - gaiacli tx delegate --amount=10mycoin --name=charlie --pubkey= + gaiacli advanced tendermint tx delegate --amount=10mycoin --name=charlie --pubkey= You'll see output like: :: - Please enter passphrase for charlie: + Please enter passphrase for charlie: { "check_tx": { "gas": 30 @@ -334,7 +334,7 @@ To get more information about the candidate, try: :: - gaiacli query candidate --pubkey= + gaiacli stake validator --pubkey= and you'll see output similar to: @@ -367,7 +367,7 @@ It's also possible the query the delegator's bond like so: :: - gaiacli query delegator-bond --delegator-address 48F74F48281C89E5E4BE9092F735EA519768E8EF --pubkey 52D6FCD8C92A97F7CCB01205ADF310A18411EA8FDCC10E65BF2FCDB05AD1689B + gaiacli stake delegation --delegator-address 48F74F48281C89E5E4BE9092F735EA519768E8EF --pubkey 52D6FCD8C92A97F7CCB01205ADF310A18411EA8FDCC10E65BF2FCDB05AD1689B with an output similar to: @@ -383,7 +383,7 @@ with an output similar to: "Shares": 20 } } - + where the ``--delegator-address`` is ``charlie``'s address and the ``-pubkey`` is the same as we've been using. @@ -396,7 +396,7 @@ your VotingPower reduce and your account balance increase. :: - gaiacli unbond --amount=5mycoin --name=charlie --pubkey= + gaiacli stake unbond --amount=5mycoin --name=charlie --pubkey= gaiacli account 48F74F48281C89E5E4BE9092F735EA519768E8EF See the bond decrease with ``gaiacli query delegator-bond`` like above. diff --git a/docs/staking/testnet.rst b/docs/staking/testnet.rst index 92aa93eb26..c5341fee66 100644 --- a/docs/staking/testnet.rst +++ b/docs/staking/testnet.rst @@ -16,7 +16,7 @@ First, generate a couple of genesis transactions to be incorparated into the gen gaiacli keys list **Note:** If you've already run these tests you may need to overwrite keys using the ``--OWK`` flag -When you list the keys you should see two addresses, we'll need these later so take note. +When you list the keys you should see two addresses, we'll need these later so take note. Now let's actually create the genesis files for both nodes: :: @@ -44,7 +44,7 @@ Nice. We can also lookup the validator set: :: - gaiacli validatorset + gaiacli advanced tendermint validatorset Then, we try to transfer some ``steak`` to another account: @@ -72,7 +72,7 @@ Finally, to relinquish all your power, unbond some coins. You should see your Vo :: - gaiacli unbond --chain-id= --name=test + gaiacli stake unbond --chain-id= --name=test That's it! From be7ec5bc07e3dec3cbcf72c5050b9aeeb37d4452 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 5 Jun 2018 01:42:01 +0200 Subject: [PATCH 122/128] Merge PR #1115: Update SDK to ABCI v11 --- Gopkg.lock | 10 +-- Gopkg.toml | 4 +- baseapp/baseapp.go | 14 ++-- baseapp/baseapp_test.go | 18 +++-- cmd/gaia/app/app.go | 2 +- cmd/gaia/app/app_test.go | 2 +- examples/basecoin/app/app.go | 2 +- examples/basecoin/app/app_test.go | 6 +- examples/democoin/app/app.go | 2 +- examples/democoin/app/app_test.go | 10 +-- examples/democoin/x/simplestake/handler.go | 5 +- mock/app.go | 2 +- mock/app_test.go | 2 +- types/context.go | 12 ++-- types/stake.go | 3 +- x/slashing/test_common.go | 2 + x/slashing/tick.go | 38 ++++------- x/slashing/tick_test.go | 77 ++++++++++++++++++++++ x/stake/keeper_test.go | 5 +- x/stake/validator.go | 5 +- 20 files changed, 149 insertions(+), 72 deletions(-) create mode 100644 x/slashing/tick_test.go diff --git a/Gopkg.lock b/Gopkg.lock index eefc701b02..3e7d8c9d98 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -267,8 +267,8 @@ "server", "types" ] - revision = "f9dce537281ffba5d1e047e6729429f7e5fb90c9" - version = "v0.11.0-rc0" + revision = "9af8b7a7c87478869f8c280ed9539470b8f470b4" + version = "v0.11.0-rc4" [[projects]] branch = "master" @@ -347,8 +347,8 @@ "types/priv_validator", "version" ] - revision = "73de99ecab464208f6ea3a96525f4e4b78425e61" - version = "v0.20.0-rc0" + revision = "b5baab0238c9ec26e3b2d229b0243f9ff9220bdb" + version = "v0.20.0-rc3" [[projects]] branch = "develop" @@ -463,6 +463,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "c8d0282dfa5b2bb7a0eb54fc24f42021e63f282265332678593658119bf5023b" + inputs-digest = "ccb2ab7644a38c2d0326280582f758256e37fc98c3ef0403581e3b85cff42188" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 8c3f5131d0..05b14be60c 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -54,7 +54,7 @@ [[constraint]] name = "github.com/tendermint/abci" - version = "0.11.0-rc0" + version = "=0.11.0-rc4" [[constraint]] name = "github.com/tendermint/go-crypto" @@ -70,7 +70,7 @@ [[constraint]] name = "github.com/tendermint/tendermint" - version = "0.20.0-rc0" + version = "=0.20.0-rc3" [[override]] name = "github.com/tendermint/tmlibs" diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index cdc5ffcf7a..4d32b92f5c 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -65,10 +65,10 @@ type BaseApp struct { // See methods setCheckState and setDeliverState. // .valUpdates accumulate in DeliverTx and are reset in BeginBlock. // QUESTION: should we put valUpdates in the deliverState.ctx? - checkState *state // for CheckTx - deliverState *state // for DeliverTx - valUpdates []abci.Validator // cached validator changes from DeliverTx - absentValidators [][]byte // absent validators from begin block + checkState *state // for CheckTx + deliverState *state // for DeliverTx + valUpdates []abci.Validator // cached validator changes from DeliverTx + signedValidators []abci.SigningValidator // absent validators from begin block } var _ abci.Application = (*BaseApp)(nil) @@ -385,8 +385,8 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg if app.beginBlocker != nil { res = app.beginBlocker(app.deliverState.ctx, req) } - // set the absent validators for addition to context in deliverTx - app.absentValidators = req.AbsentValidators + // set the signed validators for addition to context in deliverTx + app.signedValidators = req.Validators return } @@ -496,7 +496,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk ctx = app.checkState.ctx.WithTxBytes(txBytes) } else { ctx = app.deliverState.ctx.WithTxBytes(txBytes) - ctx = ctx.WithAbsentValidators(app.absentValidators) + ctx = ctx.WithSigningValidators(app.signedValidators) } // Simulate a DeliverTx for gas calculation diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 0b825e1ee8..a0b83d35cb 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -1,7 +1,6 @@ package baseapp import ( - "bytes" "encoding/json" "fmt" "os" @@ -12,6 +11,7 @@ import ( abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" + tmtypes "github.com/tendermint/tendermint/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -183,7 +183,7 @@ func TestInitChainer(t *testing.T) { // set initChainer and try again - should see the value app.SetInitChainer(initChainer) - app.InitChain(abci.RequestInitChain{GenesisBytes: []byte("{}")}) // must have valid JSON genesis file, even if empty + app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}")}) // must have valid JSON genesis file, even if empty app.Commit() res = app.Query(query) assert.Equal(t, value, res.Value) @@ -510,15 +510,20 @@ func TestValidatorChange(t *testing.T) { // Assert that validator updates are correct. for _, val := range valSet { + + pubkey, err := tmtypes.PB2TM.PubKey(val.PubKey) // Sanity - assert.NotEqual(t, len(val.PubKey), 0) + assert.Nil(t, err) // Find matching update and splice it out. - for j := 0; j < len(valUpdates); { + for j := 0; j < len(valUpdates); j++ { valUpdate := valUpdates[j] + updatePubkey, err := tmtypes.PB2TM.PubKey(valUpdate.PubKey) + assert.Nil(t, err) + // Matched. - if bytes.Equal(valUpdate.PubKey, val.PubKey) { + if updatePubkey.Equals(pubkey) { assert.Equal(t, valUpdate.Power, val.Power+1) if j < len(valUpdates)-1 { // Splice it out. @@ -528,7 +533,6 @@ func TestValidatorChange(t *testing.T) { } // Not matched. - j++ } } assert.Equal(t, len(valUpdates), 0, "Some validator updates were unexpected") @@ -542,7 +546,7 @@ func randPower() int64 { func makeVal(secret string) abci.Validator { return abci.Validator{ - PubKey: makePubKey(secret).Bytes(), + PubKey: tmtypes.TM2PB.PubKey(makePubKey(secret)), Power: randPower(), } } diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index f8e71be293..8f8ed281ed 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -130,7 +130,7 @@ func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.R // custom logic for gaia initialization func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - stateJSON := req.GenesisBytes + stateJSON := req.AppStateBytes // TODO is this now the whole genesis file? var genesisState GenesisState diff --git a/cmd/gaia/app/app_test.go b/cmd/gaia/app/app_test.go index 7ba9752361..b6fffac32f 100644 --- a/cmd/gaia/app/app_test.go +++ b/cmd/gaia/app/app_test.go @@ -114,7 +114,7 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error { // Initialize the chain vals := []abci.Validator{} - gapp.InitChain(abci.RequestInitChain{vals, stateBytes}) + gapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) gapp.Commit() return nil diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index f079010923..1718b8be23 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -130,7 +130,7 @@ func (app *BasecoinApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) ab // Custom logic for basecoin initialization func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - stateJSON := req.GenesisBytes + stateJSON := req.AppStateBytes genesisState := new(types.GenesisState) err := app.cdc.UnmarshalJSON(stateJSON, genesisState) diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index 8054baab27..3027a84707 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -105,7 +105,7 @@ func setGenesis(bapp *BasecoinApp, accs ...auth.BaseAccount) error { // Initialize the chain vals := []abci.Validator{} - bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) + bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) bapp.Commit() return nil @@ -165,7 +165,7 @@ func TestSortGenesis(t *testing.T) { // Initialize the chain vals := []abci.Validator{} - bapp.InitChain(abci.RequestInitChain{vals, []byte(genState)}) + bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: []byte(genState)}) bapp.Commit() // Unsorted coins means invalid @@ -427,7 +427,7 @@ func TestMsgQuiz(t *testing.T) { // Initialize the chain (nil) vals := []abci.Validator{} - bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) + bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) bapp.Commit() // A checkTx context (true) diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index b8b8642cf3..2075a64da0 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -118,7 +118,7 @@ func MakeCodec() *wire.Codec { // custom logic for democoin initialization func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - stateJSON := req.GenesisBytes + stateJSON := req.AppStateBytes genesisState := new(types.GenesisState) err := app.cdc.UnmarshalJSON(stateJSON, genesisState) diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index e025c50627..ba041bcff1 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -142,7 +142,7 @@ func TestGenesis(t *testing.T) { stateBytes, err := json.MarshalIndent(genesisState, "", "\t") vals := []abci.Validator{} - bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) + bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) bapp.Commit() // A checkTx context @@ -184,7 +184,7 @@ func TestMsgSendWithAccounts(t *testing.T) { // Initialize the chain vals := []abci.Validator{} - bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) + bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) bapp.Commit() // A checkTx context (true) @@ -262,7 +262,7 @@ func TestMsgMine(t *testing.T) { // Initialize the chain (nil) vals := []abci.Validator{} - bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) + bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) bapp.Commit() // A checkTx context (true) @@ -309,7 +309,7 @@ func TestMsgQuiz(t *testing.T) { // Initialize the chain (nil) vals := []abci.Validator{} - bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) + bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) bapp.Commit() // A checkTx context (true) @@ -356,7 +356,7 @@ func TestHandler(t *testing.T) { } stateBytes, err := json.MarshalIndent(genesisState, "", "\t") require.Nil(t, err) - bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) + bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes}) bapp.Commit() // A checkTx context (true) diff --git a/examples/democoin/x/simplestake/handler.go b/examples/democoin/x/simplestake/handler.go index a84e8b07bf..a94da3d5ea 100644 --- a/examples/democoin/x/simplestake/handler.go +++ b/examples/democoin/x/simplestake/handler.go @@ -2,6 +2,7 @@ package simplestake import ( abci "github.com/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -27,7 +28,7 @@ func handleMsgBond(ctx sdk.Context, k Keeper, msg MsgBond) sdk.Result { } valSet := abci.Validator{ - PubKey: msg.PubKey.Bytes(), + PubKey: tmtypes.TM2PB.PubKey(msg.PubKey), Power: power, } @@ -44,7 +45,7 @@ func handleMsgUnbond(ctx sdk.Context, k Keeper, msg MsgUnbond) sdk.Result { } valSet := abci.Validator{ - PubKey: pubKey.Bytes(), + PubKey: tmtypes.TM2PB.PubKey(pubKey), Power: int64(0), } diff --git a/mock/app.go b/mock/app.go index 09d7a658c7..ab1a8447a5 100644 --- a/mock/app.go +++ b/mock/app.go @@ -88,7 +88,7 @@ type GenesisJSON struct { // with key/value pairs func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci.ResponseInitChain { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - stateJSON := req.GenesisBytes + stateJSON := req.AppStateBytes genesisState := new(GenesisJSON) err := json.Unmarshal(stateJSON, genesisState) diff --git a/mock/app_test.go b/mock/app_test.go index 50b0761c17..be1d778295 100644 --- a/mock/app_test.go +++ b/mock/app_test.go @@ -26,7 +26,7 @@ func TestInitApp(t *testing.T) { //TODO test validators in the init chain? req := abci.RequestInitChain{ - GenesisBytes: appState, + AppStateBytes: appState, } app.InitChain(req) app.Commit() diff --git a/types/context.go b/types/context.go index 10ae99724f..c4fc385c70 100644 --- a/types/context.go +++ b/types/context.go @@ -44,7 +44,7 @@ func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byt c = c.WithIsCheckTx(isCheckTx) c = c.WithTxBytes(txBytes) c = c.WithLogger(logger) - c = c.WithAbsentValidators(nil) + c = c.WithSigningValidators(nil) c = c.WithGasMeter(NewInfiniteGasMeter()) return c } @@ -130,7 +130,7 @@ const ( contextKeyIsCheckTx contextKeyTxBytes contextKeyLogger - contextKeyAbsentValidators + contextKeySigningValidators contextKeyGasMeter ) @@ -160,8 +160,8 @@ func (c Context) TxBytes() []byte { func (c Context) Logger() log.Logger { return c.Value(contextKeyLogger).(log.Logger) } -func (c Context) AbsentValidators() [][]byte { - return c.Value(contextKeyAbsentValidators).([][]byte) +func (c Context) SigningValidators() []abci.SigningValidator { + return c.Value(contextKeySigningValidators).([]abci.SigningValidator) } func (c Context) GasMeter() GasMeter { return c.Value(contextKeyGasMeter).(GasMeter) @@ -188,8 +188,8 @@ func (c Context) WithTxBytes(txBytes []byte) Context { func (c Context) WithLogger(logger log.Logger) Context { return c.withValue(contextKeyLogger, logger) } -func (c Context) WithAbsentValidators(AbsentValidators [][]byte) Context { - return c.withValue(contextKeyAbsentValidators, AbsentValidators) +func (c Context) WithSigningValidators(SigningValidators []abci.SigningValidator) Context { + return c.withValue(contextKeySigningValidators, SigningValidators) } func (c Context) WithGasMeter(meter GasMeter) Context { return c.withValue(contextKeyGasMeter, meter) diff --git a/types/stake.go b/types/stake.go index bfcef7fa0c..6a620db762 100644 --- a/types/stake.go +++ b/types/stake.go @@ -3,6 +3,7 @@ package types import ( abci "github.com/tendermint/abci/types" "github.com/tendermint/go-crypto" + tmtypes "github.com/tendermint/tendermint/types" ) // status of a validator @@ -41,7 +42,7 @@ type Validator interface { // validator which fulfills abci validator interface for use in Tendermint func ABCIValidator(v Validator) abci.Validator { return abci.Validator{ - PubKey: v.GetPubKey().Bytes(), + PubKey: tmtypes.TM2PB.PubKey(v.GetPubKey()), Power: v.GetPower().Evaluate(), } } diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index c76eaadde7..94d323d232 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -24,10 +24,12 @@ var ( addrs = []sdk.Address{ testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160"), testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161"), + testAddr("A58856F0FD53BF058B4909A21AEC019107BA6162"), } pks = []crypto.PubKey{ newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"), newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), + newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"), } initCoins int64 = 200 ) diff --git a/x/slashing/tick.go b/x/slashing/tick.go index d7bb79e272..526baece08 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -6,49 +6,39 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" tmtypes "github.com/tendermint/tendermint/types" ) -// slash begin blocker functionality +// slashing begin block functionality func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags sdk.Tags) { - // Tag the height heightBytes := make([]byte, 8) binary.LittleEndian.PutUint64(heightBytes, uint64(req.Header.Height)) - - // TODO Add some more tags so clients can track slashing events tags = sdk.NewTags("height", heightBytes) // Deal with any equivocation evidence for _, evidence := range req.ByzantineValidators { - var pk crypto.PubKey - sk.cdc.MustUnmarshalBinaryBare(evidence.PubKey, &pk) + pk, err := tmtypes.PB2TM.PubKey(evidence.Validator.PubKey) + if err != nil { + panic(err) + } switch string(evidence.Type) { - case tmtypes.DUPLICATE_VOTE: + case tmtypes.ABCIEvidenceTypeDuplicateVote: sk.handleDoubleSign(ctx, evidence.Height, evidence.Time, pk) default: ctx.Logger().With("module", "x/slashing").Error(fmt.Sprintf("Ignored unknown evidence type: %s", string(evidence.Type))) } } - // Figure out which validators were absent - absent := make(map[crypto.PubKey]struct{}) - for _, pubkey := range req.AbsentValidators { - var pk crypto.PubKey - sk.cdc.MustUnmarshalBinaryBare(pubkey, &pk) - absent[pk] = struct{}{} - } - - // Iterate over all the validators which *should* have signed this block - sk.validatorSet.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { - pubkey := validator.GetPubKey() - present := true - if _, ok := absent[pubkey]; ok { - present = false + // Iterate over all the validators which *should* have signed this block + for _, validator := range req.Validators { + present := validator.SignedLastBlock + pubkey, err := tmtypes.PB2TM.PubKey(validator.Validator.PubKey) + if err != nil { + panic(err) } sk.handleValidatorSignature(ctx, pubkey, present) - return false - }) + } + return } diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go new file mode 100644 index 0000000000..adf2e5e5b9 --- /dev/null +++ b/x/slashing/tick_test.go @@ -0,0 +1,77 @@ +package slashing + +import ( + "testing" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/stake" +) + +func TestBeginBlocker(t *testing.T) { + ctx, ck, sk, keeper := createTestInput(t) + addr, pk, amt := addrs[2], pks[2], int64(100) + + // bond the validator + got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, pk, amt)) + require.True(t, got.IsOK()) + stake.EndBlocker(ctx, sk) + require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}}) + require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) + + val := abci.Validator{ + PubKey: tmtypes.TM2PB.PubKey(pk), + Power: amt, + } + + // mark the validator as having signed + req := abci.RequestBeginBlock{ + Validators: []abci.SigningValidator{{ + Validator: val, + SignedLastBlock: true, + }}, + } + BeginBlocker(ctx, req, keeper) + + info, found := keeper.getValidatorSigningInfo(ctx, pk.Address()) + require.True(t, found) + require.Equal(t, ctx.BlockHeight(), info.StartHeight) + require.Equal(t, int64(1), info.IndexOffset) + require.Equal(t, int64(0), info.JailedUntil) + require.Equal(t, int64(1), info.SignedBlocksCounter) + + height := int64(0) + + // for 50 blocks, mark the validator as having signed + for ; height < 50; height++ { + ctx = ctx.WithBlockHeight(height) + req = abci.RequestBeginBlock{ + Validators: []abci.SigningValidator{{ + Validator: val, + SignedLastBlock: true, + }}, + } + BeginBlocker(ctx, req, keeper) + } + + // for 51 blocks, mark the validator as having not signed + for ; height < 102; height++ { + ctx = ctx.WithBlockHeight(height) + req = abci.RequestBeginBlock{ + Validators: []abci.SigningValidator{{ + Validator: val, + SignedLastBlock: false, + }}, + } + BeginBlocker(ctx, req, keeper) + } + + // validator should be revoked + validator, found := sk.GetValidatorByPubKey(ctx, pk) + require.True(t, found) + require.Equal(t, sdk.Unbonded, validator.GetStatus()) +} diff --git a/x/stake/keeper_test.go b/x/stake/keeper_test.go index 01d4434e83..69a2144283 100644 --- a/x/stake/keeper_test.go +++ b/x/stake/keeper_test.go @@ -4,6 +4,7 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + tmtypes "github.com/tendermint/tendermint/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -463,8 +464,8 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) { updates = keeper.getTendermintUpdates(ctx) require.Equal(t, 2, len(updates)) - assert.Equal(t, validators[0].PubKey.Bytes(), updates[0].PubKey) - assert.Equal(t, validators[1].PubKey.Bytes(), updates[1].PubKey) + assert.Equal(t, tmtypes.TM2PB.PubKey(validators[0].PubKey), updates[0].PubKey) + assert.Equal(t, tmtypes.TM2PB.PubKey(validators[1].PubKey), updates[1].PubKey) assert.Equal(t, int64(0), updates[0].Power) assert.Equal(t, int64(0), updates[1].Power) } diff --git a/x/stake/validator.go b/x/stake/validator.go index 1d9957d990..a0b484d712 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" + tmtypes "github.com/tendermint/tendermint/types" ) // Validator defines the total amount of bond shares and their exchange rate to @@ -101,7 +102,7 @@ func NewDescription(moniker, identity, website, details string) Description { // abci validator from stake validator type func (v Validator) abciValidator(cdc *wire.Codec) abci.Validator { return abci.Validator{ - PubKey: v.PubKey.Bytes(), + PubKey: tmtypes.TM2PB.PubKey(v.PubKey), Power: v.PoolShares.Bonded().Evaluate(), } } @@ -110,7 +111,7 @@ func (v Validator) abciValidator(cdc *wire.Codec) abci.Validator { // with zero power used for validator updates func (v Validator) abciValidatorZero(cdc *wire.Codec) abci.Validator { return abci.Validator{ - PubKey: v.PubKey.Bytes(), + PubKey: tmtypes.TM2PB.PubKey(v.PubKey), Power: 0, } } From 5a831bd0f89c15ebe5d6a8d3f55d0779daf7308f Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Mon, 4 Jun 2018 18:35:07 -0700 Subject: [PATCH 123/128] additional changes --- client/rpc/validators.go | 2 +- docs/staking/intro.rst | 16 ++++++++-------- docs/staking/testnet.rst | 2 +- x/slashing/client/cli/query.go | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/client/rpc/validators.go b/client/rpc/validators.go index 27b7fce99e..d1aa6c9c18 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -17,7 +17,7 @@ import ( //ValidatorCommand returns the validator set for a given height func ValidatorCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "validatorset [height]", + Use: "validator-set [height]", Short: "Get the full tendermint validator set at given height", Args: cobra.MaximumNArgs(1), RunE: printValidators, diff --git a/docs/staking/intro.rst b/docs/staking/intro.rst index 5f7cdd950e..00a68811a8 100644 --- a/docs/staking/intro.rst +++ b/docs/staking/intro.rst @@ -260,11 +260,11 @@ the first part will look like: and you want the ``pub_key`` ``data`` that starts with ``96864CE``. -Now ``bob`` can declare candidacy to that pubkey: +Now ``bob`` can create a validator with that pubkey. :: - gaiacli stake create-validator --amount=10mycoin --name=bob --pubkey= --moniker=bobby + gaiacli stake create-validator --amount=10mycoin --name=bob --address-validator=
--pub-key= --moniker=bobby with an output like: @@ -312,7 +312,7 @@ Then ``charlie`` will delegate some mycoin to ``bob``: :: - gaiacli advanced tendermint tx delegate --amount=10mycoin --name=charlie --pubkey= + gaiacli stake delegate --amount=10mycoin --address-delegator= --address-validator= --name=charlie You'll see output like: @@ -334,7 +334,7 @@ To get more information about the candidate, try: :: - gaiacli stake validator --pubkey= + gaiacli stake validator
and you'll see output similar to: @@ -367,7 +367,7 @@ It's also possible the query the delegator's bond like so: :: - gaiacli stake delegation --delegator-address 48F74F48281C89E5E4BE9092F735EA519768E8EF --pubkey 52D6FCD8C92A97F7CCB01205ADF310A18411EA8FDCC10E65BF2FCDB05AD1689B + gaiacli stake delegation --address-delegator=
--address-validator=
with an output similar to: @@ -385,7 +385,7 @@ with an output similar to: } -where the ``--delegator-address`` is ``charlie``'s address and the ``-pubkey`` is the same as we've been using. +where the ``--address-delegator`` is ``charlie``'s address and the ``--address-validator`` is ``bob``'s address. Unbonding @@ -396,7 +396,7 @@ your VotingPower reduce and your account balance increase. :: - gaiacli stake unbond --amount=5mycoin --name=charlie --pubkey= + gaiacli stake unbond --amount=5mycoin --name=charlie --address-delegator=
--address-validator=
gaiacli account 48F74F48281C89E5E4BE9092F735EA519768E8EF -See the bond decrease with ``gaiacli query delegator-bond`` like above. +See the bond decrease with ``gaiacli stake delegation`` like above. diff --git a/docs/staking/testnet.rst b/docs/staking/testnet.rst index c5341fee66..4fca09c4ad 100644 --- a/docs/staking/testnet.rst +++ b/docs/staking/testnet.rst @@ -44,7 +44,7 @@ Nice. We can also lookup the validator set: :: - gaiacli advanced tendermint validatorset + gaiacli advanced tendermint validator-set Then, we try to transfer some ``steak`` to another account: diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 35f99d2fa3..948e756675 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -16,7 +16,7 @@ import ( // get the command to query signing info func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "signing_info [validator-pubkey]", + Use: "signing-info [validator-pubkey]", Short: "Query a validator's signing information", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { From 91c89627402897e77e3ff183afbcd46e6a03c76b Mon Sep 17 00:00:00 2001 From: Jeremiah Andrews Date: Mon, 4 Jun 2018 18:38:50 -0700 Subject: [PATCH 124/128] changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86a344654e..22969a4037 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ FIXES * [cli] fixed cli-bash tests * [ci] added cli-bash tests * [basecoin] updated basecoin for stake and slashing +* [docs] fixed references to old cli commands ## 0.18.1 @@ -32,7 +33,7 @@ BREAKING CHANGES * [x/auth] removed the FeeHandler function from the AnteHandler, Replaced with FeeKeeper * [x/auth] Removed GetSignatures() from Tx interface (as different Tx styles might use something different than StdSignature) * [store] Removed SubspaceIterator and ReverseSubspaceIterator from KVStore interface and replaced them with helper functions in /types -* Switch to bech32cosmos on all human readable inputs and outputs +* Switch to bech32cosmos on all human readable inputs and outputs BUG FIXES From fefd1d2d8b593812404e52d201e6060e893d4d14 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Mon, 4 Jun 2018 21:55:02 -0700 Subject: [PATCH 125/128] Merge PR #1075: Add more baseapp tests * Complete TestCheckTx * Add a test for delivering invalid transaction types * Add test for loading of older versions --- baseapp/baseapp_test.go | 158 ++++++++++++++++++++++++++++++++-------- 1 file changed, 128 insertions(+), 30 deletions(-) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index a0b83d35cb..532d39f1e6 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -83,18 +83,36 @@ func TestLoadVersion(t *testing.T) { header := abci.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) res := app.Commit() - commitID := sdk.CommitID{1, res.Data} + commitID1 := sdk.CommitID{1, res.Data} + header = abci.Header{Height: 2} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + res = app.Commit() + commitID2 := sdk.CommitID{2, res.Data} - // reload + // reload with LoadLatestVersion app = NewBaseApp(name, nil, logger, db) app.MountStoresIAVL(capKey) - err = app.LoadLatestVersion(capKey) // needed to make stores non-nil + err = app.LoadLatestVersion(capKey) assert.Nil(t, err) + testLoadVersionHelper(t, app, int64(2), commitID2) - lastHeight = app.LastBlockHeight() - lastID = app.LastCommitID() - assert.Equal(t, int64(1), lastHeight) - assert.Equal(t, commitID, lastID) + // reload with LoadVersion, see if you can commit the same block and get + // the same result + app = NewBaseApp(name, nil, logger, db) + app.MountStoresIAVL(capKey) + err = app.LoadVersion(1, capKey) + assert.Nil(t, err) + testLoadVersionHelper(t, app, int64(1), commitID1) + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + app.Commit() + testLoadVersionHelper(t, app, int64(2), commitID2) +} + +func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, expectedID sdk.CommitID) { + lastHeight := app.LastBlockHeight() + lastID := app.LastCommitID() + assert.Equal(t, expectedHeight, lastHeight) + assert.Equal(t, expectedID, lastID) } // Test that the app hash is static @@ -206,11 +224,91 @@ func TestInitChainer(t *testing.T) { assert.Equal(t, value, res.Value) } +func getStateCheckingHandler(t *testing.T, capKey *sdk.KVStoreKey, txPerHeight int, checkHeader bool) func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + counter := 0 + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + store := ctx.KVStore(capKey) + // Checking state gets updated between checkTx's / DeliverTx's + // on the store within a block. + if counter > 0 { + // check previous value in store + counterBytes := []byte{byte(counter - 1)} + prevBytes := store.Get(counterBytes) + assert.Equal(t, counterBytes, prevBytes) + } + + // set the current counter in the store + counterBytes := []byte{byte(counter)} + store.Set(counterBytes, counterBytes) + + // check that we can see the current header + // wrapped in an if, so it can be reused between CheckTx and DeliverTx tests. + if checkHeader { + thisHeader := ctx.BlockHeader() + height := int64((counter / txPerHeight) + 1) + assert.Equal(t, height, thisHeader.Height) + } + + counter++ + return sdk.Result{} + } +} + +// A mock transaction that has a validation which can fail. +type testTx struct { + positiveNum int64 +} + +const msgType2 = "testTx" + +func (tx testTx) Type() string { return msgType2 } +func (tx testTx) GetMsg() sdk.Msg { return tx } +func (tx testTx) GetSignBytes() []byte { return nil } +func (tx testTx) GetSigners() []sdk.Address { return nil } +func (tx testTx) GetSignatures() []auth.StdSignature { return nil } +func (tx testTx) ValidateBasic() sdk.Error { + if tx.positiveNum >= 0 { + return nil + } + return sdk.ErrTxDecode("positiveNum should be a non-negative integer.") +} + // Test that successive CheckTx can see each others' effects // on the store within a block, and that the CheckTx state // gets reset to the latest Committed state during Commit func TestCheckTx(t *testing.T) { - // TODO + // Initialize an app for testing + app := newBaseApp(t.Name()) + // make a cap key and mount the store + capKey := sdk.NewKVStoreKey("main") + app.MountStoresIAVL(capKey) + err := app.LoadLatestVersion(capKey) // needed to make stores non-nil + assert.Nil(t, err) + app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return }) + + txPerHeight := 3 + app.Router().AddRoute(msgType, getStateCheckingHandler(t, capKey, txPerHeight, false)). + AddRoute(msgType2, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return }) + tx := testUpdatePowerTx{} // doesn't matter + for i := 0; i < txPerHeight; i++ { + app.Check(tx) + } + // If it gets to this point, then successive CheckTx's can see the effects of + // other CheckTx's on the block. The following checks that if another block + // is committed, the CheckTx State will reset. + app.BeginBlock(abci.RequestBeginBlock{}) + tx2 := testTx{} + for i := 0; i < txPerHeight; i++ { + app.Deliver(tx2) + } + app.EndBlock(abci.RequestEndBlock{}) + app.Commit() + + checkStateStore := app.checkState.ctx.KVStore(capKey) + for i := 0; i < txPerHeight; i++ { + storedValue := checkStateStore.Get([]byte{byte(i)}) + assert.Nil(t, storedValue) + } } // Test that successive DeliverTx can see each others' effects @@ -224,30 +322,9 @@ func TestDeliverTx(t *testing.T) { err := app.LoadLatestVersion(capKey) // needed to make stores non-nil assert.Nil(t, err) - counter := 0 txPerHeight := 2 app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return }) - app.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { - store := ctx.KVStore(capKey) - if counter > 0 { - // check previous value in store - counterBytes := []byte{byte(counter - 1)} - prevBytes := store.Get(counterBytes) - assert.Equal(t, prevBytes, counterBytes) - } - - // set the current counter in the store - counterBytes := []byte{byte(counter)} - store.Set(counterBytes, counterBytes) - - // check we can see the current header - thisHeader := ctx.BlockHeader() - height := int64((counter / txPerHeight) + 1) - assert.Equal(t, height, thisHeader.Height) - - counter++ - return sdk.Result{} - }) + app.Router().AddRoute(msgType, getStateCheckingHandler(t, capKey, txPerHeight, true)) tx := testUpdatePowerTx{} // doesn't matter header := abci.Header{AppHash: []byte("apphash")} @@ -325,6 +402,27 @@ func TestSimulateTx(t *testing.T) { } } +func TestRunInvalidTransaction(t *testing.T) { + // Initialize an app for testing + app := newBaseApp(t.Name()) + // make a cap key and mount the store + capKey := sdk.NewKVStoreKey("main") + app.MountStoresIAVL(capKey) + err := app.LoadLatestVersion(capKey) // needed to make stores non-nil + assert.Nil(t, err) + app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return }) + app.Router().AddRoute(msgType2, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return }) + app.BeginBlock(abci.RequestBeginBlock{}) + // Transaction where validate fails + invalidTx := testTx{-1} + err1 := app.Deliver(invalidTx) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeTxDecode), err1.Code) + // Transaction with no known route + unknownRouteTx := testUpdatePowerTx{} + err2 := app.Deliver(unknownRouteTx) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), err2.Code) +} + // Test that transactions exceeding gas limits fail func TestTxGasLimits(t *testing.T) { logger := defaultLogger() From af15f89531600b89f807399420b5ede83833efe5 Mon Sep 17 00:00:00 2001 From: Adrian Brink Date: Tue, 5 Jun 2018 21:34:19 -0700 Subject: [PATCH 126/128] Update changelog for 0.18.0 (#1149) --- CHANGELOG.md | 72 +++++++++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22969a4037..cf2ac21b03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,49 +1,8 @@ # Changelog -## Pending - -BREAKING CHANGES -* [cli] rearranged commands under subcommands -* [stake] remove Tick and add EndBlocker - -FEATURES - -IMPROVEMENTS -* bank module uses go-wire codec instead of 'encoding/json' -* auth module uses go-wire codec instead of 'encoding/json' -* revised use of endblock and beginblock - -FIXES -* [cli] fixed cli-bash tests -* [ci] added cli-bash tests -* [basecoin] updated basecoin for stake and slashing -* [docs] fixed references to old cli commands - -## 0.18.1 - -BREAKING CHANGES - -* [x/auth] move stuff specific to auth anteHandler to the auth module rather than the types folder. This includes: - * StdTx (and its related stuff i.e. StdSignDoc, etc) - * StdFee - * StdSignature - * Account interface - * Related to this organization, I also: -* [x/auth] got rid of AccountMapper interface (in favor of the struct already in auth module) -* [x/auth] removed the FeeHandler function from the AnteHandler, Replaced with FeeKeeper -* [x/auth] Removed GetSignatures() from Tx interface (as different Tx styles might use something different than StdSignature) -* [store] Removed SubspaceIterator and ReverseSubspaceIterator from KVStore interface and replaced them with helper functions in /types -* Switch to bech32cosmos on all human readable inputs and outputs - -BUG FIXES - -* auto-sequencing transactions correctly -* query sequence via account store -* fixed duplicate pub_key in stake.Validator - ## 0.18.0 -_TBD_ +_2018-06-05_ BREAKING CHANGES @@ -62,6 +21,20 @@ BREAKING CHANGES * Introduction of Unbonding fields, lowlevel logic throughout (not fully implemented with queue) * Introduction of PoolShares type within validators, replaces three rational fields (BondedShares, UnbondingShares, UnbondedShares +* [x/auth] move stuff specific to auth anteHandler to the auth module rather than the types folder. This includes: + * StdTx (and its related stuff i.e. StdSignDoc, etc) + * StdFee + * StdSignature + * Account interface + * Related to this organization, I also: +* [x/auth] got rid of AccountMapper interface (in favor of the struct already in auth module) +* [x/auth] removed the FeeHandler function from the AnteHandler, Replaced with FeeKeeper +* [x/auth] Removed GetSignatures() from Tx interface (as different Tx styles might use something different than StdSignature) +* [store] Removed SubspaceIterator and ReverseSubspaceIterator from KVStore interface and replaced them with helper functions in /types +* [cli] rearranged commands under subcommands +* [stake] remove Tick and add EndBlocker +* Switch to bech32cosmos on all human readable inputs and outputs + FEATURES @@ -78,12 +51,22 @@ FEATURES * [stake] Added REST API * [Makefile] Added terraform/ansible playbooks to easily create remote testnets on Digital Ocean + BUG FIXES -* Auto-sequencing now works correctly * [stake] staking delegator shares exchange rate now relative to equivalent-bonded-tokens the validator has instead of bonded tokens ^ this is important for unbonded validators in the power store! +* [cli] fixed cli-bash tests +* [ci] added cli-bash tests +* [basecoin] updated basecoin for stake and slashing +* [docs] fixed references to old cli commands * [docs] Downgraded Swagger to v2 for downstream compatibility +* auto-sequencing transactions correctly +* query sequence via account store +* fixed duplicate pub_key in stake.Validator +* Auto-sequencing now works correctly + + ## 0.17.2 @@ -123,6 +106,7 @@ BUG FIXES * Auto-sequencing now works correctly + ## 0.16.0 (May 14th, 2018) BREAKING CHANGES @@ -157,12 +141,14 @@ BUG FIXES * Gaia now uses stake, ported from github.com/cosmos/gaia + ## 0.15.1 (April 29, 2018) IMPROVEMENTS: * Update Tendermint to v0.19.1 (includes many rpc fixes) + ## 0.15.0 (April 29, 2018) NOTE: v0.15.0 is a large breaking change that updates the encoding scheme to use From 5f409ce83247cce37ef34adeff2503f11a1903ee Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 6 Jun 2018 06:53:04 +0200 Subject: [PATCH 127/128] Merge PR #1086: Bech32Cosmos output/input for the LCD * refactored bech32ization * updated keys endpoints for bech32 * bech32 for sending and querying * trying to change output of validator addresses * fixed validator output * linted * fixed merge conflict * added bech32 to staking endpoints * removed some logging statements * added GetAccPubKeyBech32Cosmos * fixed cli tests * updated swagger * merged standard bech32 change * renamed bech32cosmos to bech32 * bech32ify json output for key add * readded changelog * fixed changelog merge issue * Update CHANGELOG.md --- CHANGELOG.md | 4 ++ client/keys/add.go | 11 ++--- client/keys/list.go | 9 ++-- client/keys/show.go | 8 +++- client/keys/utils.go | 64 +++++++++++++++++------------ client/lcd/lcd_test.go | 69 +++++++++++++++++-------------- client/rpc/validators.go | 50 ++++++++++++++++++++++- cmd/gaia/cli_test/cli_test.go | 8 +++- docs/sdk/lcd-rest-api.yaml | 77 ++++++++++++++++++----------------- types/account.go | 17 +++++++- x/auth/client/rest/query.go | 8 ++-- x/bank/client/rest/sendtx.go | 11 ++++- x/ibc/client/rest/transfer.go | 11 ++++- x/stake/client/rest/query.go | 75 ++++++++++++++++++++++++++++++---- x/stake/client/rest/tx.go | 64 ++++++++++++++++++++++++----- 15 files changed, 348 insertions(+), 138 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf2ac21b03..731f3c14a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +BREAKING CHANGES + +* [lcd] Switch to bech32 for addresses on all human readable inputs and outputs + ## 0.18.0 _2018-06-05_ diff --git a/client/keys/add.go b/client/keys/add.go index da368a3a63..7ad9474cef 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -102,12 +102,6 @@ func runAddCmd(cmd *cobra.Command, args []string) error { return nil } -// addOutput lets us json format the data -type addOutput struct { - Key keys.Info `json:"key"` - Seed string `json:"seed"` -} - func printCreate(info keys.Info, seed string) { output := viper.Get(cli.OutputFlag) switch output { @@ -121,7 +115,10 @@ func printCreate(info keys.Info, seed string) { fmt.Println(seed) } case "json": - out := addOutput{Key: info} + out, err := Bech32KeyOutput(info) + if err != nil { + panic(err) + } if !viper.GetBool(flagNoBackup) { out.Seed = seed } diff --git a/client/keys/list.go b/client/keys/list.go index 9af511e5cd..22f163f1d8 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -4,7 +4,6 @@ import ( "encoding/json" "net/http" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/cobra" ) @@ -54,9 +53,11 @@ func QueryKeysRequestHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("[]")) return } - keysOutput := make([]KeyOutput, len(infos)) - for i, info := range infos { - keysOutput[i] = KeyOutput{Name: info.Name, Address: sdk.Address(info.PubKey.Address().Bytes())} + keysOutput, err := Bech32KeysOutput(infos) + if err != nil { + w.WriteHeader(500) + w.Write([]byte(err.Error())) + return } output, err := json.MarshalIndent(keysOutput, "", " ") if err != nil { diff --git a/client/keys/show.go b/client/keys/show.go index c7be9cc9db..9051aba160 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -4,7 +4,6 @@ import ( "encoding/json" "net/http" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/gorilla/mux" keys "github.com/tendermint/go-crypto/keys" @@ -51,7 +50,12 @@ func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) { return } - keyOutput := KeyOutput{Name: info.Name, Address: sdk.Address(info.PubKey.Address())} + keyOutput, err := Bech32KeyOutput(info) + if err != nil { + w.WriteHeader(500) + w.Write([]byte(err.Error())) + return + } output, err := json.MarshalIndent(keyOutput, "", " ") if err != nil { w.WriteHeader(500) diff --git a/client/keys/utils.go b/client/keys/utils.go index 1c1fd0979a..d810dfa1f4 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -6,7 +6,6 @@ import ( "github.com/spf13/viper" - crypto "github.com/tendermint/go-crypto" keys "github.com/tendermint/go-crypto/keys" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" @@ -47,29 +46,47 @@ func SetKeyBase(kb keys.Keybase) { // used for outputting keys.Info over REST type KeyOutput struct { - Name string `json:"name"` - Address sdk.Address `json:"address"` - PubKey crypto.PubKey `json:"pub_key"` + Name string `json:"name"` + Address string `json:"address"` + PubKey string `json:"pub_key"` + Seed string `json:"seed,omitempty"` } -func NewKeyOutput(info keys.Info) KeyOutput { - return KeyOutput{ - Name: info.Name, - Address: sdk.Address(info.PubKey.Address().Bytes()), - PubKey: info.PubKey, - } -} - -func NewKeyOutputs(infos []keys.Info) []KeyOutput { +// create a list of KeyOutput in bech32 format +func Bech32KeysOutput(infos []keys.Info) ([]KeyOutput, error) { kos := make([]KeyOutput, len(infos)) for i, info := range infos { - kos[i] = NewKeyOutput(info) + ko, err := Bech32KeyOutput(info) + if err != nil { + return nil, err + } + kos[i] = ko } - return kos + return kos, nil +} + +// create a KeyOutput in bech32 format +func Bech32KeyOutput(info keys.Info) (KeyOutput, error) { + bechAccount, err := sdk.Bech32ifyAcc(sdk.Address(info.PubKey.Address().Bytes())) + if err != nil { + return KeyOutput{}, err + } + bechPubKey, err := sdk.Bech32ifyAccPub(info.PubKey) + if err != nil { + return KeyOutput{}, err + } + return KeyOutput{ + Name: info.Name, + Address: bechAccount, + PubKey: bechPubKey, + }, nil } func printInfo(info keys.Info) { - ko := NewKeyOutput(info) + ko, err := Bech32KeyOutput(info) + if err != nil { + panic(err) + } switch viper.Get(cli.OutputFlag) { case "text": fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") @@ -84,7 +101,10 @@ func printInfo(info keys.Info) { } func printInfos(infos []keys.Info) { - kos := NewKeyOutputs(infos) + kos, err := Bech32KeysOutput(infos) + if err != nil { + panic(err) + } switch viper.Get(cli.OutputFlag) { case "text": fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") @@ -101,13 +121,5 @@ func printInfos(infos []keys.Info) { } func printKeyOutput(ko KeyOutput) { - bechAccount, err := sdk.Bech32ifyAcc(ko.Address) - if err != nil { - panic(err) - } - bechPubKey, err := sdk.Bech32ifyAccPub(ko.PubKey) - if err != nil { - panic(err) - } - fmt.Printf("%s\t%s\t%s\n", ko.Name, bechAccount, bechPubKey) + fmt.Printf("%s\t%s\t%s\n", ko.Name, ko.Address, ko.PubKey) } diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 7a9cdbc254..47df51e7e3 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -33,6 +33,7 @@ import ( client "github.com/cosmos/cosmos-sdk/client" keys "github.com/cosmos/cosmos-sdk/client/keys" + rpc "github.com/cosmos/cosmos-sdk/client/rpc" gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/server" tests "github.com/cosmos/cosmos-sdk/tests" @@ -40,14 +41,17 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/stake" + stakerest "github.com/cosmos/cosmos-sdk/x/stake/client/rest" ) var ( coinDenom = "steak" coinAmount = int64(10000000) - validatorAddr1 = "" - validatorAddr2 = "" + validatorAddr1Hx = "" + validatorAddr2Hx = "" + validatorAddr1 = "" + validatorAddr2 = "" // XXX bad globals name = "test" @@ -99,13 +103,13 @@ func TestKeys(t *testing.T) { err = cdc.UnmarshalJSON([]byte(body), &m) require.Nil(t, err) - sendAddrAcc, _ := sdk.GetAccAddressHex(sendAddr) addrAcc, _ := sdk.GetAccAddressHex(addr) + addrBech32, _ := sdk.Bech32ifyAcc(addrAcc) - assert.Equal(t, m[0].Name, name, "Did not serve keys name correctly") - assert.Equal(t, m[0].Address, sendAddrAcc, "Did not serve keys Address correctly") - assert.Equal(t, m[1].Name, newName, "Did not serve keys name correctly") - assert.Equal(t, m[1].Address, addrAcc, "Did not serve keys Address correctly") + assert.Equal(t, name, m[0].Name, "Did not serve keys name correctly") + assert.Equal(t, sendAddr, m[0].Address, "Did not serve keys Address correctly") + assert.Equal(t, newName, m[1].Name, "Did not serve keys name correctly") + assert.Equal(t, addrBech32, m[1].Address, "Did not serve keys Address correctly") // select key keyEndpoint := fmt.Sprintf("/keys/%s", newName) @@ -116,7 +120,7 @@ func TestKeys(t *testing.T) { require.Nil(t, err) assert.Equal(t, newName, m2.Name, "Did not serve keys name correctly") - assert.Equal(t, addrAcc, m2.Address, "Did not serve keys Address correctly") + assert.Equal(t, addrBech32, m2.Address, "Did not serve keys Address correctly") // update key jsonStr = []byte(fmt.Sprintf(`{"old_password":"%s", "new_password":"12345678901"}`, newPassword)) @@ -198,7 +202,7 @@ func TestBlock(t *testing.T) { func TestValidators(t *testing.T) { - var resultVals ctypes.ResultValidators + var resultVals rpc.ResultValidatorsOutput res, body := request(t, port, "GET", "/validatorsets/latest", nil) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -206,7 +210,10 @@ func TestValidators(t *testing.T) { err := cdc.UnmarshalJSON([]byte(body), &resultVals) require.Nil(t, err, "Couldn't parse validatorset") - assert.NotEqual(t, ctypes.ResultValidators{}, resultVals) + assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals) + + assert.Contains(t, resultVals.Validators[0].Address, "cosmosvaladdr") + assert.Contains(t, resultVals.Validators[0].PubKey, "cosmosvalpub") // -- @@ -216,7 +223,7 @@ func TestValidators(t *testing.T) { err = cdc.UnmarshalJSON([]byte(body), &resultVals) require.Nil(t, err, "Couldn't parse validatorset") - assert.NotEqual(t, ctypes.ResultValidators{}, resultVals) + assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals) // -- @@ -225,10 +232,11 @@ func TestValidators(t *testing.T) { } func TestCoinSend(t *testing.T) { + bz, _ := hex.DecodeString("8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6") + someFakeAddr, _ := sdk.Bech32ifyAcc(bz) // query empty - //res, body := request(t, port, "GET", "/accounts/8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6", nil) - res, body := request(t, port, "GET", "/accounts/8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6", nil) + res, body := request(t, port, "GET", "/accounts/"+someFakeAddr, nil) require.Equal(t, http.StatusNoContent, res.StatusCode, body) acc := getAccount(t, sendAddr) @@ -323,15 +331,14 @@ func TestValidatorsQuery(t *testing.T) { // 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 { + if validators[0].Owner == validatorAddr1 || validators[1].Owner == validatorAddr1 { foundVal1 = true } - if res1 == validatorAddr2 || res2 == validatorAddr2 { + if validators[0].Owner == validatorAddr2 || validators[1].Owner == 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) + assert.True(t, foundVal1, "validatorAddr1 %v, owner1 %v, owner2 %v", validatorAddr1, validators[0].Owner, validators[1].Owner) + assert.True(t, foundVal2, "validatorAddr2 %v, owner1 %v, owner2 %v", validatorAddr2, validators[0].Owner, validators[1].Owner) } func TestBond(t *testing.T) { @@ -418,8 +425,10 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { pk1 := genDoc.Validators[0].PubKey pk2 := genDoc.Validators[1].PubKey - validatorAddr1 = hex.EncodeToString(pk1.Address()) - validatorAddr2 = hex.EncodeToString(pk2.Address()) + validatorAddr1Hx = hex.EncodeToString(pk1.Address()) + validatorAddr2Hx = hex.EncodeToString(pk2.Address()) + validatorAddr1, _ = sdk.Bech32ifyVal(pk1.Address()) + validatorAddr2, _ = sdk.Bech32ifyVal(pk2.Address()) // NOTE it's bad practice to reuse pk address for the owner address but doing in the // test for simplicity @@ -444,7 +453,8 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { if err != nil { return nil, nil, err } - sendAddr = info.PubKey.Address().String() // XXX global + sendAddrHex, _ := sdk.GetAccAddressHex(info.PubKey.Address().String()) + sendAddr, _ = sdk.Bech32ifyAcc(sendAddrHex) // XXX global accAuth := auth.NewBaseAccountWithAddress(info.PubKey.Address()) accAuth.Coins = sdk.Coins{{"steak", 100}} acc := gapp.NewGenesisAccount(&accAuth) @@ -548,7 +558,7 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype kb := client.MockKeyBase() receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519")) require.Nil(t, err) - receiveAddr = receiveInfo.PubKey.Address().String() + receiveAddr, _ = sdk.Bech32ifyAcc(receiveInfo.PubKey.Address()) acc := getAccount(t, sendAddr) sequence := acc.GetSequence() @@ -565,12 +575,11 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype } func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) { - // create receive address kb := client.MockKeyBase() receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519")) require.Nil(t, err) - receiveAddr := receiveInfo.PubKey.Address().String() + receiveAddr, _ := sdk.Bech32ifyAcc(receiveInfo.PubKey.Address()) // get the account to get the sequence acc := getAccount(t, sendAddr) @@ -609,13 +618,13 @@ func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxC "sequence": %d, "delegate": [ { - "delegator_addr": "%x", + "delegator_addr": "%s", "validator_addr": "%s", "bond": { "denom": "%s", "amount": 10 } } ], "unbond": [] - }`, name, password, sequence, acc.GetAddress(), validatorAddr1, coinDenom)) + }`, name, password, sequence, sendAddr, validatorAddr1, coinDenom)) res, body := request(t, port, "POST", "/stake/delegations", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -639,12 +648,12 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT "bond": [], "unbond": [ { - "delegator_addr": "%x", + "delegator_addr": "%s", "validator_addr": "%s", "shares": "1" } ] - }`, name, password, sequence, acc.GetAddress(), validatorAddr1)) + }`, name, password, sequence, sendAddr, validatorAddr1)) res, body := request(t, port, "POST", "/stake/delegations", jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -655,11 +664,11 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT return results[0] } -func getValidators(t *testing.T) []stake.Validator { +func getValidators(t *testing.T) []stakerest.StakeValidatorOutput { // 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.Validators + var validators []stakerest.StakeValidatorOutput err := cdc.UnmarshalJSON([]byte(body), &validators) require.Nil(t, err) return validators diff --git a/client/rpc/validators.go b/client/rpc/validators.go index d1aa6c9c18..f8835d7377 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -10,6 +10,8 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + tmtypes "github.com/tendermint/tendermint/types" ) // TODO these next two functions feel kinda hacky based on their placement @@ -28,6 +30,38 @@ func ValidatorCommand() *cobra.Command { return cmd } +// Validator output in bech32 format +type ValidatorOutput struct { + Address string `json:"address"` // in bech32 + PubKey string `json:"pub_key"` // in bech32 + Accum int64 `json:"accum"` + VotingPower int64 `json:"voting_power"` +} + +// Validators at a certain height output in bech32 format +type ResultValidatorsOutput struct { + BlockHeight int64 `json:"block_height"` + Validators []ValidatorOutput `json:"validators"` +} + +func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error) { + bechAddress, err := sdk.Bech32ifyVal(validator.Address) + if err != nil { + return ValidatorOutput{}, err + } + bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey) + if err != nil { + return ValidatorOutput{}, err + } + + return ValidatorOutput{ + Address: bechAddress, + PubKey: bechValPubkey, + Accum: validator.Accum, + VotingPower: validator.VotingPower, + }, nil +} + func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) { // get the node node, err := ctx.GetNode() @@ -35,12 +69,23 @@ func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) { return nil, err } - res, err := node.Validators(height) + validatorsRes, err := node.Validators(height) if err != nil { return nil, err } - output, err := cdc.MarshalJSON(res) + outputValidatorsRes := ResultValidatorsOutput{ + BlockHeight: validatorsRes.BlockHeight, + Validators: make([]ValidatorOutput, len(validatorsRes.Validators)), + } + for i := 0; i < len(validatorsRes.Validators); i++ { + outputValidatorsRes.Validators[i], err = bech32ValidatorOutput(validatorsRes.Validators[i]) + if err != nil { + return nil, err + } + } + + output, err := cdc.MarshalJSON(outputValidatorsRes) if err != nil { return nil, err } @@ -96,6 +141,7 @@ func ValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc { w.Write([]byte(err.Error())) return } + w.Write(output) } } diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index ae46a623cd..1868452a64 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -170,7 +170,13 @@ func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.Address, crypto.PubKey) var ko keys.KeyOutput keys.UnmarshalJSON([]byte(out), &ko) - return ko.Address, ko.PubKey + address, err := sdk.GetAccAddressBech32(ko.Address) + require.NoError(t, err) + + pk, err := sdk.GetAccPubKeyBech32(ko.PubKey) + require.NoError(t, err) + + return address, pk } func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount { diff --git a/docs/sdk/lcd-rest-api.yaml b/docs/sdk/lcd-rest-api.yaml index 408b2a792b..3008d7f73c 100644 --- a/docs/sdk/lcd-rest-api.yaml +++ b/docs/sdk/lcd-rest-api.yaml @@ -102,7 +102,7 @@ paths: - application/json responses: 200: - description: 12 word Seed + description: 16 word Seed schema: type: string /keys/{name}: @@ -204,7 +204,7 @@ paths: parameters: - in: path name: address - description: Account address + description: Account address in bech32 format required: true type: string get: @@ -222,7 +222,7 @@ paths: parameters: - in: path name: address - description: Account address + description: Account address in bech32 format required: true type: string post: @@ -255,18 +255,6 @@ paths: description: Tx was send and will probably be added to the next block 400: description: The Tx was malformated - /accounts/{address}/nonce: - parameters: - - in: path - name: address - description: Account address - required: true - type: string - get: - summary: Get the nonce for a certain account - responses: - 200: - description: Plaintext nonce i.e. "4" defaults to "0" /blocks/latest: get: summary: Get the latest block @@ -304,9 +292,14 @@ paths: 200: description: The validator set at the latest block height schema: - type: array - items: - $ref: "#/definitions/Delegate" + type: object + properties: + block_height: + type: number + validators: + type: array + items: + $ref: "#/definitions/Validator" /validatorsets/{height}: parameters: - in: path @@ -322,9 +315,14 @@ paths: 200: description: The validator set at a specific block height schema: - type: array - items: - $ref: "#/definitions/Delegate" + type: object + properties: + block_height: + type: number + validators: + type: array + items: + $ref: "#/definitions/Validator" 404: description: Block at height not available # /txs: @@ -549,7 +547,20 @@ paths: definitions: Address: type: string - example: DF096FDE8D380FA5B2AD20DB2962C82DDEA1ED9B + description: bech32 encoded addres + example: cosmosaccaddr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq + ValidatorAddress: + type: string + description: bech32 encoded addres + example: cosmosvaladdr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq + PubKey: + type: string + description: bech32 encoded public key + example: cosmosaccpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq + ValidatorPubKey: + type: string + description: bech32 encoded public key + example: cosmosvalpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq Coins: type: object properties: @@ -652,16 +663,6 @@ definitions: example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958 Pubkey: $ref: "#/definitions/PubKey" - PubKey: - type: object - properties: - type: - type: string - enum: - - ed25519 - data: - type: string - example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958 Account: type: object properties: @@ -753,17 +754,19 @@ definitions: type: array items: type: object - Delegate: + Validator: type: object properties: + address: + $ref: '#/definitions/ValidatorAddress' pub_key: - $ref: "#/definitions/PubKey" + $ref: "#/definitions/ValidatorPubKey" power: type: number example: 1000 - name: - type: string - example: "159.89.3.34" + accum: + type: number + example: 1000 # Added by API Auto Mocking Plugin host: virtserver.swaggerhub.com basePath: /faboweb1/Cosmos-LCD-2/1.0.0 diff --git a/types/account.go b/types/account.go index ad0c58231f..00d180a1c7 100644 --- a/types/account.go +++ b/types/account.go @@ -32,7 +32,7 @@ func Bech32ifyAccPub(pub crypto.PubKey) (string, error) { } // Bech32ifyVal returns the bech32 encoded string for a validator address -func bech32ifyVal(addr Address) (string, error) { +func Bech32ifyVal(addr Address) (string, error) { return bech32.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes()) } @@ -62,6 +62,21 @@ func GetAccAddressBech32(address string) (addr Address, err error) { return Address(bz), nil } +// create a Pubkey from a string +func GetAccPubKeyBech32(address string) (pk crypto.PubKey, err error) { + bz, err := getFromBech32(address, Bech32PrefixAccPub) + if err != nil { + return nil, err + } + + pk, err = crypto.PubKeyFromBytes(bz) + if err != nil { + return nil, err + } + + return pk, nil +} + // create an Address from a hex string func GetValAddressHex(address string) (addr Address, err error) { if len(address) == 0 { diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index a60ce5cdb2..bcae59c203 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -1,7 +1,6 @@ package rest import ( - "encoding/hex" "fmt" "net/http" @@ -26,17 +25,16 @@ func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, sto func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder, ctx context.CoreContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - addr := vars["address"] + bech32addr := vars["address"] - bz, err := hex.DecodeString(addr) + addr, err := sdk.GetAccAddressBech32(bech32addr) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - key := sdk.Address(bz) - res, err := ctx.Query(key, storeName) + res, err := ctx.Query(addr, storeName) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Could't query account. Error: %s", err.Error()))) diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index defed3f144..83ab3b843f 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -41,7 +41,14 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont return func(w http.ResponseWriter, r *http.Request) { // collect data vars := mux.Vars(r) - address := vars["address"] + bech32addr := vars["address"] + + address, err := sdk.GetAccAddressBech32(bech32addr) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } var m sendBody body, err := ioutil.ReadAll(r.Body) @@ -64,7 +71,7 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont return } - to, err := sdk.GetAccAddressHex(address) + to, err := sdk.GetAccAddressHex(address.String()) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go index 48a29ee801..d897c6e4f6 100644 --- a/x/ibc/client/rest/transfer.go +++ b/x/ibc/client/rest/transfer.go @@ -35,7 +35,14 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core // collect data vars := mux.Vars(r) destChainID := vars["destchain"] - address := vars["address"] + bech32addr := vars["address"] + + address, err := sdk.GetAccAddressBech32(bech32addr) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } var m transferBody body, err := ioutil.ReadAll(r.Body) @@ -58,7 +65,7 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core return } - bz, err := hex.DecodeString(address) + bz, err := hex.DecodeString(address.String()) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 3e439c2b44..0da3260cb8 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -1,7 +1,6 @@ package rest import ( - "encoding/hex" "fmt" "net/http" @@ -30,24 +29,22 @@ func bondingStatusHandlerFn(ctx context.CoreContext, storeName string, cdc *wire // read parameters vars := mux.Vars(r) - delegator := vars["delegator"] - validator := vars["validator"] + bech32delegator := vars["delegator"] + bech32validator := vars["validator"] - bz, err := hex.DecodeString(delegator) + delegatorAddr, err := sdk.GetAccAddressBech32(bech32delegator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - delegatorAddr := sdk.Address(bz) - bz, err = hex.DecodeString(validator) + validatorAddr, err := sdk.GetValAddressBech32(bech32validator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - validatorAddr := sdk.Address(bz) key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc) @@ -83,6 +80,62 @@ func bondingStatusHandlerFn(ctx context.CoreContext, storeName string, cdc *wire } } +// TODO inherit from Validator +type StakeValidatorOutput struct { + Owner string `json:"owner"` // in bech32 + PubKey string `json:"pub_key"` // in bech32 + Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? + + PoolShares stake.PoolShares `json:"pool_shares"` // total shares for tokens held in the pool + DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators + + Description stake.Description `json:"description"` // description terms for the validator + BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator + BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change + ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer + + Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators + CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge + CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission + CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) + + // fee related + PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools +} + +func bech32StakeValidatorOutput(validator stake.Validator) (StakeValidatorOutput, error) { + bechOwner, err := sdk.Bech32ifyVal(validator.Owner) + if err != nil { + return StakeValidatorOutput{}, err + } + bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey) + if err != nil { + return StakeValidatorOutput{}, err + } + + return StakeValidatorOutput{ + Owner: bechOwner, + PubKey: bechValPubkey, + Revoked: validator.Revoked, + + PoolShares: validator.PoolShares, + DelegatorShares: validator.DelegatorShares, + + Description: validator.Description, + BondHeight: validator.BondHeight, + BondIntraTxCounter: validator.BondIntraTxCounter, + ProposerRewardPool: validator.ProposerRewardPool, + + Commission: validator.Commission, + CommissionMax: validator.CommissionMax, + CommissionChangeRate: validator.CommissionChangeRate, + CommissionChangeToday: validator.CommissionChangeToday, + + PrevBondedShares: validator.PrevBondedShares, + }, nil +} + +// TODO bech32 // http request handler to query list of validators func validatorsHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -100,16 +153,20 @@ func validatorsHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Co } // parse out the validators - validators := make([]stake.Validator, len(kvs)) + validators := make([]StakeValidatorOutput, len(kvs)) for i, kv := range kvs { var validator stake.Validator + var bech32Validator StakeValidatorOutput err = cdc.UnmarshalBinary(kv.Value, &validator) + if err == nil { + bech32Validator, err = bech32StakeValidatorOutput(validator) + } if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) return } - validators[i] = validator + validators[i] = bech32Validator } output, err := cdc.MarshalJSON(validators) diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index eaf206bf6b..33fe73c699 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -3,6 +3,7 @@ package rest import ( "bytes" "encoding/json" + "fmt" "io/ioutil" "net/http" @@ -23,13 +24,24 @@ func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, k ).Methods("POST") } +type msgDelegateInput struct { + DelegatorAddr string `json:"delegator_addr"` // in bech32 + ValidatorAddr string `json:"validator_addr"` // in bech32 + Bond sdk.Coin `json:"bond"` +} +type msgUnbondInput struct { + DelegatorAddr string `json:"delegator_addr"` // in bech32 + ValidatorAddr string `json:"validator_addr"` // in bech32 + Shares string `json:"shares"` +} + type editDelegationsBody struct { - 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"` + LocalAccountName string `json:"name"` + Password string `json:"password"` + ChainID string `json:"chain_id"` + Sequence int64 `json:"sequence"` + Delegate []msgDelegateInput `json:"delegate"` + Unbond []msgUnbondInput `json:"unbond"` } func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc { @@ -59,21 +71,53 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte messages := make([]sdk.Msg, len(m.Delegate)+len(m.Unbond)) i := 0 for _, msg := range m.Delegate { - if !bytes.Equal(info.Address(), msg.DelegatorAddr) { + delegatorAddr, err := sdk.GetAccAddressBech32(msg.DelegatorAddr) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))) + return + } + validatorAddr, err := sdk.GetValAddressBech32(msg.ValidatorAddr) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) + return + } + if !bytes.Equal(info.Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return } - messages[i] = msg + messages[i] = stake.MsgDelegate{ + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + Bond: msg.Bond, + } i++ } for _, msg := range m.Unbond { - if !bytes.Equal(info.Address(), msg.DelegatorAddr) { + delegatorAddr, err := sdk.GetAccAddressBech32(msg.DelegatorAddr) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))) + return + } + validatorAddr, err := sdk.GetValAddressBech32(msg.ValidatorAddr) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))) + return + } + if !bytes.Equal(info.Address(), delegatorAddr) { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Must use own delegator address")) return } - messages[i] = msg + messages[i] = stake.MsgUnbond{ + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + Shares: msg.Shares, + } i++ } From 3fbee11ccc5a504c925cdb42f7c6a1edd1be6d92 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 6 Jun 2018 18:38:13 +0200 Subject: [PATCH 128/128] Merge PR #1142: Export validators to genesis * Validator export skeleton * Update export command, add tests, update CHANGELOG * Rename exportAppState to exportAppStateAndTMValidators --- CHANGELOG.md | 6 +++++ cmd/gaia/app/app.go | 10 +++++-- cmd/gaia/app/app_test.go | 36 +++++++++++++++++++++++++ cmd/gaia/cmd/gaiad/main.go | 7 ++--- examples/basecoin/app/app.go | 10 +++++-- examples/basecoin/cmd/basecoind/main.go | 7 ++--- examples/democoin/app/app.go | 9 +++++-- examples/democoin/cmd/democoind/main.go | 7 ++--- server/constructors.go | 11 ++++---- server/export.go | 3 ++- types/stake.go | 1 + x/stake/genesis.go | 19 ++++++++++++- x/stake/validator.go | 1 + 13 files changed, 105 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 731f3c14a3..6d65416915 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ BREAKING CHANGES +FEATURES + +IMPROVEMENTS +* export command now writes current validator set for Tendermint + +FIXES * [lcd] Switch to bech32 for addresses on all human readable inputs and outputs ## 0.18.0 diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 8f8ed281ed..f06ed2be30 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -5,6 +5,7 @@ import ( "os" abci "github.com/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -153,7 +154,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci } // export the state of gaia for a genesis file -func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) { +func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) { ctx := app.NewContext(true, abci.Header{}) // iterate to get the accounts @@ -169,5 +170,10 @@ func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) { Accounts: accounts, StakeData: stake.WriteGenesis(ctx, app.stakeKeeper), } - return wire.MarshalJSONIndent(app.cdc, genState) + appState, err = wire.MarshalJSONIndent(app.cdc, genState) + if err != nil { + return nil, nil, err + } + validators = stake.WriteValidators(ctx, app.stakeKeeper) + return appState, validators, nil } diff --git a/cmd/gaia/app/app_test.go b/cmd/gaia/app/app_test.go index b6fffac32f..0fe1cfe5b9 100644 --- a/cmd/gaia/app/app_test.go +++ b/cmd/gaia/app/app_test.go @@ -430,6 +430,42 @@ func TestStakeMsgs(t *testing.T) { require.False(t, found) } +func TestExportValidators(t *testing.T) { + gapp := newGaiaApp() + + genCoins, err := sdk.ParseCoins("42steak") + require.Nil(t, err) + bondCoin, err := sdk.ParseCoin("10steak") + require.Nil(t, err) + + acc1 := &auth.BaseAccount{ + Address: addr1, + Coins: genCoins, + } + acc2 := &auth.BaseAccount{ + Address: addr2, + Coins: genCoins, + } + + err = setGenesis(gapp, acc1, acc2) + require.Nil(t, err) + + // Create Validator + description := stake.NewDescription("foo_moniker", "", "", "") + createValidatorMsg := stake.NewMsgCreateValidator( + addr1, priv1.PubKey(), bondCoin, description, + ) + SignCheckDeliver(t, gapp, createValidatorMsg, []int64{0}, true, priv1) + gapp.Commit() + + // Export validator set + _, validators, err := gapp.ExportAppStateAndValidators() + require.Nil(t, err) + require.Equal(t, 1, len(validators)) // 1 validator + require.Equal(t, priv1.PubKey(), validators[0].PubKey) + require.Equal(t, int64(10), validators[0].Power) +} + //____________________________________________________________________________________ func CheckBalance(t *testing.T, gapp *GaiaApp, addr sdk.Address, balExpected string) { diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 30cb276ee1..5d0eb90300 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -6,6 +6,7 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -26,7 +27,7 @@ func main() { server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(), server.ConstructAppCreator(newApp, "gaia"), - server.ConstructAppExporter(exportAppState, "gaia")) + server.ConstructAppExporter(exportAppStateAndTMValidators, "gaia")) // prepare and add flags executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome) @@ -37,7 +38,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application { return app.NewGaiaApp(logger, db) } -func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) { +func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) { gapp := app.NewGaiaApp(logger, db) - return gapp.ExportAppStateJSON() + return gapp.ExportAppStateAndValidators() } diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index 1718b8be23..fdb0638b69 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -4,6 +4,7 @@ import ( "encoding/json" abci "github.com/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -155,7 +156,7 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) } // Custom logic for state export -func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) { +func (app *BasecoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) { ctx := app.NewContext(true, abci.Header{}) // iterate to get the accounts @@ -173,5 +174,10 @@ func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro genState := types.GenesisState{ Accounts: accounts, } - return wire.MarshalJSONIndent(app.cdc, genState) + appState, err = wire.MarshalJSONIndent(app.cdc, genState) + if err != nil { + return nil, nil, err + } + validators = stake.WriteValidators(ctx, app.stakeKeeper) + return appState, validators, err } diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 4e6a30a086..4a6498e1be 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -27,7 +28,7 @@ func main() { server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit, server.ConstructAppCreator(newApp, "basecoin"), - server.ConstructAppExporter(exportAppState, "basecoin")) + server.ConstructAppExporter(exportAppStateAndTMValidators, "basecoin")) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.basecoind") @@ -39,7 +40,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application { return app.NewBasecoinApp(logger, db) } -func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) { +func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) { bapp := app.NewBasecoinApp(logger, db) - return bapp.ExportAppStateJSON() + return bapp.ExportAppStateAndValidators() } diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 2075a64da0..dc7c3c9d8e 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -4,6 +4,7 @@ import ( "encoding/json" abci "github.com/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -154,7 +155,7 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep } // Custom logic for state export -func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) { +func (app *DemocoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) { ctx := app.NewContext(true, abci.Header{}) // iterate to get the accounts @@ -174,5 +175,9 @@ func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro POWGenesis: pow.WriteGenesis(ctx, app.powKeeper), CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper), } - return wire.MarshalJSONIndent(app.cdc, genState) + appState, err = wire.MarshalJSONIndent(app.cdc, genState) + if err != nil { + return nil, nil, err + } + return appState, validators, nil } diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 3283da58ae..76d29075e9 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -46,9 +47,9 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application { return app.NewDemocoinApp(logger, db) } -func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) { +func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) { dapp := app.NewDemocoinApp(logger, db) - return dapp.ExportAppStateJSON() + return dapp.ExportAppStateAndValidators() } func main() { @@ -63,7 +64,7 @@ func main() { server.AddCommands(ctx, cdc, rootCmd, CoolAppInit, server.ConstructAppCreator(newApp, "democoin"), - server.ConstructAppExporter(exportAppState, "democoin")) + server.ConstructAppExporter(exportAppStateAndTMValidators, "democoin")) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.democoind") diff --git a/server/constructors.go b/server/constructors.go index 3d6950062b..c91c67a18d 100644 --- a/server/constructors.go +++ b/server/constructors.go @@ -5,6 +5,7 @@ import ( "path/filepath" abci "github.com/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" ) @@ -13,8 +14,8 @@ import ( // and other flags (?) to start type AppCreator func(string, log.Logger) (abci.Application, error) -// AppExporter dumps all app state to JSON-serializable structure -type AppExporter func(home string, log log.Logger) (json.RawMessage, error) +// AppExporter dumps all app state to JSON-serializable structure and returns the current validator set +type AppExporter func(home string, log log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error) // ConstructAppCreator returns an application generation function func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name string) AppCreator { @@ -30,12 +31,12 @@ func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name s } // ConstructAppExporter returns an application export function -func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, error), name string) AppExporter { - return func(rootDir string, logger log.Logger) (json.RawMessage, error) { +func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error), name string) AppExporter { + return func(rootDir string, logger log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error) { dataDir := filepath.Join(rootDir, "data") db, err := dbm.NewGoLevelDB(name, dataDir) if err != nil { - return nil, err + return nil, nil, err } return appFn(logger, db) } diff --git a/server/export.go b/server/export.go index dad2df9cc9..794235f629 100644 --- a/server/export.go +++ b/server/export.go @@ -18,7 +18,7 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co Short: "Export state to JSON", RunE: func(cmd *cobra.Command, args []string) error { home := viper.GetString("home") - appState, err := appExporter(home, ctx.Logger) + appState, validators, err := appExporter(home, ctx.Logger) if err != nil { return errors.Errorf("Error exporting state: %v\n", err) } @@ -27,6 +27,7 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co return err } doc.AppStateJSON = appState + doc.Validators = validators encoded, err := wire.MarshalJSONIndent(cdc, doc) if err != nil { return err diff --git a/types/stake.go b/types/stake.go index 6a620db762..7484295cc5 100644 --- a/types/stake.go +++ b/types/stake.go @@ -32,6 +32,7 @@ func BondStatusToString(b BondStatus) string { // validator for a delegated proof of stake system type Validator interface { + GetMoniker() string // moniker of the validator GetStatus() BondStatus // status of the validator GetOwner() Address // owner address to receive/return validators coins GetPubKey() crypto.PubKey // validation pubkey diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 0a7c528bf6..43ea61d8b7 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -1,6 +1,10 @@ package stake -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + tmtypes "github.com/tendermint/tendermint/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) // GenesisState - all staking state that must be provided at genesis type GenesisState struct { @@ -63,3 +67,16 @@ func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState { bonds, } } + +// WriteValidators - output current validator set +func WriteValidators(ctx sdk.Context, k Keeper) (vals []tmtypes.GenesisValidator) { + k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { + vals = append(vals, tmtypes.GenesisValidator{ + PubKey: validator.GetPubKey(), + Power: validator.GetPower().Evaluate(), + Name: validator.GetMoniker(), + }) + return false + }) + return +} diff --git a/x/stake/validator.go b/x/stake/validator.go index a0b484d712..3b135c12bf 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -251,6 +251,7 @@ func (v Validator) DelegatorShareExRate(pool Pool) sdk.Rat { var _ sdk.Validator = Validator{} // nolint - for sdk.Validator +func (v Validator) GetMoniker() string { return v.Description.Moniker } func (v Validator) GetStatus() sdk.BondStatus { return v.Status() } func (v Validator) GetOwner() sdk.Address { return v.Owner } func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey }