From 4ddfef6204065cba8f84fc481bd982d2a026f6d9 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Tue, 28 Aug 2018 01:28:27 -0700 Subject: [PATCH 01/28] Add documentation regarding environment variables Closes #1973. --- docs/validators/security.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/validators/security.md b/docs/validators/security.md index d3e3d6988d..5ccf988148 100644 --- a/docs/validators/security.md +++ b/docs/validators/security.md @@ -39,3 +39,14 @@ Sentry Nodes should edit their config.toml: # Comma separated list of peer IDs to keep private (will not be gossiped to other peers) private_peer_ids = "ipaddress of validator nodes" ``` + +## Environment Variables + +By default, uppercase environment variables with the following prefixes will replace lowercase command-line flags: + +- `GA` (for Gaia flags) +- `TM` (for Tendermint flags) +- `BC` (for democli or basecli flags) + +For example, the environment variable `GA_CHAIN_ID` will map to the command line flag `--chain-id`. Note that while explicit command-line flags will take precedence over environment variables, environment variables will take precedence over any of your configuration files. For this reason, it's imperative that you lock down your environment such that any critical parameters are defined as flags on the CLI or prevent modification of any environment variables. + \ No newline at end of file From 703c643fc08487b954ccd750d63d2cd405be61a4 Mon Sep 17 00:00:00 2001 From: HaoyangLiu Date: Thu, 30 Aug 2018 12:50:41 +0800 Subject: [PATCH 02/28] IRISHUB-238: Add multiply store proof build and verification --- client/context/client_manager.go | 46 ++++++++++ client/context/client_manager_test.go | 16 ++++ client/context/context.go | 15 ++++ client/context/query.go | 79 ++++++++++++++++++ client/lcd/root.go | 14 ++++ store/multistoreproof.go | 116 ++++++++++++++++++++++++++ store/multistoreproof_test.go | 96 +++++++++++++++++++++ store/rootmultistore.go | 19 +++++ 8 files changed, 401 insertions(+) create mode 100644 client/context/client_manager.go create mode 100644 client/context/client_manager_test.go create mode 100644 store/multistoreproof.go create mode 100644 store/multistoreproof_test.go diff --git a/client/context/client_manager.go b/client/context/client_manager.go new file mode 100644 index 0000000000..8fffb9d651 --- /dev/null +++ b/client/context/client_manager.go @@ -0,0 +1,46 @@ +package context + +import ( + "github.com/pkg/errors" + rpcclient "github.com/tendermint/tendermint/rpc/client" + "strings" + "sync" +) + +// ClientManager is a manager of a set of rpc clients to full nodes. +// This manager can do load balancing upon these rpc clients. +type ClientManager struct { + clients []rpcclient.Client + currentIndex int + mutex sync.Mutex +} + +// NewClientManager create a new ClientManager +func NewClientManager(nodeURIs string) (*ClientManager, error) { + if nodeURIs != "" { + nodeURLArray := strings.Split(nodeURIs, ",") + var clients []rpcclient.Client + for _, url := range nodeURLArray { + client := rpcclient.NewHTTP(url, "/websocket") + clients = append(clients, client) + } + mgr := &ClientManager{ + currentIndex: 0, + clients: clients, + } + return mgr, nil + } + return nil, errors.New("missing node URIs") +} + +func (mgr *ClientManager) getClient() rpcclient.Client { + mgr.mutex.Lock() + defer mgr.mutex.Unlock() + + client := mgr.clients[mgr.currentIndex] + mgr.currentIndex++ + if mgr.currentIndex >= len(mgr.clients) { + mgr.currentIndex = 0 + } + return client +} diff --git a/client/context/client_manager_test.go b/client/context/client_manager_test.go new file mode 100644 index 0000000000..c060e11cea --- /dev/null +++ b/client/context/client_manager_test.go @@ -0,0 +1,16 @@ +package context + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestClientManager(t *testing.T) { + nodeURIs := "10.10.10.10:26657,20.20.20.20:26657,30.30.30.30:26657" + clientMgr, err := NewClientManager(nodeURIs) + assert.Empty(t, err) + endpoint := clientMgr.getClient() + assert.NotEqual(t, endpoint, clientMgr.getClient()) + clientMgr.getClient() + assert.Equal(t, endpoint, clientMgr.getClient()) +} \ No newline at end of file diff --git a/client/context/context.go b/client/context/context.go index 743c923552..b57e336657 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/viper" rpcclient "github.com/tendermint/tendermint/rpc/client" + tendermintLite "github.com/tendermint/tendermint/lite" ) const ctxAccStoreName = "acc" @@ -32,6 +33,8 @@ type CLIContext struct { Async bool JSON bool PrintResponse bool + Certifier tendermintLite.Certifier + ClientManager *ClientManager } // NewCLIContext returns a new initialized CLIContext with parameters from the @@ -117,3 +120,15 @@ func (ctx CLIContext) WithUseLedger(useLedger bool) CLIContext { ctx.UseLedger = useLedger return ctx } + +// WithCertifier - return a copy of the context with an updated Certifier +func (ctx CLIContext) WithCertifier(certifier tendermintLite.Certifier) CLIContext { + ctx.Certifier = certifier + return ctx +} + +// WithClientManager - return a copy of the context with an updated ClientManager +func (ctx CLIContext) WithClientManager(clientManager *ClientManager) CLIContext { + ctx.ClientManager = clientManager + return ctx +} diff --git a/client/context/query.go b/client/context/query.go index e526c0abbc..72defb0d4a 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -13,6 +13,11 @@ import ( cmn "github.com/tendermint/tendermint/libs/common" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" + "github.com/cosmos/cosmos-sdk/store" + "github.com/cosmos/cosmos-sdk/wire" + "strings" + tendermintLiteProxy "github.com/tendermint/tendermint/lite/proxy" + abci "github.com/tendermint/tendermint/abci/types" ) // GetNode returns an RPC client. If the context's client is not defined, an @@ -304,12 +309,86 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log) } + // Data from trusted node or subspace query doesn't need verification + if ctx.TrustNode || !isQueryStoreWithProof(path) { + return resp.Value, nil + } + + err = ctx.verifyProof(path, resp) + if err != nil { + return nil, err + } + return resp.Value, nil } +// verifyProof perform response proof verification +func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error { + + // TODO: Later we consider to return error for missing valid certifier to verify data from untrusted node + if ctx.Certifier == nil { + if ctx.Logger != nil { + io.WriteString(ctx.Logger, fmt.Sprintf("Missing valid certifier to verify data from untrusted node\n")) + } + return nil + } + + node, err := ctx.GetNode() + if err != nil { + return err + } + + // TODO: need improvement + // If the the node http client connect to a full node which can't produce or receive new blocks, + // then here the code will wait for a while and return error if time is out. + // AppHash for height H is in header H+1 + commit, err := tendermintLiteProxy.GetCertifiedCommit(resp.Height+1, node, ctx.Certifier) + if err != nil { + return err + } + + var multiStoreProof store.MultiStoreProof + cdc := wire.NewCodec() + err = cdc.UnmarshalBinary(resp.Proof, &multiStoreProof) + if err != nil { + return errors.Wrap(err, "failed to unmarshalBinary rangeProof") + } + + // Validate the substore commit hash against trusted appHash + substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(multiStoreProof.StoreName, + multiStoreProof.CommitIDList, commit.Header.AppHash) + if err != nil { + return errors.Wrap(err, "failed in verifying the proof against appHash") + } + err = store.VerifyRangeProof(resp.Key, resp.Value, substoreCommitHash, &multiStoreProof.RangeProof) + if err != nil { + return errors.Wrap(err, "failed in the range proof verification") + } + return nil +} + // queryStore performs a query from a Tendermint node with the provided a store // name and path. func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, error) { path := fmt.Sprintf("/store/%s/%s", storeName, endPath) return ctx.query(path, key) } + +// isQueryStoreWithProof expects a format like /// +// queryType can be app or store +// if subpath equals to "/store" or "/key", then return true +func isQueryStoreWithProof(path string) (bool) { + if !strings.HasPrefix(path, "/") { + return false + } + paths := strings.SplitN(path[1:], "/", 3) + if len(paths) != 3 { + return false + } + // Currently, only when query subpath is "/store" or "/key", will proof be included in response. + // If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go + if paths[2] == "store" || paths[2] == "key" { + return true + } + return false +} diff --git a/client/lcd/root.go b/client/lcd/root.go index bfa62f1cf0..71c9a51144 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -22,6 +22,9 @@ import ( cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/libs/log" tmserver "github.com/tendermint/tendermint/rpc/lib/server" + tendermintLiteProxy "github.com/tendermint/tendermint/lite/proxy" + "github.com/tendermint/tendermint/libs/cli" + tendermintLite "github.com/tendermint/tendermint/lite" ) // ServeCommand will generate a long-running rest server @@ -80,6 +83,17 @@ func createHandler(cdc *wire.Codec) http.Handler { cliCtx := context.NewCLIContext().WithCodec(cdc).WithLogger(os.Stdout) + chainID := viper.GetString(client.FlagChainID) + home := viper.GetString(cli.HomeFlag) + nodeURI := viper.GetString(client.FlagNode) + var certifier tendermintLite.Certifier + if chainID != "" && home != "" && nodeURI != ""{ + certifier, err = tendermintLiteProxy.GetCertifier(chainID, home, nodeURI) + if err != nil { + panic(err) + } + cliCtx = cliCtx.WithCertifier(certifier) + } // TODO: make more functional? aka r = keys.RegisterRoutes(r) r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET") r.HandleFunc("/node_version", NodeVersionRequestHandler(cliCtx)).Methods("GET") diff --git a/store/multistoreproof.go b/store/multistoreproof.go new file mode 100644 index 0000000000..e98a198e93 --- /dev/null +++ b/store/multistoreproof.go @@ -0,0 +1,116 @@ +package store + +import ( + "bytes" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/pkg/errors" + "github.com/tendermint/iavl" + cmn "github.com/tendermint/tendermint/libs/common" +) + +// commitID of substores, such as acc store, gov store +type SubstoreCommitID struct { + Name string `json:"name"` + Version int64 `json:"version"` + CommitHash cmn.HexBytes `json:"commit_hash"` +} + +// proof of store which have multi substores +type MultiStoreProof struct { + CommitIDList []SubstoreCommitID `json:"commit_id_list"` + StoreName string `json:"store_name"` + RangeProof iavl.RangeProof `json:"range_proof"` +} + +// build MultiStoreProof based on iavl proof and storeInfos +func BuildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []storeInfo) ([]byte, error) { + var rangeProof iavl.RangeProof + err := cdc.UnmarshalBinary(iavlProof, &rangeProof) + if err != nil { + return nil, err + } + + var multiStoreProof MultiStoreProof + for _, storeInfo := range storeInfos { + + commitID := SubstoreCommitID{ + Name: storeInfo.Name, + Version: storeInfo.Core.CommitID.Version, + CommitHash: storeInfo.Core.CommitID.Hash, + } + multiStoreProof.CommitIDList = append(multiStoreProof.CommitIDList, commitID) + } + multiStoreProof.StoreName = storeName + multiStoreProof.RangeProof = rangeProof + + proof, err := cdc.MarshalBinary(multiStoreProof) + if err != nil { + return nil, err + } + + return proof, nil +} + +// verify multiStoreCommitInfo against appHash +func VerifyMultiStoreCommitInfo(storeName string, multiStoreCommitInfo []SubstoreCommitID, appHash []byte) ([]byte, error) { + var substoreCommitHash []byte + var storeInfos []storeInfo + var height int64 + for _, multiStoreCommitID := range multiStoreCommitInfo { + + if multiStoreCommitID.Name == storeName { + substoreCommitHash = multiStoreCommitID.CommitHash + height = multiStoreCommitID.Version + } + storeInfo := storeInfo{ + Name: multiStoreCommitID.Name, + Core: storeCore{ + CommitID: sdk.CommitID{ + Version: multiStoreCommitID.Version, + Hash: multiStoreCommitID.CommitHash, + }, + }, + } + + storeInfos = append(storeInfos, storeInfo) + } + if len(substoreCommitHash) == 0 { + return nil, cmn.NewError("failed to get substore root commit hash by store name") + } + + ci := commitInfo{ + Version: height, + StoreInfos: storeInfos, + } + + if !bytes.Equal(appHash, ci.Hash()) { + return nil, cmn.NewError("the merkle root of multiStoreCommitInfo doesn't equal to appHash") + } + return substoreCommitHash, nil +} + +// verify iavl proof +func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof *iavl.RangeProof) error { + + // Validate the proof to ensure data integrity. + err := rangeProof.Verify(substoreCommitHash) + if err != nil { + return errors.Wrap(err, "proof root hash doesn't equal to substore commit root hash") + } + + if len(value) != 0 { + // Validate existence proof + err = rangeProof.VerifyItem(key, value) + if err != nil { + return errors.Wrap(err, "failed in existence verification") + } + } else { + // Validate absence proof + err = rangeProof.VerifyAbsence(key) + if err != nil { + return errors.Wrap(err, "failed in absence verification") + } + } + + return nil +} \ No newline at end of file diff --git a/store/multistoreproof_test.go b/store/multistoreproof_test.go new file mode 100644 index 0000000000..b1667c7265 --- /dev/null +++ b/store/multistoreproof_test.go @@ -0,0 +1,96 @@ +package store + +import ( + "encoding/hex" + "github.com/stretchr/testify/assert" + "github.com/tendermint/iavl" + cmn "github.com/tendermint/tendermint/libs/common" + "testing" +) + +func TestVerifyMultiStoreCommitInfo(t *testing.T) { + appHash, _ := hex.DecodeString("ebf3c1fb724d3458023c8fefef7b33add2fc1e84") + + substoreRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828") + storeName := "acc" + + var multiStoreCommitInfo []SubstoreCommitID + + gocRootHash, _ := hex.DecodeString("62c171bb022e47d1f745608ff749e676dbd25f78") + multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ + Name: "gov", + Version: 689, + CommitHash: gocRootHash, + }) + + multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ + Name: "main", + Version: 689, + CommitHash: nil, + }) + + accRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828") + multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ + Name: "acc", + Version: 689, + CommitHash: accRootHash, + }) + + multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ + Name: "ibc", + Version: 689, + CommitHash: nil, + }) + + stakeRootHash, _ := hex.DecodeString("987d1d27b8771d93aa3691262f661d2c85af7ca4") + multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ + Name: "stake", + Version: 689, + CommitHash: stakeRootHash, + }) + + slashingRootHash, _ := hex.DecodeString("388ee6e5b11f367069beb1eefd553491afe9d73e") + multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ + Name: "slashing", + Version: 689, + CommitHash: slashingRootHash, + }) + + commitHash, err := VerifyMultiStoreCommitInfo(storeName, multiStoreCommitInfo, appHash) + assert.Nil(t, err) + assert.Equal(t, commitHash, substoreRootHash) + + appHash, _ = hex.DecodeString("29de216bf5e2531c688de36caaf024cd3bb09ee3") + + _, err = VerifyMultiStoreCommitInfo(storeName, multiStoreCommitInfo, appHash) + assert.Error(t, err, "appHash doesn't match to the merkle root of multiStoreCommitInfo") +} + +func TestVerifyRangeProof(t *testing.T) { + tree := iavl.NewTree(nil, 0) + + rand := cmn.NewRand() + rand.Seed(0) // for determinism + for _, ikey := range []byte{0x11, 0x32, 0x50, 0x72, 0x99} { + key := []byte{ikey} + tree.Set(key, []byte(rand.Str(8))) + } + + root := tree.Hash() + + key := []byte{0x32} + val, proof, err := tree.GetWithProof(key) + assert.Nil(t, err) + assert.NotEmpty(t, val) + assert.NotEmpty(t, proof) + err = VerifyRangeProof(key, val, root, proof) + assert.Nil(t, err) + + key = []byte{0x40} + val, proof, err = tree.GetWithProof(key) + assert.Nil(t, err) + assert.Empty(t, val) + assert.NotEmpty(t, proof) + err = VerifyRangeProof(key, val, root, proof) + assert.Nil(t, err) +} \ No newline at end of file diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 04f8e44e69..2a9a9373a4 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -291,6 +291,25 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery { // trim the path and make the query req.Path = subpath res := queryable.Query(req) + + + // Currently, only when query subpath is "/store" or "/key", will proof be included in response. + // If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go + if !req.Prove || subpath != "/store" && subpath != "/key" { + return res + } + + //Load commit info from db + commitInfo, errMsg := getCommitInfo(rs.db,res.Height) + if errMsg != nil { + return sdk.ErrInternal(errMsg.Error()).QueryResult() + } + + res.Proof, errMsg = BuildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos) + if errMsg != nil { + return sdk.ErrInternal(errMsg.Error()).QueryResult() + } + return res } From 5473771105b5db36c093a6a6de649240cd40e3bb Mon Sep 17 00:00:00 2001 From: HaoyangLiu Date: Thu, 30 Aug 2018 15:08:10 +0800 Subject: [PATCH 03/28] IRISHUB-238 :add trust option for rest-server command --- client/lcd/root.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client/lcd/root.go b/client/lcd/root.go index 71c9a51144..75cf3632ea 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -69,6 +69,7 @@ func ServeCommand(cdc *wire.Codec) *cobra.Command { cmd.Flags().String(client.FlagChainID, "", "The chain ID to connect to") cmd.Flags().String(client.FlagNode, "tcp://localhost:26657", "Address of the node to connect to") cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections") + cmd.Flags().Bool(client.FlagTrustNode, false, "Whether trust connected full node") return cmd } From b878edc388788542b55398c1923b742e63c4ecc2 Mon Sep 17 00:00:00 2001 From: HaoyangLiu Date: Thu, 30 Aug 2018 15:52:17 +0800 Subject: [PATCH 04/28] IRISHUB-238: fix failures in test_lint and test_cover --- client/context/client_manager_test.go | 2 +- client/context/context.go | 2 +- client/context/query.go | 20 ++++++++++---------- client/lcd/test_helpers.go | 2 ++ store/multistoreproof.go | 2 +- store/multistoreproof_test.go | 2 +- store/rootmultistore.go | 3 +-- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/client/context/client_manager_test.go b/client/context/client_manager_test.go index c060e11cea..1960f74ced 100644 --- a/client/context/client_manager_test.go +++ b/client/context/client_manager_test.go @@ -13,4 +13,4 @@ func TestClientManager(t *testing.T) { assert.NotEqual(t, endpoint, clientMgr.getClient()) clientMgr.getClient() assert.Equal(t, endpoint, clientMgr.getClient()) -} \ No newline at end of file +} diff --git a/client/context/context.go b/client/context/context.go index b57e336657..28506756cf 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -9,8 +9,8 @@ import ( "github.com/spf13/viper" - rpcclient "github.com/tendermint/tendermint/rpc/client" tendermintLite "github.com/tendermint/tendermint/lite" + rpcclient "github.com/tendermint/tendermint/rpc/client" ) const ctxAccStoreName = "acc" diff --git a/client/context/query.go b/client/context/query.go index 72defb0d4a..aac0c90306 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -10,14 +10,14 @@ import ( "github.com/pkg/errors" - cmn "github.com/tendermint/tendermint/libs/common" - rpcclient "github.com/tendermint/tendermint/rpc/client" - ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/wire" - "strings" - tendermintLiteProxy "github.com/tendermint/tendermint/lite/proxy" abci "github.com/tendermint/tendermint/abci/types" + cmn "github.com/tendermint/tendermint/libs/common" + tendermintLiteProxy "github.com/tendermint/tendermint/lite/proxy" + rpcclient "github.com/tendermint/tendermint/rpc/client" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + "strings" ) // GetNode returns an RPC client. If the context's client is not defined, an @@ -351,18 +351,18 @@ func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error { cdc := wire.NewCodec() err = cdc.UnmarshalBinary(resp.Proof, &multiStoreProof) if err != nil { - return errors.Wrap(err, "failed to unmarshalBinary rangeProof") + return errors.Wrap(err, "failed to unmarshalBinary rangeProof") } // Validate the substore commit hash against trusted appHash - substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(multiStoreProof.StoreName, + substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(multiStoreProof.StoreName, multiStoreProof.CommitIDList, commit.Header.AppHash) if err != nil { - return errors.Wrap(err, "failed in verifying the proof against appHash") + return errors.Wrap(err, "failed in verifying the proof against appHash") } err = store.VerifyRangeProof(resp.Key, resp.Value, substoreCommitHash, &multiStoreProof.RangeProof) if err != nil { - return errors.Wrap(err, "failed in the range proof verification") + return errors.Wrap(err, "failed in the range proof verification") } return nil } @@ -377,7 +377,7 @@ func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([ // isQueryStoreWithProof expects a format like /// // queryType can be app or store // if subpath equals to "/store" or "/key", then return true -func isQueryStoreWithProof(path string) (bool) { +func isQueryStoreWithProof(path string) bool { if !strings.HasPrefix(path, "/") { return false } diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 818eae1e86..8a344976a1 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -37,6 +37,7 @@ import ( "github.com/tendermint/tendermint/proxy" tmrpc "github.com/tendermint/tendermint/rpc/lib/server" tmtypes "github.com/tendermint/tendermint/types" + "time" ) // makePathname creates a unique pathname for each test. It will panic if it @@ -190,6 +191,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress node, err := startTM(config, logger, genDoc, privVal, app) require.NoError(t, err) + time.Sleep(3 * time.Second) lcd, err := startLCD(logger, listenAddr, cdc) require.NoError(t, err) diff --git a/store/multistoreproof.go b/store/multistoreproof.go index e98a198e93..5ca214bc7d 100644 --- a/store/multistoreproof.go +++ b/store/multistoreproof.go @@ -113,4 +113,4 @@ func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof * } return nil -} \ No newline at end of file +} diff --git a/store/multistoreproof_test.go b/store/multistoreproof_test.go index b1667c7265..1538915677 100644 --- a/store/multistoreproof_test.go +++ b/store/multistoreproof_test.go @@ -93,4 +93,4 @@ func TestVerifyRangeProof(t *testing.T) { assert.NotEmpty(t, proof) err = VerifyRangeProof(key, val, root, proof) assert.Nil(t, err) -} \ No newline at end of file +} diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 2a9a9373a4..c5ce52b0ba 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -292,7 +292,6 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery { req.Path = subpath res := queryable.Query(req) - // Currently, only when query subpath is "/store" or "/key", will proof be included in response. // If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go if !req.Prove || subpath != "/store" && subpath != "/key" { @@ -300,7 +299,7 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery { } //Load commit info from db - commitInfo, errMsg := getCommitInfo(rs.db,res.Height) + commitInfo, errMsg := getCommitInfo(rs.db, res.Height) if errMsg != nil { return sdk.ErrInternal(errMsg.Error()).QueryResult() } From 3f83aca5992ea483ad42dc4431dfdbf6af4540c7 Mon Sep 17 00:00:00 2001 From: HaoyangLiu Date: Thu, 30 Aug 2018 16:24:56 +0800 Subject: [PATCH 05/28] IRISHUB-238: fix test_lint failures in client/lcd/root.go and server/ --- client/lcd/root.go | 8 ++++---- server/export_test.go | 16 ++++++++-------- server/mock/app.go | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client/lcd/root.go b/client/lcd/root.go index 75cf3632ea..f05fb88081 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -19,12 +19,12 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/tendermint/tendermint/libs/cli" cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/libs/log" - tmserver "github.com/tendermint/tendermint/rpc/lib/server" - tendermintLiteProxy "github.com/tendermint/tendermint/lite/proxy" - "github.com/tendermint/tendermint/libs/cli" tendermintLite "github.com/tendermint/tendermint/lite" + tendermintLiteProxy "github.com/tendermint/tendermint/lite/proxy" + tmserver "github.com/tendermint/tendermint/rpc/lib/server" ) // ServeCommand will generate a long-running rest server @@ -88,7 +88,7 @@ func createHandler(cdc *wire.Codec) http.Handler { home := viper.GetString(cli.HomeFlag) nodeURI := viper.GetString(client.FlagNode) var certifier tendermintLite.Certifier - if chainID != "" && home != "" && nodeURI != ""{ + if chainID != "" && home != "" && nodeURI != "" { certifier, err = tendermintLiteProxy.GetCertifier(chainID, home, nodeURI) if err != nil { panic(err) diff --git a/server/export_test.go b/server/export_test.go index 358f72cf60..488c55bbf6 100644 --- a/server/export_test.go +++ b/server/export_test.go @@ -1,16 +1,16 @@ package server import ( - "testing" - "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/wire" - "github.com/tendermint/tendermint/libs/log" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - "os" "bytes" + "github.com/cosmos/cosmos-sdk/server/mock" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/stretchr/testify/require" + tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" + "github.com/tendermint/tendermint/libs/log" "io" - "github.com/cosmos/cosmos-sdk/server/mock" - ) + "os" + "testing" +) func TestEmptyState(t *testing.T) { defer setupViper(t)() diff --git a/server/mock/app.go b/server/mock/app.go index eb2dfc3cc3..3c6ad3ec27 100644 --- a/server/mock/app.go +++ b/server/mock/app.go @@ -129,7 +129,7 @@ func AppGenStateEmpty(_ *wire.Codec, _ []json.RawMessage) (appState json.RawMess // Return a validator, not much else func AppGenTx(_ *wire.Codec, pk crypto.PubKey, genTxConfig gc.GenTx) ( - appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { + appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { validator = tmtypes.GenesisValidator{ PubKey: pk, From 5e85a5cdcdba8d9d7287e3950ae439d6b9ffd515 Mon Sep 17 00:00:00 2001 From: HaoyangLiu Date: Thu, 30 Aug 2018 17:14:10 +0800 Subject: [PATCH 06/28] IRISHUB-238: delete client manager --- client/context/client_manager.go | 46 --------------------------- client/context/client_manager_test.go | 16 ---------- client/context/context.go | 7 ---- 3 files changed, 69 deletions(-) delete mode 100644 client/context/client_manager.go delete mode 100644 client/context/client_manager_test.go diff --git a/client/context/client_manager.go b/client/context/client_manager.go deleted file mode 100644 index 8fffb9d651..0000000000 --- a/client/context/client_manager.go +++ /dev/null @@ -1,46 +0,0 @@ -package context - -import ( - "github.com/pkg/errors" - rpcclient "github.com/tendermint/tendermint/rpc/client" - "strings" - "sync" -) - -// ClientManager is a manager of a set of rpc clients to full nodes. -// This manager can do load balancing upon these rpc clients. -type ClientManager struct { - clients []rpcclient.Client - currentIndex int - mutex sync.Mutex -} - -// NewClientManager create a new ClientManager -func NewClientManager(nodeURIs string) (*ClientManager, error) { - if nodeURIs != "" { - nodeURLArray := strings.Split(nodeURIs, ",") - var clients []rpcclient.Client - for _, url := range nodeURLArray { - client := rpcclient.NewHTTP(url, "/websocket") - clients = append(clients, client) - } - mgr := &ClientManager{ - currentIndex: 0, - clients: clients, - } - return mgr, nil - } - return nil, errors.New("missing node URIs") -} - -func (mgr *ClientManager) getClient() rpcclient.Client { - mgr.mutex.Lock() - defer mgr.mutex.Unlock() - - client := mgr.clients[mgr.currentIndex] - mgr.currentIndex++ - if mgr.currentIndex >= len(mgr.clients) { - mgr.currentIndex = 0 - } - return client -} diff --git a/client/context/client_manager_test.go b/client/context/client_manager_test.go deleted file mode 100644 index 1960f74ced..0000000000 --- a/client/context/client_manager_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package context - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestClientManager(t *testing.T) { - nodeURIs := "10.10.10.10:26657,20.20.20.20:26657,30.30.30.30:26657" - clientMgr, err := NewClientManager(nodeURIs) - assert.Empty(t, err) - endpoint := clientMgr.getClient() - assert.NotEqual(t, endpoint, clientMgr.getClient()) - clientMgr.getClient() - assert.Equal(t, endpoint, clientMgr.getClient()) -} diff --git a/client/context/context.go b/client/context/context.go index 28506756cf..ffdd0f7bc0 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -34,7 +34,6 @@ type CLIContext struct { JSON bool PrintResponse bool Certifier tendermintLite.Certifier - ClientManager *ClientManager } // NewCLIContext returns a new initialized CLIContext with parameters from the @@ -126,9 +125,3 @@ func (ctx CLIContext) WithCertifier(certifier tendermintLite.Certifier) CLIConte ctx.Certifier = certifier return ctx } - -// WithClientManager - return a copy of the context with an updated ClientManager -func (ctx CLIContext) WithClientManager(clientManager *ClientManager) CLIContext { - ctx.ClientManager = clientManager - return ctx -} From fa78303253c2380f6fcb0918629f18d335310d5d Mon Sep 17 00:00:00 2001 From: Greg Szabo Date: Wed, 29 Aug 2018 14:54:22 -0400 Subject: [PATCH 07/28] DataDog hostname reporting fix --- .../roles/update-datadog-agent/templates/datadog.yaml.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networks/remote/ansible/roles/update-datadog-agent/templates/datadog.yaml.j2 b/networks/remote/ansible/roles/update-datadog-agent/templates/datadog.yaml.j2 index 7e35a5255e..3c2e031dde 100644 --- a/networks/remote/ansible/roles/update-datadog-agent/templates/datadog.yaml.j2 +++ b/networks/remote/ansible/roles/update-datadog-agent/templates/datadog.yaml.j2 @@ -31,7 +31,7 @@ api_key: {{DD_API_KEY}} force_tls_12: yes # Force the hostname to whatever you want. (default: auto-detected) -hostname: {{inventory_hostname}} +hostname: {{inventory_hostname | replace ("_","-")}} # Make the agent use "hostname -f" on unix-based systems as a last resort # way of determining the hostname instead of Golang "os.Hostname()" From 03c56fc02442099e415a9f5ad5752bd5ae2e336c Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Thu, 30 Aug 2018 18:33:48 -0700 Subject: [PATCH 08/28] Merge PR #2190: Rename --gen-txs to --with-txs * Rename --gen-txs to --with-txs Closes #1088. * Update CHANGELOG.md --- PENDING.md | 1 + docs/getting-started/create-testnet.md | 2 +- .../remote/ansible/roles/setup-validators/tasks/main.yml | 2 +- server/init.go | 6 +++--- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/PENDING.md b/PENDING.md index f45541ccdc..339868c99d 100644 --- a/PENDING.md +++ b/PENDING.md @@ -13,6 +13,7 @@ BREAKING CHANGES * [cli] \#2061 changed proposalID in governance REST endpoints to proposal-id * [cli] \#2014 `gaiacli advanced` no longer exists - to access `ibc`, `rest-server`, and `validator-set` commands use `gaiacli ibc`, `gaiacli rest-server`, and `gaiacli tendermint`, respectively * [makefile] `get_vendor_deps` no longer updates lock file it just updates vendor directory. Use `update_vendor_deps` to update the lock file. [#2152](https://github.com/cosmos/cosmos-sdk/pull/2152) + * [cli] \#2190 `gaiacli init --gen-txs` is now `gaiacli init --with-txs` to reduce confusion * Gaia * Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013) diff --git a/docs/getting-started/create-testnet.md b/docs/getting-started/create-testnet.md index 0b68b3287b..74fd1d5ef2 100644 --- a/docs/getting-started/create-testnet.md +++ b/docs/getting-started/create-testnet.md @@ -13,7 +13,7 @@ Now these json files need to be aggregated together via Github, a Google form, p Place all files on one computer in `$HOME/.gaiad/gen-tx/` ```bash -gaiad init --gen-txs -o --chain= +gaiad init --with-txs -o --chain= ``` This will generate a `genesis.json` in `$HOME/.gaiad/config/genesis.json` distribute this file to all validators on your testnet. diff --git a/networks/remote/ansible/roles/setup-validators/tasks/main.yml b/networks/remote/ansible/roles/setup-validators/tasks/main.yml index 8832db4aa2..d8cb499135 100644 --- a/networks/remote/ansible/roles/setup-validators/tasks/main.yml +++ b/networks/remote/ansible/roles/setup-validators/tasks/main.yml @@ -70,7 +70,7 @@ unarchive: src=files/gen-tx.tgz dest=/home/gaiad/.gaiad/config/gentx owner=gaiad - name: Generate genesis.json - command: "/usr/bin/gaiad init --gen-txs --name=node{{nodeid.stdout_lines[0]}} --chain-id={{TESTNET_NAME}}" + command: "/usr/bin/gaiad init --with-txs --name=node{{nodeid.stdout_lines[0]}} --chain-id={{TESTNET_NAME}}" become: yes become_user: gaiad args: diff --git a/server/init.go b/server/init.go index 39f3d0b7f8..105325e0d5 100644 --- a/server/init.go +++ b/server/init.go @@ -41,7 +41,7 @@ var ( //parameter names, init command var ( FlagOverwrite = "overwrite" - FlagGenTxs = "gen-txs" + FlagWithTxs = "with-txs" FlagIP = "ip" FlagChainID = "chain-id" ) @@ -169,7 +169,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { config.SetRoot(viper.GetString(tmcli.HomeFlag)) initConfig := InitConfig{ viper.GetString(FlagChainID), - viper.GetBool(FlagGenTxs), + viper.GetBool(FlagWithTxs), filepath.Join(config.RootDir, "config", "gentx"), viper.GetBool(FlagOverwrite), } @@ -198,7 +198,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { } cmd.Flags().BoolP(FlagOverwrite, "o", false, "overwrite the genesis.json file") cmd.Flags().String(FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") - cmd.Flags().Bool(FlagGenTxs, false, "apply genesis transactions from [--home]/config/gentx/") + cmd.Flags().Bool(FlagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/") cmd.Flags().AddFlagSet(appInit.FlagsAppGenState) cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) // need to add this flagset for when no GenTx's provided cmd.AddCommand(GenTxCmd(ctx, cdc, appInit)) From dc0f13214d75734d2ab47c7ee6c86ecb06d72077 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Thu, 30 Aug 2018 18:38:28 -0700 Subject: [PATCH 09/28] Merge PR #2170: Add show-address command * Add show-address command Closes #1274. * Add PENDING entry * Add godoc * Updates from code review --- PENDING.md | 1 + server/tm_cmds.go | 50 +++++++++++++++++++++++++++++++++++------------ server/util.go | 1 + 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/PENDING.md b/PENDING.md index 339868c99d..14747be9d6 100644 --- a/PENDING.md +++ b/PENDING.md @@ -42,6 +42,7 @@ FEATURES * [cli] \#2047 The --gas-adjustment flag can be used to adjust the estimate obtained via the simulation triggered by --gas=0. * Gaia + * [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address` * SDK * [querier] added custom querier functionality, so ABCI query requests can be handled by keepers diff --git a/server/tm_cmds.go b/server/tm_cmds.go index c2395e3996..d84022183a 100644 --- a/server/tm_cmds.go +++ b/server/tm_cmds.go @@ -11,6 +11,7 @@ import ( tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" "github.com/tendermint/tendermint/p2p" pvm "github.com/tendermint/tendermint/privval" + "github.com/cosmos/cosmos-sdk/client" ) // ShowNodeIDCmd - ported from Tendermint, dump node ID to stdout @@ -32,7 +33,6 @@ func ShowNodeIDCmd(ctx *Context) *cobra.Command { // ShowValidator - ported from Tendermint, show this node's validator info func ShowValidatorCmd(ctx *Context) *cobra.Command { - flagJSON := "json" cmd := cobra.Command{ Use: "show-validator", Short: "Show this node's tendermint validator info", @@ -42,16 +42,8 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command { privValidator := pvm.LoadOrGenFilePV(cfg.PrivValidatorFile()) valPubKey := privValidator.PubKey - if viper.GetBool(flagJSON) { - - cdc := wire.NewCodec() - wire.RegisterCrypto(cdc) - pubKeyJSONBytes, err := cdc.MarshalJSON(valPubKey) - if err != nil { - return err - } - fmt.Println(string(pubKeyJSONBytes)) - return nil + if viper.GetBool(client.FlagJson) { + return printlnJSON(valPubKey) } pubkey, err := sdk.Bech32ifyValPub(valPubKey) if err != nil { @@ -61,10 +53,44 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command { return nil }, } - cmd.Flags().Bool(flagJSON, false, "get machine parseable output") + cmd.Flags().Bool(client.FlagJson, false, "get machine parseable output") return &cmd } +// ShowAddressCmd - show this node's validator address +func ShowAddressCmd(ctx *Context) *cobra.Command { + cmd := &cobra.Command{ + Use: "show-address", + Short: "Shows this node's tendermint validator address", + RunE: func(cmd *cobra.Command, args []string) error { + cfg := ctx.Config + privValidator := pvm.LoadOrGenFilePV(cfg.PrivValidatorFile()) + valAddr := (sdk.ValAddress)(privValidator.Address) + + if viper.GetBool(client.FlagJson) { + return printlnJSON(valAddr) + } + + fmt.Println(valAddr.String()) + return nil + }, + } + + cmd.Flags().Bool(client.FlagJson, false, "get machine parseable output") + return cmd +} + +func printlnJSON(v interface{}) error { + cdc := wire.NewCodec() + wire.RegisterCrypto(cdc) + marshalled, err := cdc.MarshalJSON(v) + if err != nil { + return err + } + fmt.Println(string(marshalled)) + return nil +} + // UnsafeResetAllCmd - extension of the tendermint command, resets initialization func UnsafeResetAllCmd(ctx *Context) *cobra.Command { return &cobra.Command{ diff --git a/server/util.go b/server/util.go index 0f5a7b3eb2..04c539eb42 100644 --- a/server/util.go +++ b/server/util.go @@ -112,6 +112,7 @@ func AddCommands( tendermintCmd.AddCommand( ShowNodeIDCmd(ctx), ShowValidatorCmd(ctx), + ShowAddressCmd(ctx), ) rootCmd.AddCommand( From ab76fd964a8af03c41ed7160bc2399b8d811502e Mon Sep 17 00:00:00 2001 From: HaoyangLiu Date: Fri, 31 Aug 2018 10:03:48 +0800 Subject: [PATCH 10/28] IRISHUB-238: remove todo, refactor comment and refactor multistoreproof --- client/context/context.go | 6 +-- client/context/query.go | 21 +++------- store/multistoreproof.go | 78 ++++++++++++++--------------------- store/multistoreproof_test.go | 78 +++++++++++++++++++++++------------ store/rootmultistore.go | 7 +--- 5 files changed, 92 insertions(+), 98 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index ffdd0f7bc0..d28cc34f87 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -9,7 +9,7 @@ import ( "github.com/spf13/viper" - tendermintLite "github.com/tendermint/tendermint/lite" + tmlite "github.com/tendermint/tendermint/lite" rpcclient "github.com/tendermint/tendermint/rpc/client" ) @@ -33,7 +33,7 @@ type CLIContext struct { Async bool JSON bool PrintResponse bool - Certifier tendermintLite.Certifier + Certifier tmlite.Certifier } // NewCLIContext returns a new initialized CLIContext with parameters from the @@ -121,7 +121,7 @@ func (ctx CLIContext) WithUseLedger(useLedger bool) CLIContext { } // WithCertifier - return a copy of the context with an updated Certifier -func (ctx CLIContext) WithCertifier(certifier tendermintLite.Certifier) CLIContext { +func (ctx CLIContext) WithCertifier(certifier tmlite.Certifier) CLIContext { ctx.Certifier = certifier return ctx } diff --git a/client/context/query.go b/client/context/query.go index aac0c90306..47390d7872 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -14,7 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" abci "github.com/tendermint/tendermint/abci/types" cmn "github.com/tendermint/tendermint/libs/common" - tendermintLiteProxy "github.com/tendermint/tendermint/lite/proxy" + tmliteProxy "github.com/tendermint/tendermint/lite/proxy" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" "strings" @@ -325,12 +325,8 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro // verifyProof perform response proof verification func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error { - // TODO: Later we consider to return error for missing valid certifier to verify data from untrusted node if ctx.Certifier == nil { - if ctx.Logger != nil { - io.WriteString(ctx.Logger, fmt.Sprintf("Missing valid certifier to verify data from untrusted node\n")) - } - return nil + return fmt.Errorf("missing valid certifier to verify data from untrusted node") } node, err := ctx.GetNode() @@ -338,11 +334,8 @@ func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error { return err } - // TODO: need improvement - // If the the node http client connect to a full node which can't produce or receive new blocks, - // then here the code will wait for a while and return error if time is out. // AppHash for height H is in header H+1 - commit, err := tendermintLiteProxy.GetCertifiedCommit(resp.Height+1, node, ctx.Certifier) + commit, err := tmliteProxy.GetCertifiedCommit(resp.Height+1, node, ctx.Certifier) if err != nil { return err } @@ -356,7 +349,7 @@ func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error { // Validate the substore commit hash against trusted appHash substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(multiStoreProof.StoreName, - multiStoreProof.CommitIDList, commit.Header.AppHash) + multiStoreProof.StoreInfos, commit.Header.AppHash) if err != nil { return errors.Wrap(err, "failed in verifying the proof against appHash") } @@ -376,7 +369,6 @@ func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([ // isQueryStoreWithProof expects a format like /// // queryType can be app or store -// if subpath equals to "/store" or "/key", then return true func isQueryStoreWithProof(path string) bool { if !strings.HasPrefix(path, "/") { return false @@ -385,9 +377,8 @@ func isQueryStoreWithProof(path string) bool { if len(paths) != 3 { return false } - // Currently, only when query subpath is "/store" or "/key", will proof be included in response. - // If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go - if paths[2] == "store" || paths[2] == "key" { + + if store.RequireProof(paths[2]) { return true } return false diff --git a/store/multistoreproof.go b/store/multistoreproof.go index 5ca214bc7d..62cc30ddfc 100644 --- a/store/multistoreproof.go +++ b/store/multistoreproof.go @@ -2,48 +2,33 @@ package store import ( "bytes" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/pkg/errors" "github.com/tendermint/iavl" cmn "github.com/tendermint/tendermint/libs/common" ) -// commitID of substores, such as acc store, gov store -type SubstoreCommitID struct { - Name string `json:"name"` - Version int64 `json:"version"` - CommitHash cmn.HexBytes `json:"commit_hash"` -} - -// proof of store which have multi substores +// MultiStoreProof defines a collection of store proofs in a multi-store type MultiStoreProof struct { - CommitIDList []SubstoreCommitID `json:"commit_id_list"` - StoreName string `json:"store_name"` - RangeProof iavl.RangeProof `json:"range_proof"` + StoreInfos []storeInfo + StoreName string + RangeProof iavl.RangeProof } -// build MultiStoreProof based on iavl proof and storeInfos -func BuildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []storeInfo) ([]byte, error) { +// buildMultiStoreProof build MultiStoreProof based on iavl proof and storeInfos +func buildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []storeInfo) ([]byte, error) { var rangeProof iavl.RangeProof err := cdc.UnmarshalBinary(iavlProof, &rangeProof) if err != nil { return nil, err } - var multiStoreProof MultiStoreProof - for _, storeInfo := range storeInfos { - - commitID := SubstoreCommitID{ - Name: storeInfo.Name, - Version: storeInfo.Core.CommitID.Version, - CommitHash: storeInfo.Core.CommitID.Hash, - } - multiStoreProof.CommitIDList = append(multiStoreProof.CommitIDList, commitID) + msp := MultiStoreProof{ + StoreInfos: storeInfos, + StoreName: storeName, + RangeProof: rangeProof, } - multiStoreProof.StoreName = storeName - multiStoreProof.RangeProof = rangeProof - proof, err := cdc.MarshalBinary(multiStoreProof) + proof, err := cdc.MarshalBinary(msp) if err != nil { return nil, err } @@ -51,28 +36,15 @@ func BuildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []store return proof, nil } -// verify multiStoreCommitInfo against appHash -func VerifyMultiStoreCommitInfo(storeName string, multiStoreCommitInfo []SubstoreCommitID, appHash []byte) ([]byte, error) { +// VerifyMultiStoreCommitInfo verify multiStoreCommitInfo against appHash +func VerifyMultiStoreCommitInfo(storeName string, storeInfos []storeInfo, appHash []byte) ([]byte, error) { var substoreCommitHash []byte - var storeInfos []storeInfo var height int64 - for _, multiStoreCommitID := range multiStoreCommitInfo { - - if multiStoreCommitID.Name == storeName { - substoreCommitHash = multiStoreCommitID.CommitHash - height = multiStoreCommitID.Version + for _, storeInfo := range storeInfos { + if storeInfo.Name == storeName { + substoreCommitHash = storeInfo.Core.CommitID.Hash + height = storeInfo.Core.CommitID.Version } - storeInfo := storeInfo{ - Name: multiStoreCommitID.Name, - Core: storeCore{ - CommitID: sdk.CommitID{ - Version: multiStoreCommitID.Version, - Hash: multiStoreCommitID.CommitHash, - }, - }, - } - - storeInfos = append(storeInfos, storeInfo) } if len(substoreCommitHash) == 0 { return nil, cmn.NewError("failed to get substore root commit hash by store name") @@ -89,7 +61,7 @@ func VerifyMultiStoreCommitInfo(storeName string, multiStoreCommitInfo []Substor return substoreCommitHash, nil } -// verify iavl proof +// VerifyRangeProof verify iavl RangeProof func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof *iavl.RangeProof) error { // Validate the proof to ensure data integrity. @@ -99,13 +71,13 @@ func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof * } if len(value) != 0 { - // Validate existence proof + // Verify existence proof err = rangeProof.VerifyItem(key, value) if err != nil { return errors.Wrap(err, "failed in existence verification") } } else { - // Validate absence proof + // Verify absence proof err = rangeProof.VerifyAbsence(key) if err != nil { return errors.Wrap(err, "failed in absence verification") @@ -114,3 +86,13 @@ func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof * return nil } + +// RequireProof return whether proof is require for the subpath +func RequireProof(subpath string) bool { + // Currently, only when query subpath is "/store" or "/key", will proof be included in response. + // If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go:212 + if subpath == "/store" || subpath == "/key" { + return true + } + return false +} diff --git a/store/multistoreproof_test.go b/store/multistoreproof_test.go index 1538915677..b4e8a84b16 100644 --- a/store/multistoreproof_test.go +++ b/store/multistoreproof_test.go @@ -14,55 +14,79 @@ func TestVerifyMultiStoreCommitInfo(t *testing.T) { substoreRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828") storeName := "acc" - var multiStoreCommitInfo []SubstoreCommitID + var storeInfos []storeInfo gocRootHash, _ := hex.DecodeString("62c171bb022e47d1f745608ff749e676dbd25f78") - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "gov", - Version: 689, - CommitHash: gocRootHash, + storeInfos = append(storeInfos, storeInfo{ + Name: "gov", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: gocRootHash, + }, + }, }) - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "main", - Version: 689, - CommitHash: nil, + storeInfos = append(storeInfos, storeInfo{ + Name: "main", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: nil, + }, + }, }) accRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828") - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "acc", - Version: 689, - CommitHash: accRootHash, + storeInfos = append(storeInfos, storeInfo{ + Name: "acc", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: accRootHash, + }, + }, }) - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "ibc", - Version: 689, - CommitHash: nil, + storeInfos = append(storeInfos, storeInfo{ + Name: "ibc", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: nil, + }, + }, }) stakeRootHash, _ := hex.DecodeString("987d1d27b8771d93aa3691262f661d2c85af7ca4") - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "stake", - Version: 689, - CommitHash: stakeRootHash, + storeInfos = append(storeInfos, storeInfo{ + Name: "stake", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: stakeRootHash, + }, + }, }) slashingRootHash, _ := hex.DecodeString("388ee6e5b11f367069beb1eefd553491afe9d73e") - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "slashing", - Version: 689, - CommitHash: slashingRootHash, + storeInfos = append(storeInfos, storeInfo{ + Name: "slashing", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: slashingRootHash, + }, + }, }) - commitHash, err := VerifyMultiStoreCommitInfo(storeName, multiStoreCommitInfo, appHash) + commitHash, err := VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash) assert.Nil(t, err) assert.Equal(t, commitHash, substoreRootHash) appHash, _ = hex.DecodeString("29de216bf5e2531c688de36caaf024cd3bb09ee3") - _, err = VerifyMultiStoreCommitInfo(storeName, multiStoreCommitInfo, appHash) + _, err = VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash) assert.Error(t, err, "appHash doesn't match to the merkle root of multiStoreCommitInfo") } diff --git a/store/rootmultistore.go b/store/rootmultistore.go index c5ce52b0ba..5f6b082832 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -292,19 +292,16 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery { req.Path = subpath res := queryable.Query(req) - // Currently, only when query subpath is "/store" or "/key", will proof be included in response. - // If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go - if !req.Prove || subpath != "/store" && subpath != "/key" { + if !req.Prove || !RequireProof(subpath) { return res } - //Load commit info from db commitInfo, errMsg := getCommitInfo(rs.db, res.Height) if errMsg != nil { return sdk.ErrInternal(errMsg.Error()).QueryResult() } - res.Proof, errMsg = BuildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos) + res.Proof, errMsg = buildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos) if errMsg != nil { return sdk.ErrInternal(errMsg.Error()).QueryResult() } From 9de7650b990f2186084448804789447782b3aff7 Mon Sep 17 00:00:00 2001 From: HaoyangLiu Date: Fri, 31 Aug 2018 10:15:37 +0800 Subject: [PATCH 11/28] IRISHUB-238: fix a bug in judge whether proof is required and refactor comment --- client/context/query.go | 2 +- store/multistoreproof.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 47390d7872..31861a972e 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -378,7 +378,7 @@ func isQueryStoreWithProof(path string) bool { return false } - if store.RequireProof(paths[2]) { + if store.RequireProof("/" + paths[2]) { return true } return false diff --git a/store/multistoreproof.go b/store/multistoreproof.go index 62cc30ddfc..05eb49730a 100644 --- a/store/multistoreproof.go +++ b/store/multistoreproof.go @@ -64,7 +64,7 @@ func VerifyMultiStoreCommitInfo(storeName string, storeInfos []storeInfo, appHas // VerifyRangeProof verify iavl RangeProof func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof *iavl.RangeProof) error { - // Validate the proof to ensure data integrity. + // Verify the proof to ensure data integrity. err := rangeProof.Verify(substoreCommitHash) if err != nil { return errors.Wrap(err, "proof root hash doesn't equal to substore commit root hash") From 6d2fb8edefe61f31ea47234d2a5b5164fe51ac9f Mon Sep 17 00:00:00 2001 From: HaoyangLiu Date: Fri, 31 Aug 2018 11:29:55 +0800 Subject: [PATCH 12/28] IRISHUB-238: fix test_cli failure, move certifier creation from lcd/root.go to NewCLIContext --- client/context/context.go | 23 ++++++++++++++++++++++- client/flags.go | 1 + client/lcd/root.go | 22 ++++------------------ 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index d28cc34f87..2d9c9b90c9 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -9,8 +9,12 @@ import ( "github.com/spf13/viper" + "github.com/tendermint/tendermint/libs/cli" + tendermintLite "github.com/tendermint/tendermint/lite" tmlite "github.com/tendermint/tendermint/lite" + tendermintLiteProxy "github.com/tendermint/tendermint/lite/proxy" rpcclient "github.com/tendermint/tendermint/rpc/client" + "fmt" ) const ctxAccStoreName = "acc" @@ -46,6 +50,22 @@ func NewCLIContext() CLIContext { rpc = rpcclient.NewHTTP(nodeURI, "/websocket") } + trustNode := viper.GetBool(client.FlagTrustNode) + var certifier tendermintLite.Certifier + if !trustNode { + chainID := viper.GetString(client.FlagChainID) + home := viper.GetString(cli.HomeFlag) + if chainID != "" && home != "" && nodeURI != "" { + var err error + certifier, err = tendermintLiteProxy.GetCertifier(chainID, home, nodeURI) + if err != nil { + panic(err) + } + } else { + panic(fmt.Errorf("can't create certifier for distrust mode, values from these options may be empty: --chain-id, --home or --node")) + } + } + return CLIContext{ Client: rpc, NodeURI: nodeURI, @@ -54,11 +74,12 @@ func NewCLIContext() CLIContext { Height: viper.GetInt64(client.FlagHeight), Gas: viper.GetInt64(client.FlagGas), GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment), - TrustNode: viper.GetBool(client.FlagTrustNode), + TrustNode: trustNode, UseLedger: viper.GetBool(client.FlagUseLedger), Async: viper.GetBool(client.FlagAsync), JSON: viper.GetBool(client.FlagJson), PrintResponse: viper.GetBool(client.FlagPrintResponse), + Certifier: certifier, } } diff --git a/client/flags.go b/client/flags.go index 81e0670678..12bddb7d96 100644 --- a/client/flags.go +++ b/client/flags.go @@ -58,6 +58,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command { c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously") c.Flags().Bool(FlagJson, false, "return output in json format") c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)") + c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for query responses") } return cmds } diff --git a/client/lcd/root.go b/client/lcd/root.go index f05fb88081..f18ee5dfd4 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -4,11 +4,11 @@ import ( "net/http" "os" - client "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" - keys "github.com/cosmos/cosmos-sdk/client/keys" - rpc "github.com/cosmos/cosmos-sdk/client/rpc" - tx "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/client/rpc" + "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/wire" auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest" bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest" @@ -19,11 +19,8 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/tendermint/tendermint/libs/cli" cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/libs/log" - tendermintLite "github.com/tendermint/tendermint/lite" - tendermintLiteProxy "github.com/tendermint/tendermint/lite/proxy" tmserver "github.com/tendermint/tendermint/rpc/lib/server" ) @@ -84,17 +81,6 @@ func createHandler(cdc *wire.Codec) http.Handler { cliCtx := context.NewCLIContext().WithCodec(cdc).WithLogger(os.Stdout) - chainID := viper.GetString(client.FlagChainID) - home := viper.GetString(cli.HomeFlag) - nodeURI := viper.GetString(client.FlagNode) - var certifier tendermintLite.Certifier - if chainID != "" && home != "" && nodeURI != "" { - certifier, err = tendermintLiteProxy.GetCertifier(chainID, home, nodeURI) - if err != nil { - panic(err) - } - cliCtx = cliCtx.WithCertifier(certifier) - } // TODO: make more functional? aka r = keys.RegisterRoutes(r) r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET") r.HandleFunc("/node_version", NodeVersionRequestHandler(cliCtx)).Methods("GET") From 2d92803b9f7789fd5c03fdd207d0b70b2ee1dd5a Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 31 Aug 2018 00:06:44 -0400 Subject: [PATCH 13/28] Merge PR #2040: Refactor Validator Account Types/Bech32 Prefixing * Add new account bech32 prefixes with godocs * Restructure spacing of existing account code * Update account godocs * More account godoc updates + new tm pub/addr helpers * Update validator type to use new account types/bech32 prefixes * Fix account documentation errors * Update Bech32 prefix for consensus nodes * Update Bech32 spec doc * Fix account type tests * Add missing account consensus functions, clear up godocs, and fix tests * Add to TestRandBech32PubkeyConsistency check * Update initialization of validator public keys * Update query signing info command * Implement new ConsAddress type with associated unit tests * [WIP] Update stake and slashing parameters * Update all calls to MustBech32ifyValPub * [WIP] Validator operator API updates * [WIP] Fix and update unit tests * Fix gov logs (helping to debug failing tests) * Fix gov tally * Fix all broken x/ unit tests * Update gaia app genesis address logic * Fix linting errors * Fix broken LCD tests * Fix broken CLI tests * Implement command to get validator address and pubkey from key name * Add support for getting validator key information via REST endpoint * Update PENDING log * Update docs * Revert GaiaGenTx.PubKey bech32 prefix * Fix broken docs and cli tests * Update genesis to use correct Bech32 (cons) prefix for pubkeys * Update docs and unit tests to reflect new cosmos account bech32 prefix * minor formatting --- PENDING.md | 8 + client/keys/add.go | 3 +- client/keys/root.go | 2 +- client/keys/show.go | 110 ++++-- client/keys/utils.go | 70 +++- client/lcd/lcd_test.go | 64 ++-- client/rpc/validators.go | 2 +- cmd/gaia/app/genesis.go | 9 +- cmd/gaia/app/sim_test.go | 4 +- cmd/gaia/cli_test/cli_test.go | 15 +- docs/clients/lcd-rest-api.yaml | 6 +- docs/clients/ledger.md | 2 +- docs/ics/ics-030-signed-messages.md | 2 +- docs/light/api.md | 24 +- docs/sdk/clients.md | 76 ++-- docs/spec/other/bech32.md | 27 +- docs/validators/validator-faq.md | 13 +- docs/validators/validator-setup.md | 14 +- examples/README.md | 20 +- examples/democoin/mock/validator.go | 8 +- examples/democoin/x/assoc/validator_set.go | 22 +- examples/democoin/x/oracle/handler.go | 4 +- examples/democoin/x/pow/types_test.go | 4 +- server/tm_cmds.go | 4 +- types/account.go | 420 +++++++++++++++------ types/account_test.go | 80 +++- types/stake.go | 6 +- x/bank/msgs_test.go | 4 +- x/gov/endblocker_test.go | 19 +- x/gov/handler.go | 8 +- x/gov/tally.go | 24 +- x/gov/tally_test.go | 124 ++++-- x/gov/test_common.go | 14 + x/slashing/app_test.go | 8 +- x/slashing/client/cli/query.go | 2 +- x/slashing/client/cli/tx.go | 4 +- x/slashing/client/rest/query.go | 2 +- x/slashing/client/rest/tx.go | 6 +- x/slashing/handler_test.go | 6 +- x/slashing/keeper_test.go | 30 +- x/slashing/msg.go | 10 +- x/slashing/msg_test.go | 4 +- x/slashing/simulation/msgs.go | 2 +- x/slashing/test_common.go | 4 +- x/slashing/tick_test.go | 4 +- x/stake/app_test.go | 34 +- x/stake/client/cli/query.go | 12 +- x/stake/client/cli/tx.go | 58 +-- x/stake/client/rest/query.go | 47 ++- x/stake/client/rest/tx.go | 67 ++-- x/stake/client/rest/utils.go | 25 +- x/stake/genesis_test.go | 10 +- x/stake/handler_test.go | 92 ++--- x/stake/keeper/delegation.go | 71 ++-- x/stake/keeper/key.go | 80 ++-- x/stake/keeper/sdk_types.go | 4 +- x/stake/keeper/test_common.go | 12 +- x/stake/keeper/validator.go | 8 +- x/stake/keeper/validator_test.go | 52 +-- x/stake/simulation/msgs.go | 22 +- x/stake/types/delegation.go | 19 +- x/stake/types/delegation_test.go | 22 +- x/stake/types/msg.go | 105 +++--- x/stake/types/msg_test.go | 92 ++--- x/stake/types/test_utils.go | 8 +- x/stake/types/validator.go | 16 +- 66 files changed, 1315 insertions(+), 835 deletions(-) diff --git a/PENDING.md b/PENDING.md index 14747be9d6..832f25e8f4 100644 --- a/PENDING.md +++ b/PENDING.md @@ -14,12 +14,18 @@ BREAKING CHANGES * [cli] \#2014 `gaiacli advanced` no longer exists - to access `ibc`, `rest-server`, and `validator-set` commands use `gaiacli ibc`, `gaiacli rest-server`, and `gaiacli tendermint`, respectively * [makefile] `get_vendor_deps` no longer updates lock file it just updates vendor directory. Use `update_vendor_deps` to update the lock file. [#2152](https://github.com/cosmos/cosmos-sdk/pull/2152) * [cli] \#2190 `gaiacli init --gen-txs` is now `gaiacli init --with-txs` to reduce confusion + * \#2040 All commands that utilize a validator's address must now use the new + bech32 prefix, `cosmosval`. A validator's Tendermint signing key and address + now use a new bech32 prefix, `cosmoscons`. * Gaia * Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013) * [x/stake] \#1901 Validator type's Owner field renamed to Operator; Validator's GetOwner() renamed accordingly to comply with the SDK's Validator interface. * [docs] [#2001](https://github.com/cosmos/cosmos-sdk/pull/2001) Update slashing spec for slashing period * [x/stake, x/slashing] [#1305](https://github.com/cosmos/cosmos-sdk/issues/1305) - Rename "revoked" to "jailed" + * [x/stake] \#2040 Validator operator type has now changed to `sdk.ValAddress` + * A new bech32 prefix has been introduced for Tendermint signing keys and + addresses, `cosmosconspub` and `cosmoscons` respectively. * SDK * [core] \#1807 Switch from use of rational to decimal @@ -38,6 +44,8 @@ FEATURES * Gaia CLI (`gaiacli`) * [cli] Cmds to query staking pool and params * [gov][cli] #2062 added `--proposal` flag to `submit-proposal` that allows a JSON file containing a proposal to be passed in + * \#2040 Add `--bech` to `gaiacli keys show` and respective REST endpoint to + provide desired Bech32 prefix encoding * [cli] \#2047 Setting the --gas flag value to 0 triggers a simulation of the tx before the actual execution. The gas estimate obtained via the simulation will be used as gas limit in the actual execution. * [cli] \#2047 The --gas-adjustment flag can be used to adjust the estimate obtained via the simulation triggered by --gas=0. diff --git a/client/keys/add.go b/client/keys/add.go index d462db1c06..c421728196 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -128,7 +128,8 @@ func printCreate(info keys.Info, seed string) { output := viper.Get(cli.OutputFlag) switch output { case "text": - printInfo(info) + printKeyInfo(info, Bech32KeyOutput) + // print seed unless requested not to. if !viper.GetBool(client.FlagUseLedger) && !viper.GetBool(flagNoBackup) { fmt.Println("**Important** write this seed phrase in a safe place.") diff --git a/client/keys/root.go b/client/keys/root.go index c8f6aea693..f2a27dc0c8 100644 --- a/client/keys/root.go +++ b/client/keys/root.go @@ -21,7 +21,7 @@ func Commands() *cobra.Command { cmd.AddCommand( addKeyCommand(), listKeysCmd, - showKeysCmd, + showKeysCmd(), client.LineBreak, deleteKeyCommand(), updateKeyCommand(), diff --git a/client/keys/show.go b/client/keys/show.go index e9d692ece5..9710cac11e 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -2,6 +2,7 @@ package keys import ( "encoding/json" + "fmt" "net/http" "github.com/cosmos/cosmos-sdk/crypto/keys" @@ -18,46 +19,69 @@ const ( FlagAddress = "address" // FlagPublicKey represents the user's public key on the command line. FlagPublicKey = "pubkey" + // FlagBechPrefix defines a desired Bech32 prefix encoding for a key + FlagBechPrefix = "bech" ) -var showKeysCmd = &cobra.Command{ - Use: "show ", - Short: "Show key info for the given name", - Long: `Return public details of one local key.`, - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - name := args[0] - info, err := getKey(name) - if err != nil { - return err - } +func showKeysCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "show [name]", + Short: "Show key info for the given name", + Long: `Return public details of one local key.`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + name := args[0] + info, err := getKey(name) + if err != nil { + return err + } - showAddress := viper.GetBool(FlagAddress) - showPublicKey := viper.GetBool(FlagPublicKey) - outputSet := cmd.Flag(cli.OutputFlag).Changed - if showAddress && showPublicKey { - return errors.New("cannot use both --address and --pubkey at once") - } - if outputSet && (showAddress || showPublicKey) { - return errors.New("cannot use --output with --address or --pubkey") - } - if showAddress { - printKeyAddress(info) - return nil - } - if showPublicKey { - printPubKey(info) - return nil - } + showAddress := viper.GetBool(FlagAddress) + showPublicKey := viper.GetBool(FlagPublicKey) + outputSet := cmd.Flag(cli.OutputFlag).Changed - printInfo(info) - return nil - }, + if showAddress && showPublicKey { + return errors.New("cannot use both --address and --pubkey at once") + } + if outputSet && (showAddress || showPublicKey) { + return errors.New("cannot use --output with --address or --pubkey") + } + + bechKeyOut, err := getBechKeyOut(viper.GetString(FlagBechPrefix)) + if err != nil { + return err + } + + switch { + case showAddress: + printKeyAddress(info, bechKeyOut) + case showPublicKey: + printPubKey(info, bechKeyOut) + default: + printKeyInfo(info, bechKeyOut) + } + return nil + }, + } + + cmd.Flags().String(FlagBechPrefix, "acc", "The Bech32 prefix encoding for a key (acc|val|cons)") + cmd.Flags().Bool(FlagAddress, false, "output the address only (overrides --output)") + cmd.Flags().Bool(FlagPublicKey, false, "output the public key only (overrides --output)") + + return cmd } -func init() { - showKeysCmd.Flags().Bool(FlagAddress, false, "output the address only (overrides --output)") - showKeysCmd.Flags().Bool(FlagPublicKey, false, "output the public key only (overrides --output)") +func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) { + switch bechPrefix { + case "acc": + return Bech32KeyOutput, nil + case "val": + return Bech32ValKeyOutput, nil + case "cons": + return Bech32ConsKeyOutput, nil + } + + return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix) } func getKey(name string) (keys.Info, error) { @@ -76,21 +100,35 @@ func getKey(name string) (keys.Info, error) { func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) name := vars["name"] + bechPrefix := r.URL.Query().Get(FlagBechPrefix) + + if bechPrefix == "" { + bechPrefix = "acc" + } + + bechKeyOut, err := getBechKeyOut(bechPrefix) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } info, err := getKey(name) - // TODO check for the error if key actually does not exist, instead of assuming this as the reason + // TODO: check for the error if key actually does not exist, instead of + // assuming this as the reason if err != nil { w.WriteHeader(404) w.Write([]byte(err.Error())) return } - keyOutput, err := Bech32KeyOutput(info) + keyOutput, err := bechKeyOut(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 aa1b4bed9c..95fc83ed65 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -21,6 +21,8 @@ const KeyDBName = "keys" // keybase is used to make GetKeyBase a singleton var keybase keys.Keybase +type bechKeyOutFn func(keyInfo keys.Info) (KeyOutput, error) + // TODO make keybase take a database not load from the directory // initialize a keybase based on the configuration @@ -97,11 +99,11 @@ func SetKeyBase(kb keys.Keybase) { // used for outputting keys.Info over REST type KeyOutput struct { - Name string `json:"name"` - Type string `json:"type"` - Address sdk.AccAddress `json:"address"` - PubKey string `json:"pub_key"` - Seed string `json:"seed,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + Address string `json:"address"` + PubKey string `json:"pub_key"` + Seed string `json:"seed,omitempty"` } // create a list of KeyOutput in bech32 format @@ -119,24 +121,61 @@ func Bech32KeysOutput(infos []keys.Info) ([]KeyOutput, error) { // create a KeyOutput in bech32 format func Bech32KeyOutput(info keys.Info) (KeyOutput, error) { - account := sdk.AccAddress(info.GetPubKey().Address().Bytes()) + accAddr := sdk.AccAddress(info.GetPubKey().Address().Bytes()) bechPubKey, err := sdk.Bech32ifyAccPub(info.GetPubKey()) if err != nil { return KeyOutput{}, err } + return KeyOutput{ Name: info.GetName(), Type: info.GetType().String(), - Address: account, + Address: accAddr.String(), PubKey: bechPubKey, }, nil } -func printInfo(info keys.Info) { - ko, err := Bech32KeyOutput(info) +// Bech32ConsKeyOutput returns key output for a consensus node's key +// information. +func Bech32ConsKeyOutput(keyInfo keys.Info) (KeyOutput, error) { + consAddr := sdk.ConsAddress(keyInfo.GetPubKey().Address().Bytes()) + + bechPubKey, err := sdk.Bech32ifyConsPub(keyInfo.GetPubKey()) + if err != nil { + return KeyOutput{}, err + } + + return KeyOutput{ + Name: keyInfo.GetName(), + Type: keyInfo.GetType().String(), + Address: consAddr.String(), + PubKey: bechPubKey, + }, nil +} + +// Bech32ValKeyOutput returns key output for a validator's key information. +func Bech32ValKeyOutput(keyInfo keys.Info) (KeyOutput, error) { + valAddr := sdk.ValAddress(keyInfo.GetPubKey().Address().Bytes()) + + bechPubKey, err := sdk.Bech32ifyValPub(keyInfo.GetPubKey()) + if err != nil { + return KeyOutput{}, err + } + + return KeyOutput{ + Name: keyInfo.GetName(), + Type: keyInfo.GetType().String(), + Address: valAddr.String(), + PubKey: bechPubKey, + }, nil +} + +func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) { + ko, err := bechKeyOut(keyInfo) if err != nil { panic(err) } + switch viper.Get(cli.OutputFlag) { case "text": fmt.Printf("NAME:\tTYPE:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") @@ -146,6 +185,7 @@ func printInfo(info keys.Info) { if err != nil { panic(err) } + fmt.Println(string(out)) } } @@ -174,18 +214,20 @@ func printKeyOutput(ko KeyOutput) { fmt.Printf("%s\t%s\t%s\t%s\n", ko.Name, ko.Type, ko.Address, ko.PubKey) } -func printKeyAddress(info keys.Info) { - ko, err := Bech32KeyOutput(info) +func printKeyAddress(info keys.Info, bechKeyOut bechKeyOutFn) { + ko, err := bechKeyOut(info) if err != nil { panic(err) } - fmt.Println(ko.Address.String()) + + fmt.Println(ko.Address) } -func printPubKey(info keys.Info) { - ko, err := Bech32KeyOutput(info) +func printPubKey(info keys.Info, bechKeyOut bechKeyOutFn) { + ko, err := bechKeyOut(info) if err != nil { panic(err) } + fmt.Println(ko.PubKey) } diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 298cf0027e..d68ba278c1 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -62,7 +62,7 @@ func TestKeys(t *testing.T) { err = wire.Cdc.UnmarshalJSON([]byte(body), &resp) require.Nil(t, err, body) - addr2Bech32 := resp.Address.String() + addr2Bech32 := resp.Address _, err = sdk.AccAddressFromBech32(addr2Bech32) require.NoError(t, err, "Failed to return a correct bech32 address") @@ -81,9 +81,9 @@ func TestKeys(t *testing.T) { addrBech32 := addr.String() require.Equal(t, name, m[0].Name, "Did not serve keys name correctly") - require.Equal(t, addrBech32, m[0].Address.String(), "Did not serve keys Address correctly") + require.Equal(t, addrBech32, m[0].Address, "Did not serve keys Address correctly") require.Equal(t, newName, m[1].Name, "Did not serve keys name correctly") - require.Equal(t, addr2Bech32, m[1].Address.String(), "Did not serve keys Address correctly") + require.Equal(t, addr2Bech32, m[1].Address, "Did not serve keys Address correctly") // select key keyEndpoint := fmt.Sprintf("/keys/%s", newName) @@ -94,7 +94,7 @@ func TestKeys(t *testing.T) { require.Nil(t, err) require.Equal(t, newName, m2.Name, "Did not serve keys name correctly") - require.Equal(t, addr2Bech32, m2.Address.String(), "Did not serve keys Address correctly") + require.Equal(t, addr2Bech32, m2.Address, "Did not serve keys Address correctly") // update key jsonStr = []byte(fmt.Sprintf(`{ @@ -204,8 +204,8 @@ func TestValidators(t *testing.T) { require.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals) - require.Contains(t, resultVals.Validators[0].Address.String(), "cosmosvaladdr") - require.Contains(t, resultVals.Validators[0].PubKey, "cosmosvalpub") + require.Contains(t, resultVals.Validators[0].Address.String(), "cosmosval") + require.Contains(t, resultVals.Validators[0].PubKey, "cosmosconspub") // -- @@ -313,7 +313,7 @@ func TestTxs(t *testing.T) { require.Equal(t, http.StatusBadRequest, res.StatusCode, body) // query empty - res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", "cosmosaccaddr1jawd35d9aq4u76sr3fjalmcqc8hqygs9gtnmv3"), nil) + res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", "cosmos1jawd35d9aq4u76sr3fjalmcqc8hqygs90d0g0v"), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, "[]", body) @@ -407,7 +407,7 @@ func TestValidatorsQuery(t *testing.T) { // make sure all the validators were found (order unknown because sorted by operator addr) foundVal := false - pkBech := sdk.MustBech32ifyValPub(pks[0]) + pkBech := sdk.MustBech32ifyConsPub(pks[0]) if validators[0].PubKey == pkBech { foundVal = true } @@ -419,7 +419,7 @@ func TestValidatorQuery(t *testing.T) { defer cleanup() require.Equal(t, 1, len(pks)) - validator1Operator := sdk.AccAddress(pks[0].Address()) + validator1Operator := sdk.ValAddress(pks[0].Address()) validator := getValidator(t, port, validator1Operator) assert.Equal(t, validator.Operator, validator1Operator, "The returned validator does not hold the correct data") } @@ -430,7 +430,7 @@ func TestBonding(t *testing.T) { cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}) defer cleanup() - validator1Operator := sdk.AccAddress(pks[0].Address()) + validator1Operator := sdk.ValAddress(pks[0].Address()) validator := getValidator(t, port, validator1Operator) // create bond TX @@ -611,7 +611,7 @@ func TestUnjail(t *testing.T) { // XXX: any less than this and it fails tests.WaitForHeight(3, port) - pkString, _ := sdk.Bech32ifyValPub(pks[0]) + pkString, _ := sdk.Bech32ifyConsPub(pks[0]) signingInfo := getSigningInfo(t, port, pkString) tests.WaitForHeight(4, port) require.Equal(t, true, signingInfo.IndexOffset > 0) @@ -817,8 +817,8 @@ func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing. // ============= Stake Module ================ -func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.AccAddress) rest.DelegationWithoutRat { - res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delegatorAddr, validatorAddr), nil) +func getDelegation(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) rest.DelegationWithoutRat { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delAddr, valAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) var bond rest.DelegationWithoutRat @@ -829,8 +829,8 @@ func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.A return bond } -func getUndelegations(t *testing.T, port string, delegatorAddr, validatorAddr sdk.AccAddress) []stake.UnbondingDelegation { - res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delegatorAddr, validatorAddr), nil) +func getUndelegations(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) []stake.UnbondingDelegation { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delAddr, valAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) var unbondings []stake.UnbondingDelegation @@ -884,8 +884,8 @@ func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddr return bondedValidators } -func getDelegatorValidator(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) stake.BechValidator { - res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delegatorAddr, validatorAddr), nil) +func getDelegatorValidator(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) stake.BechValidator { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delAddr, valAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) var bondedValidator stake.BechValidator @@ -895,8 +895,10 @@ func getDelegatorValidator(t *testing.T, port string, delegatorAddr sdk.AccAddre return bondedValidator } -func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.AccAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) { - acc := getAccount(t, port, delegatorAddr) +func doDelegate(t *testing.T, port, seed, name, password string, + delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) { + + acc := getAccount(t, port, delAddr) accnum := acc.GetAccountNumber() sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) @@ -918,9 +920,9 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, "complete_unbondings": [], "begin_redelegates": [], "complete_redelegates": [] - }`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr, "steak", amount)) + }`, name, password, accnum, sequence, chainID, delAddr, valAddr, "steak", amount)) - res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr) + res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) var results []ctypes.ResultBroadcastTxCommit @@ -931,9 +933,9 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, } func doBeginUnbonding(t *testing.T, port, seed, name, password string, - delegatorAddr, validatorAddr sdk.AccAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) { + delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) { - acc := getAccount(t, port, delegatorAddr) + acc := getAccount(t, port, delAddr) accnum := acc.GetAccountNumber() sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) @@ -955,9 +957,9 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string, "complete_unbondings": [], "begin_redelegates": [], "complete_redelegates": [] - }`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr, amount)) + }`, name, password, accnum, sequence, chainID, delAddr, valAddr, amount)) - res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr) + res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) var results []ctypes.ResultBroadcastTxCommit @@ -968,9 +970,9 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string, } func doBeginRedelegation(t *testing.T, port, seed, name, password string, - delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) (resultTx ctypes.ResultBroadcastTxCommit) { + delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) (resultTx ctypes.ResultBroadcastTxCommit) { - acc := getAccount(t, port, delegatorAddr) + acc := getAccount(t, port, delAddr) accnum := acc.GetAccountNumber() sequence := acc.GetSequence() @@ -994,9 +996,9 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, } ], "complete_redelegates": [] - }`, name, password, accnum, sequence, chainID, delegatorAddr, validatorSrcAddr, validatorDstAddr)) + }`, name, password, accnum, sequence, chainID, delAddr, valSrcAddr, valDstAddr)) - res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr) + res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr) require.Equal(t, http.StatusOK, res.StatusCode, body) var results []ctypes.ResultBroadcastTxCommit @@ -1015,8 +1017,8 @@ func getValidators(t *testing.T, port string) []stake.BechValidator { return validators } -func getValidator(t *testing.T, port string, validatorAddr sdk.AccAddress) stake.BechValidator { - res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", validatorAddr.String()), nil) +func getValidator(t *testing.T, port string, valAddr sdk.ValAddress) stake.BechValidator { + res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", valAddr.String()), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) var validator stake.BechValidator err := cdc.UnmarshalJSON([]byte(body), &validator) diff --git a/client/rpc/validators.go b/client/rpc/validators.go index d2daa4ec5c..cb002d3ea0 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -45,7 +45,7 @@ type ResultValidatorsOutput struct { } func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error) { - bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey) + bechValPubkey, err := sdk.Bech32ifyConsPub(validator.PubKey) if err != nil { return ValidatorOutput{}, err } diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 0fbbc06031..bfcaa92dde 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -142,7 +142,7 @@ func GaiaAppGenTxNF(cdc *wire.Codec, pk crypto.PubKey, addr sdk.AccAddress, name gaiaGenTx := GaiaGenTx{ Name: name, Address: addr, - PubKey: sdk.MustBech32ifyAccPub(pk), + PubKey: sdk.MustBech32ifyConsPub(pk), } bz, err = wire.MarshalJSONIndent(cdc, gaiaGenTx) if err != nil { @@ -192,8 +192,9 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState // add the validator if len(genTx.Name) > 0 { desc := stake.NewDescription(genTx.Name, "", "", "") - validator := stake.NewValidator(genTx.Address, - sdk.MustGetAccPubKeyBech32(genTx.PubKey), desc) + validator := stake.NewValidator( + sdk.ValAddress(genTx.Address), sdk.MustGetConsPubKeyBech32(genTx.PubKey), desc, + ) stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal)) // increase the supply @@ -204,7 +205,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState // create the self-delegation from the issuedDelShares delegation := stake.Delegation{ - DelegatorAddr: validator.Operator, + DelegatorAddr: sdk.AccAddress(validator.Operator), ValidatorAddr: validator.Operator, Shares: issuedDelShares, Height: 0, diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 0ca936bdbf..559b8b4b9a 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -57,10 +57,10 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json // XXX Try different numbers of initially bonded validators numInitiallyBonded := int64(50) for i := 0; i < int(numInitiallyBonded); i++ { - validator := stake.NewValidator(accs[i], keys[i].PubKey(), stake.Description{}) + validator := stake.NewValidator(sdk.ValAddress(accs[i]), keys[i].PubKey(), stake.Description{}) validator.Tokens = sdk.NewDec(100) validator.DelegatorShares = sdk.NewDec(100) - delegation := stake.Delegation{accs[i], accs[i], sdk.NewDec(100), 0} + delegation := stake.Delegation{accs[i], sdk.ValAddress(accs[i]), sdk.NewDec(100), 0} validators = append(validators, validator) delegations = append(delegations, delegation) } diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index f794e5140d..b91b5a45d6 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -124,7 +124,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome)) barAddr, barPubKey := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome)) - barCeshPubKey := sdk.MustBech32ifyValPub(barPubKey) + barCeshPubKey := sdk.MustBech32ifyConsPub(barPubKey) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) @@ -154,14 +154,14 @@ func TestGaiaCLICreateValidator(t *testing.T) { barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags)) require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc) - validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags)) - require.Equal(t, validator.Operator, barAddr) + validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", sdk.ValAddress(barAddr), flags)) + require.Equal(t, validator.Operator, sdk.ValAddress(barAddr)) require.True(sdk.DecEq(t, sdk.NewDec(2), validator.Tokens)) // unbond a single share unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags) unbondStr += fmt.Sprintf(" --from=%s", "bar") - unbondStr += fmt.Sprintf(" --validator=%s", barAddr) + unbondStr += fmt.Sprintf(" --validator=%s", sdk.ValAddress(barAddr)) unbondStr += fmt.Sprintf(" --shares-amount=%v", "1") success := executeWrite(t, unbondStr, app.DefaultKeyPass) @@ -172,7 +172,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").Int64(), "%v", barAcc) */ - validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags)) + validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", sdk.ValAddress(barAddr), flags)) require.Equal(t, "1.0000000000", validator.Tokens.String()) params := executeGetParams(t, fmt.Sprintf("gaiacli stake parameters --output=json %v", flags)) @@ -352,7 +352,10 @@ func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.AccAddress, crypto.PubKe pk, err := sdk.GetAccPubKeyBech32(ko.PubKey) require.NoError(t, err) - return ko.Address, pk + accAddr, err := sdk.AccAddressFromBech32(ko.Address) + require.NoError(t, err) + + return accAddr, pk } func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount { diff --git a/docs/clients/lcd-rest-api.yaml b/docs/clients/lcd-rest-api.yaml index 5be69302d5..4f402089ad 100644 --- a/docs/clients/lcd-rest-api.yaml +++ b/docs/clients/lcd-rest-api.yaml @@ -710,15 +710,15 @@ definitions: Address: type: string description: bech32 encoded addres - example: cosmosaccaddr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq + example: cosmos:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq ValidatorAddress: type: string description: bech32 encoded addres - example: cosmosvaladdr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq + example: cosmosval:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq PubKey: type: string description: bech32 encoded public key - example: cosmosaccpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq + example: cosmospub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq ValidatorPubKey: type: string description: bech32 encoded public key diff --git a/docs/clients/ledger.md b/docs/clients/ledger.md index 5ea1224eae..26b0215b3d 100644 --- a/docs/clients/ledger.md +++ b/docs/clients/ledger.md @@ -17,7 +17,7 @@ Once you have the Cosmos app installed on your Ledger, and the Ledger is accessi ```bash $ gaiacli keys add {{ .Key.Name }} --ledger NAME: TYPE: ADDRESS: PUBKEY: -{{ .Key.Name }} ledger cosmosaccaddr1aw64xxr80lwqqdk8u2xhlrkxqaxamkr3e2g943 cosmosaccpub1addwnpepqvhs678gh9aqrjc2tg2vezw86csnvgzqq530ujkunt5tkuc7lhjkz5mj629 +{{ .Key.Name }} ledger cosmos1aw64xxr80lwqqdk8u2xhlrkxqaxamkr3e2g943 cosmospub1addwnpepqvhs678gh9aqrjc2tg2vezw86csnvgzqq530ujkunt5tkuc7lhjkz5mj629 ``` This key will only be accessible while the Ledger is plugged in and unlocked. To send some coins with this key, run the following: diff --git a/docs/ics/ics-030-signed-messages.md b/docs/ics/ics-030-signed-messages.md index e73d9f5803..8f53238f7e 100644 --- a/docs/ics/ics-030-signed-messages.md +++ b/docs/ics/ics-030-signed-messages.md @@ -186,7 +186,7 @@ data = { "text": "I hereby claim I am ABC on Keybase!" } -cosmosSignBytes(data, "cosmosaccaddr1pvsch6cddahhrn5e8ekw0us50dpnugwnlfngt3") +cosmosSignBytes(data, "cosmos1pvsch6cddahhrn5e8ekw0us50dpnugwnlfngt3") > "0x7fc4a495473045022100dec81a9820df0102381cdbf7e8b0f1e2cb64c58e0ecda1324543742e0388e41a02200df37905a6505c1b56a404e23b7473d2c0bc5bcda96771d2dda59df6ed2b98f8" ``` diff --git a/docs/light/api.md b/docs/light/api.md index 6c5e8aa5f0..7168cf9d74 100644 --- a/docs/light/api.md +++ b/docs/light/api.md @@ -71,13 +71,13 @@ This API exposes all functionality needed for key creation, signing and manageme "account":[ { "name":"monkey", - "address":"cosmosaccaddr1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd", - "pub_key":"cosmosaccpub1zcjduc3q8s8ha96ry4xc5xvjp9tr9w9p0e5lk5y0rpjs5epsfxs4wmf72x3shvus0t" + "address":"cosmos1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd", + "pub_key":"cosmospub1zcjduc3q8s8ha96ry4xc5xvjp9tr9w9p0e5lk5y0rpjs5epsfxs4wmf72x3shvus0t" }, { "name":"test", - "address":"cosmosaccaddr1thlqhjqw78zvcy0ua4ldj9gnazqzavyw4eske2", - "pub_key":"cosmosaccpub1zcjduc3qyx6hlf825jcnj39adpkaxjer95q7yvy25yhfj3dmqy2ctev0rxmse9cuak" + "address":"cosmos1thlqhjqw78zvcy0ua4ldj9gnazqzavyw4eske2", + "pub_key":"cosmospub1zcjduc3qyx6hlf825jcnj39adpkaxjer95q7yvy25yhfj3dmqy2ctev0rxmse9cuak" } ], "block_height":5241 @@ -125,8 +125,8 @@ Returns on success: "error":"", "result":{ "name":"test", - "address":"cosmosaccaddr1thlqhjqw78zvcy0ua4ldj9gnazqzavyw4eske2", - "pub_key":"cosmosaccpub1zcjduc3qyx6hlf825jcnj39adpkaxjer95q7yvy25yhfj3dmqy2ctev0rxmse9cuak" + "address":"cosmos1thlqhjqw78zvcy0ua4ldj9gnazqzavyw4eske2", + "pub_key":"cosmospub1zcjduc3qyx6hlf825jcnj39adpkaxjer95q7yvy25yhfj3dmqy2ctev0rxmse9cuak" } } ``` @@ -588,7 +588,7 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te "description": "string", // PlainTextProposal supported now. SoftwareUpgradeProposal and other types may be supported soon "proposal_type": "string", - // A cosmosaccaddr address + // A cosmos address "proposer": "string", "initial_deposit": [ { @@ -689,7 +689,7 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te "error":"", "result":{ "amount": {"atom": 150}, - "depositer": "cosmosaccaddr1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd", + "depositer": "cosmos1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd", "proposal-id": 16 } } @@ -731,12 +731,12 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te "result": [ { "proposal-id": 1, - "voter": "cosmosaccaddr1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd", + "voter": "cosmos1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd", "option": "no_with_veto" }, { "proposal-id": 1, - "voter": "cosmosaccaddr1849m9wncrqp6v4tkss6a3j8uzvuv0cp7f75lrq", + "voter": "cosmos1849m9wncrqp6v4tkss6a3j8uzvuv0cp7f75lrq", "option": "yes" }, ] @@ -761,7 +761,7 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te "sequence": 0, "gas": 0 }, - // A cosmosaccaddr address + // A cosmos address "voter": "string", // Value of the vote option `Yes`, `No` `Abstain`, `NoWithVeto` "option": "string", @@ -794,7 +794,7 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te "error":"", "result":{ "proposal-id": 1, - "voter": "cosmosaccaddr1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd", + "voter": "cosmos1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd", "option": "no_with_veto" } } diff --git a/docs/sdk/clients.md b/docs/sdk/clients.md index 0a1c2a38d9..7a23ba28ac 100644 --- a/docs/sdk/clients.md +++ b/docs/sdk/clients.md @@ -18,17 +18,21 @@ There are three types of key representations that are used: -- `cosmosaccaddr` +- `cosmos` - Derived from account keys generated by `gaiacli keys add` - Used to receive funds - - e.g. `cosmosaccaddr15h6vd5f0wqps26zjlwrc6chah08ryu4hzzdwhc` -- `cosmosaccpub` + - e.g. `cosmos15h6vd5f0wqps26zjlwrc6chah08ryu4hzzdwhc` +* `cosmosval` + * Used to associate a validator to it's operator + * Used to invoke staking commands + * e.g. `cosmosval1carzvgq3e6y3z5kz5y6gxp3wpy3qdrv928vyah` +- `cosmospub` - Derived from account keys generated by `gaiacli keys add` - - e.g. `cosmosaccpub1zcjduc3q7fu03jnlu2xpl75s2nkt7krm6grh4cc5aqth73v0zwmea25wj2hsqhlqzm` -- `cosmosvalpub` + - e.g. `cosmospub1zcjduc3q7fu03jnlu2xpl75s2nkt7krm6grh4cc5aqth73v0zwmea25wj2hsqhlqzm` +- `cosmosconspub` - Generated when the node is created with `gaiad init`. - Get this value with `gaiad tendermint show-validator` - - e.g. `cosmosvalpub1zcjduc3qcyj09qc03elte23zwshdx92jm6ce88fgc90rtqhjx8v0608qh5ssp0w94c` + - e.g. `cosmosconspub1zcjduepq0ms2738680y72v44tfyqm3c9ppduku8fs6sr73fx7m666sjztznqzp2emf` #### Generate Keys @@ -48,6 +52,12 @@ If you check your private keys, you'll now see ``: gaiacli keys show ``` +View the validator operator's address via: + +```shell +gaiacli keys show --bech=val +``` + You can see all your available keys by typing: ```bash @@ -68,18 +78,18 @@ We strongly recommend _NOT_ using the same passphrase for multiple keys. The Ten #### Get Tokens -The best way to get tokens is from the [Cosmos Testnet Faucet](https://faucetcosmos.network). If the faucet is not working for you, try asking [#cosmos-validators](https://riot.im/app/#/room/#cosmos-validators:matrix.org). The faucet needs the `cosmosaccaddr` from the account you wish to use for staking. +The best way to get tokens is from the [Cosmos Testnet Faucet](https://faucetcosmos.network). If the faucet is not working for you, try asking [#cosmos-validators](https://riot.im/app/#/room/#cosmos-validators:matrix.org). The faucet needs the `cosmos` from the account you wish to use for staking. #### Query Account balance After receiving tokens to your address, you can view your account's balance by typing: ```bash -gaiacli account +gaiacli account ``` ::: warning Note -When you query an account balance with zero tokens, you will get this error: `No account with address was found in the state.` This can also happen if you fund the account before your node has fully synced with the chain. These are both normal. +When you query an account balance with zero tokens, you will get this error: `No account with address was found in the state.` This can also happen if you fund the account before your node has fully synced with the chain. These are both normal. ::: @@ -90,7 +100,7 @@ gaiacli send \ --amount=10faucetToken \ --chain-id= \ --name= \ - --to= + --to= ``` ::: warning Note @@ -106,14 +116,14 @@ Gas estimate might be inaccurate as state changes could occur in between the end Now, view the updated balances of the origin and destination accounts: ```bash -gaiacli account -gaiacli account +gaiacli account +gaiacli account ``` You can also check your balance at a given block by using the `--block` flag: ```bash -gaiacli account --block= +gaiacli account --block= ``` ### Staking @@ -137,7 +147,7 @@ gaiacli stake validators If you want to get the information of a single validator you can check it with: ```bash -gaiacli stake validator +gaiacli stake validator ``` #### Bond Tokens @@ -164,14 +174,14 @@ Once submitted a delegation to a validator, you can see it's information by usin ```bash gaiacli stake delegation \ - --address-delegator= \ - --address-validator=$(gaiad tendermint show-validator) + --address-delegator= \ + --validator= ``` Or if you want to check all your current delegations with disctinct validators: ```bash -gaiacli stake delegations +gaiacli stake delegations ``` You can also get previous delegation(s) status by adding the `--height` flag. @@ -182,7 +192,7 @@ If for any reason the validator misbehaves, or you just want to unbond a certain ```bash gaiacli stake unbond begin \ - --address-validator=$(gaiad tendermint show-validator) \ + --validator= \ --shares-percent=100 \ --from= \ --chain-id= @@ -192,7 +202,7 @@ Later you must complete the unbonding process by using the `gaiacli stake unbond ```bash gaiacli stake unbond complete \ - --address-validator=$(gaiad tendermint show-validator) \ + --validator= \ --from= \ --chain-id= ``` @@ -203,14 +213,14 @@ Once you begin an unbonding-delegation, you can see it's information by using th ```bash gaiacli stake unbonding-delegation \ - --address-delegator= \ - --address-validator=$(gaiad tendermint show-validator) \ + --address-delegator= \ + --validator= \ ``` Or if you want to check all your current unbonding-delegations with disctinct validators: ```bash -gaiacli stake unbonding-delegations +gaiacli stake unbonding-delegations ``` You can also get previous unbonding-delegation(s) status by adding the `--height` flag. @@ -221,8 +231,8 @@ A redelegation is a type delegation that allows you to bond illiquid tokens from ```bash gaiacli stake redelegate begin \ - --address-validator-source=$(gaiad tendermint show-validator) \ - --address-validator-dest= \ + --address-validator-source= \ + --address-validator-dest= \ --shares-percent=50 \ --from= \ --chain-id= @@ -234,7 +244,7 @@ Later you must complete the redelegation process by using the `gaiacli stake red ```bash gaiacli stake unbond complete \ - --address-validator=$(gaiad tendermint show-validator) \ + --validator= \ --from= \ --chain-id= ``` @@ -245,15 +255,15 @@ Once you begin an redelegation, you can see it's information by using the follow ```bash gaiacli stake redelegation \ - --address-delegator= \ - --address-validator-source=$(gaiad tendermint show-validator) \ - --address-validator-dest= \ + --address-delegator= \ + --address-validator-source= \ + --address-validator-dest= \ ``` Or if you want to check all your current unbonding-delegations with disctinct validators: ```bash -gaiacli stake redelegations +gaiacli stake redelegations ``` You can also get previous redelegation(s) status by adding the `--height` flag. @@ -286,7 +296,7 @@ gaiacli gov submit-proposal \ --title= \ --description=<description> \ --type=<Text/ParameterChange/SoftwareUpgrade> \ - --proposer=<account_cosmosaccaddr> \ + --proposer=<account_cosmos> \ --deposit=<40steak> \ --from=<name> \ --chain-id=<chain_id> @@ -316,7 +326,7 @@ In order for a proposal to be broadcasted to the network, the amount deposited m ```bash gaiacli gov deposit \ --proposal-id=<proposal_id> \ - --depositer=<account_cosmosaccaddr> \ + --depositer=<account_cosmos> \ --deposit=<200steak> \ --from=<name> \ --chain-id=<chain_id> @@ -331,7 +341,7 @@ After a proposal's deposit reaches the `MinDeposit` value, the voting period ope ```bash gaiacli gov vote \ --proposal-id=<proposal_id> \ - --voter=<account_cosmosaccaddr> \ + --voter=<account_cosmos> \ --option=<Yes/No/NoWithVeto/Abstain> \ --from=<name> \ --chain-id=<chain_id> @@ -344,7 +354,7 @@ Check the vote with the option you just submitted: ```bash gaiacli gov query-vote \ --proposal-id=<proposal_id> \ - --voter=<account_cosmosaccaddr> + --voter=<account_cosmos> ``` #### Query Parameters diff --git a/docs/spec/other/bech32.md b/docs/spec/other/bech32.md index 1558c1ec37..911102a8a7 100644 --- a/docs/spec/other/bech32.md +++ b/docs/spec/other/bech32.md @@ -1,25 +1,24 @@ # Bech32 on Cosmos -The Cosmos network prefers to use the Bech32 address format whereever users must handle binary data. Bech32 encoding provides robust integrity checks on data and the human readable part(HRP) provides contextual hints that can assist UI developers with providing informative error messages. +The Cosmos network prefers to use the Bech32 address format wherever users must handle binary data. Bech32 encoding provides robust integrity checks on data and the human readable part(HRP) provides contextual hints that can assist UI developers with providing informative error messages. In the Cosmos network, keys and addresses may refer to a number of different roles in the network like accounts, validators etc. +## HRP table -## HRP table - -| HRP | Definition | -| ------------- |:-------------:| -| `cosmos` | Cosmos Account Address | -| `cosmospub` | Cosmos Account Public Key | -| `cosmosval` | Cosmos Validator Consensus Address | -| `cosmosvalpub`| Cosmos Validator Consensus Public Key| +| HRP | Definition | +|---------------|--------------------------------------| +| cosmos | Cosmos Account Address | +| cosmospub | Cosmos Account Public Key | +| cosmoscons | Cosmos Consensus Address | +| cosmosconspub | Cosmos Consensus Public Key | +| cosmosval | Cosmos Validator Operator Address | +| cosmosvalpub | Cosmos Validator Operator Public Key | ## Encoding -While all user facing interfaces to Cosmos software should exposed bech32 interfaces, many internal interfaces encode binary value in hex or base64 encoded form. +While all user facing interfaces to Cosmos software should exposed Bech32 interfaces, many internal interfaces encode binary value in hex or base64 encoded form. -To covert between other binary reprsentation of addresses and keys, it is important to first apply the Amino enocoding process before bech32 encoding. +To covert between other binary representation of addresses and keys, it is important to first apply the Amino encoding process before bech32 encoding. -A complete implementation of the Amino serialization format is unncessary in most cases. Simply prepending bytes from this [table](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography) to the bytestring payload before bech32 encoding will sufficient for compatible representation. - -  +A complete implementation of the Amino serialization format is unnecessary in most cases. Simply prepending bytes from this [table](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography) to the byte string payload before bech32 encoding will sufficient for compatible representation. diff --git a/docs/validators/validator-faq.md b/docs/validators/validator-faq.md index 6018ac3233..470f139d43 100644 --- a/docs/validators/validator-faq.md +++ b/docs/validators/validator-faq.md @@ -77,13 +77,14 @@ We view testnet participation as a great way to signal to the community that you In short, there are two types of keys: -- **Tendermint Key**: This is a unique key used to sign block hashes. It is associated with a public key `cosmosvalpub`. - + Generated when the node is created with gaiad init. - + Get this value with gaiad tendermint show_validator - +M e.g. cosmosvalpub1zcjduc3qcyj09qc03elte23zwshdx92jm6ce88fgc90rtqhjx8v0608qh5ssp0w94c - -- **Application keys**: These keys are created from the application and used to sign transactions. As a validator, you will probably use one key to sign staking-related transactions, and another key to sign governance-related transactions. Application keys are associated with a public key `cosmosaccpub` and an address `cosmosaccaddr`. Both are derived from account keys generated by `gaiacli keys add`. +* **Tendermint Key**: This is a unique key used to sign block hashes. It is associated with a public key `cosmosconspub`. + * Generated when the node is created with gaiad init. + * Get this value with `gaiad tendermint show-validator` + e.g. `cosmosconspub1zcjduc3qcyj09qc03elte23zwshdx92jm6ce88fgc90rtqhjx8v0608qh5ssp0w94c` +* **Application keys**: These keys are created from the application and used to sign transactions. As a validator, you will probably use one key to sign staking-related transactions, and another key to sign governance-related transactions. Application keys are associated with a public key `cosmospub` and an address `cosmos`. Both are derived from account keys generated by `gaiacli keys add`. + * Note: A validator's operator key is directly tied to an application key, but + uses reserved prefixes solely for this purpose: `cosmosval` and `cosmosvalpub` ### What are the different states a validator can be in? diff --git a/docs/validators/validator-setup.md b/docs/validators/validator-setup.md index 6fa4fefd21..8bf3e951de 100644 --- a/docs/validators/validator-setup.md +++ b/docs/validators/validator-setup.md @@ -16,7 +16,7 @@ If you want to become a validator for the Hub's `mainnet`, you should [research ### Create Your Validator -Your `cosmosvalpub` can be used to create a new validator by staking tokens. You can find your validator pubkey by running: +Your `cosmosconspub` can be used to create a new validator by staking tokens. You can find your validator pubkey by running: ```bash gaiad tendermint show-validator @@ -32,7 +32,7 @@ Don't use more `steak` thank you have! You can always get more by using the [Fau gaiacli stake create-validator \ --amount=5steak \ --pubkey=$(gaiad tendermint show-validator) \ - --address-validator=<account_cosmosaccaddr> + --address-validator=<account_cosmosval> --moniker="choose a moniker" \ --chain-id=<chain_id> \ --name=<key_name> @@ -46,7 +46,7 @@ The `--identity` can be used as to verify identity with systems like Keybase or ```bash gaiacli stake edit-validator - --validator=<account_cosmosaccaddr> + --validator=<account_cosmos> --moniker="choose a moniker" \ --website="https://cosmos.network" \ --identity=6A0D65E29A4CBC8E @@ -60,7 +60,7 @@ gaiacli stake edit-validator View the validator's information with this command: ```bash -gaiacli stake validator <account_cosmosaccaddr> +gaiacli stake validator <account_cosmos> ``` ### Track Validator Signing Information @@ -80,7 +80,7 @@ When a validator is "jailed" for downtime, you must submit an `Unjail` transacti gaiacli stake unjail \ --from=<key_name> \ --chain-id=<chain_id> - --validator=<account_cosmosaccaddr> \ + --validator=<account_cosmosval> \ --chain-id=gaia-6002 ``` @@ -110,10 +110,10 @@ Here's how you can return the voting power back to your validator. First, if `ga gaiad start ``` -Wait for your full node to catch up to the latest block. Next, run the following command. Note that `<cosmosaccaddr>` is the address of your validator account, and `<name>` is the name of the validator account. You can find this info by running `gaiacli keys list`. +Wait for your full node to catch up to the latest block. Next, run the following command. Note that `<cosmos>` is the address of your validator account, and `<name>` is the name of the validator account. You can find this info by running `gaiacli keys list`. ```bash -gaiacli stake unjail <cosmosaccaddr> --chain-id=<chain_id> --name=<name> +gaiacli stake unjail <cosmos> --chain-id=<chain_id> --name=<name> ``` ::: danger Warning diff --git a/examples/README.md b/examples/README.md index d12e3d3fcc..11aef9d280 100644 --- a/examples/README.md +++ b/examples/README.md @@ -103,10 +103,10 @@ basecli keys list You should now see alice, bob and charlie's account all show up. ``` -NAME: ADDRESS: PUBKEY: -alice cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f cosmosaccpub1addwnpepq0w037u5g7y7lvdvsred2dehg90j84k0weyss5ynysf0nnnax74agrsxns6 -bob cosmosaccaddr18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz cosmosaccpub1addwnpepqwe97n8lryxrzvamrvjfj24jys3uzf8wndfvqa2l7mh5nsv4jrvdznvyeg6 -charlie cosmosaccaddr13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q cosmosaccpub1addwnpepqdmtxv35rrmv2dvcr3yhfyxj7dzrd4z4rnhmclksq4g55a4wpl54clvx33l +NAME: ADDRESS: PUBKEY: +alice cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f cosmospub1addwnpepq0w037u5g7y7lvdvsred2dehg90j84k0weyss5ynysf0nnnax74agrsxns6 +bob cosmos18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz cosmospub1addwnpepqwe97n8lryxrzvamrvjfj24jys3uzf8wndfvqa2l7mh5nsv4jrvdznvyeg6 +charlie cosmos13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q cosmospub1addwnpepqdmtxv35rrmv2dvcr3yhfyxj7dzrd4z4rnhmclksq4g55a4wpl54clvx33l ``` @@ -115,15 +115,15 @@ charlie cosmosaccaddr13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q cosmosaccpub1addwnp Lets send bob and charlie some tokens. First, lets query alice's account so we can see what kind of tokens she has: ``` -basecli account cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f +basecli account cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f ``` -Where `cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f` is alice's address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search for bob's or charlie's address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some! +Where `cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f` is alice's address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search for bob's or charlie's address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some! The following command will send coins from alice, to bob: ``` -basecli send --from=alice --amount=10000mycoin --to=cosmosaccaddr18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz +basecli send --from=alice --amount=10000mycoin --to=cosmos18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz --sequence=0 --chain-id=test-chain-AE4XQo ``` @@ -136,13 +136,13 @@ Flag Descriptions: Now if we check bobs account, it should have `10000 mycoin`. You can do so by running : ``` -basecli account cosmosaccaddr18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz +basecli account cosmos18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz ``` Now lets send some from bob to charlie. Make sure you send less than bob has, otherwise the transaction will fail: ``` -basecli send --from=bob --amount=5000mycoin --to=cosmosaccaddr13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q +basecli send --from=bob --amount=5000mycoin --to=cosmos13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q --sequence=0 --chain-id=test-chain-AE4XQo ``` @@ -151,7 +151,7 @@ Note how we use the ``--from`` flag to select a different account to send from. Lets now try to send from bob back to alice: ``` -basecli send --from=bob --amount=3000mycoin --to=cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f +basecli send --from=bob --amount=3000mycoin --to=cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f --sequence=1 --chain-id=test-chain-AE4XQo ``` diff --git a/examples/democoin/mock/validator.go b/examples/democoin/mock/validator.go index bb936097cc..f937e45dcc 100644 --- a/examples/democoin/mock/validator.go +++ b/examples/democoin/mock/validator.go @@ -9,7 +9,7 @@ import ( // Validator implements sdk.Validator type Validator struct { - Address sdk.AccAddress + Address sdk.ValAddress Power sdk.Dec } @@ -19,7 +19,7 @@ func (v Validator) GetStatus() sdk.BondStatus { } // Implements sdk.Validator -func (v Validator) GetOperator() sdk.AccAddress { +func (v Validator) GetOperator() sdk.ValAddress { return v.Address } @@ -78,9 +78,9 @@ func (vs *ValidatorSet) IterateValidatorsBonded(ctx sdk.Context, fn func(index i } // Validator implements sdk.ValidatorSet -func (vs *ValidatorSet) Validator(ctx sdk.Context, addr sdk.AccAddress) sdk.Validator { +func (vs *ValidatorSet) Validator(ctx sdk.Context, addr sdk.ValAddress) sdk.Validator { for _, val := range vs.Validators { - if bytes.Equal(val.Address, addr) { + if bytes.Equal(val.Address.Bytes(), addr.Bytes()) { return val } } diff --git a/examples/democoin/x/assoc/validator_set.go b/examples/democoin/x/assoc/validator_set.go index ad89aab192..8a954c7203 100644 --- a/examples/democoin/x/assoc/validator_set.go +++ b/examples/democoin/x/assoc/validator_set.go @@ -37,7 +37,7 @@ func NewValidatorSet(cdc *wire.Codec, store sdk.KVStore, valset sdk.ValidatorSet } // Implements sdk.ValidatorSet -func (valset ValidatorSet) Validator(ctx sdk.Context, addr sdk.AccAddress) (res sdk.Validator) { +func (valset ValidatorSet) Validator(ctx sdk.Context, addr sdk.ValAddress) (res sdk.Validator) { base := valset.store.Get(GetBaseKey(addr)) res = valset.ValidatorSet.Validator(ctx, base) if res == nil { @@ -46,23 +46,23 @@ func (valset ValidatorSet) Validator(ctx sdk.Context, addr sdk.AccAddress) (res return } -// GetBaseKey :: sdk.AccAddress -> sdk.AccAddress -func GetBaseKey(addr sdk.AccAddress) []byte { +// GetBaseKey :: sdk.ValAddress -> sdk.ValAddress +func GetBaseKey(addr sdk.ValAddress) []byte { return append([]byte{0x00}, addr...) } -// GetAssocPrefix :: sdk.AccAddress -> (sdk.AccAddress -> byte) -func GetAssocPrefix(base sdk.AccAddress) []byte { +// GetAssocPrefix :: sdk.ValAddress -> (sdk.ValAddress -> byte) +func GetAssocPrefix(base sdk.ValAddress) []byte { return append([]byte{0x01}, base...) } -// GetAssocKey :: (sdk.AccAddress, sdk.AccAddress) -> byte -func GetAssocKey(base sdk.AccAddress, assoc sdk.AccAddress) []byte { +// GetAssocKey :: (sdk.ValAddress, sdk.ValAddress) -> byte +func GetAssocKey(base sdk.ValAddress, assoc sdk.ValAddress) []byte { return append(append([]byte{0x01}, base...), assoc...) } // Associate associates new address with validator address -func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.AccAddress, assoc sdk.AccAddress) bool { +func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool { if len(base) != valset.addrLen || len(assoc) != valset.addrLen { return false } @@ -76,7 +76,7 @@ func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.AccAddress, assoc } // Dissociate removes association between addresses -func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.AccAddress, assoc sdk.AccAddress) bool { +func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool { if len(base) != valset.addrLen || len(assoc) != valset.addrLen { return false } @@ -90,8 +90,8 @@ func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.AccAddress, asso } // Associations returns all associated addresses with a validator -func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.AccAddress) (res []sdk.AccAddress) { - res = make([]sdk.AccAddress, valset.maxAssoc) +func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.ValAddress) (res []sdk.ValAddress) { + res = make([]sdk.ValAddress, valset.maxAssoc) iter := sdk.KVStorePrefixIterator(valset.store, GetAssocPrefix(base)) defer iter.Close() i := 0 diff --git a/examples/democoin/x/oracle/handler.go b/examples/democoin/x/oracle/handler.go index 1aaefc7e16..c525222c4c 100644 --- a/examples/democoin/x/oracle/handler.go +++ b/examples/democoin/x/oracle/handler.go @@ -68,8 +68,8 @@ func (keeper Keeper) Handle(h Handler, ctx sdk.Context, o Msg, codespace sdk.Cod } info.LastSigned = ctx.BlockHeight() - // Check the signer is a validater - val := valset.Validator(ctx, signer) + // check the signer is a validator + val := valset.Validator(ctx, sdk.ValAddress(signer)) if val == nil { return ErrNotValidator(codespace, signer).Result() } diff --git a/examples/democoin/x/pow/types_test.go b/examples/democoin/x/pow/types_test.go index be848d9408..dbe6ad35e9 100644 --- a/examples/democoin/x/pow/types_test.go +++ b/examples/democoin/x/pow/types_test.go @@ -55,14 +55,14 @@ func TestMsgMineString(t *testing.T) { addr := sdk.AccAddress([]byte("sender")) msg := MsgMine{addr, 0, 0, 0, []byte("abc")} res := msg.String() - require.Equal(t, res, "MsgMine{Sender: cosmosaccaddr1wdjkuer9wg4wml9c, Difficulty: 0, Count: 0, Nonce: 0, Proof: abc}") + require.Equal(t, res, "MsgMine{Sender: cosmos1wdjkuer9wgh76ts6, Difficulty: 0, Count: 0, Nonce: 0, Proof: abc}") } func TestMsgMineGetSignBytes(t *testing.T) { addr := sdk.AccAddress([]byte("sender")) msg := MsgMine{addr, 1, 1, 1, []byte("abc")} res := msg.GetSignBytes() - require.Equal(t, string(res), `{"count":1,"difficulty":1,"nonce":1,"proof":"YWJj","sender":"cosmosaccaddr1wdjkuer9wg4wml9c"}`) + require.Equal(t, string(res), `{"count":1,"difficulty":1,"nonce":1,"proof":"YWJj","sender":"cosmos1wdjkuer9wgh76ts6"}`) } func TestMsgMineGetSigners(t *testing.T) { diff --git a/server/tm_cmds.go b/server/tm_cmds.go index d84022183a..b6daf07753 100644 --- a/server/tm_cmds.go +++ b/server/tm_cmds.go @@ -45,10 +45,12 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command { if viper.GetBool(client.FlagJson) { return printlnJSON(valPubKey) } - pubkey, err := sdk.Bech32ifyValPub(valPubKey) + + pubkey, err := sdk.Bech32ifyConsPub(valPubKey) if err != nil { return err } + fmt.Println(pubkey) return nil }, diff --git a/types/account.go b/types/account.go index 00076b5299..1df600c36e 100644 --- a/types/account.go +++ b/types/account.go @@ -13,251 +13,422 @@ import ( "github.com/tendermint/tendermint/libs/bech32" ) -// Bech32 prefixes const ( - // expected address length + // AddrLen defines a valid address length AddrLen = 20 - // Bech32 prefixes - Bech32PrefixAccAddr = "cosmosaccaddr" - Bech32PrefixAccPub = "cosmosaccpub" - Bech32PrefixValAddr = "cosmosvaladdr" - Bech32PrefixValPub = "cosmosvalpub" + // Bech32PrefixAccAddr defines the Bech32 prefix of an account's address + Bech32PrefixAccAddr = "cosmos" + // Bech32PrefixAccPub defines the Bech32 prefix of an account's public key + Bech32PrefixAccPub = "cosmospub" + // Bech32PrefixValAddr defines the Bech32 prefix of a validator's operator address + Bech32PrefixValAddr = "cosmosval" + // Bech32PrefixValPub defines the Bech32 prefix of a validator's operator public key + Bech32PrefixValPub = "cosmosvalpub" + // Bech32PrefixConsAddr defines the Bech32 prefix of a consensus node address + Bech32PrefixConsAddr = "cosmoscons" + // Bech32PrefixConsPub defines the Bech32 prefix of a consensus node public key + Bech32PrefixConsPub = "cosmosconspub" ) -//__________________________________________________________ +// ---------------------------------------------------------------------------- +// account +// ---------------------------------------------------------------------------- -// AccAddress a wrapper around bytes meant to represent an account address -// When marshaled to a string or json, it uses bech32 +// AccAddress a wrapper around bytes meant to represent an account address. +// When marshaled to a string or JSON, it uses Bech32. type AccAddress []byte -// create an AccAddress from a hex string +// AccAddressFromHex creates an AccAddress from a hex string. func AccAddressFromHex(address string) (addr AccAddress, err error) { if len(address) == 0 { - return addr, errors.New("decoding bech32 address failed: must provide an address") + return addr, errors.New("decoding Bech32 address failed: must provide an address") } + bz, err := hex.DecodeString(address) if err != nil { return nil, err } + return AccAddress(bz), nil } -// create an AccAddress from a bech32 string +// AccAddressFromBech32 creates an AccAddress from a Bech32 string. func AccAddressFromBech32(address string) (addr AccAddress, err error) { bz, err := GetFromBech32(address, Bech32PrefixAccAddr) if err != nil { return nil, err } + return AccAddress(bz), nil } -// Marshal needed for protobuf compatibility -func (bz AccAddress) Marshal() ([]byte, error) { - return bz, nil +// Returns boolean for whether two AccAddresses are Equal +func (aa AccAddress) Equals(aa2 AccAddress) bool { + if aa.Empty() && aa2.Empty() { + return true + } + + return bytes.Compare(aa.Bytes(), aa2.Bytes()) == 0 } -// Unmarshal needed for protobuf compatibility -func (bz *AccAddress) Unmarshal(data []byte) error { - *bz = data +// Returns boolean for whether an AccAddress is empty +func (aa AccAddress) Empty() bool { + if aa == nil { + return true + } + + aa2 := AccAddress{} + return bytes.Compare(aa.Bytes(), aa2.Bytes()) == 0 +} + +// Marshal returns the raw address bytes. It is needed for protobuf +// compatibility. +func (aa AccAddress) Marshal() ([]byte, error) { + return aa, nil +} + +// Unmarshal sets the address to the given data. It is needed for protobuf +// compatibility. +func (aa *AccAddress) Unmarshal(data []byte) error { + *aa = data return nil } -// Marshals to JSON using Bech32 -func (bz AccAddress) MarshalJSON() ([]byte, error) { - return json.Marshal(bz.String()) +// MarshalJSON marshals to JSON using Bech32. +func (aa AccAddress) MarshalJSON() ([]byte, error) { + return json.Marshal(aa.String()) } -// Unmarshals from JSON assuming Bech32 encoding -func (bz *AccAddress) UnmarshalJSON(data []byte) error { +// UnmarshalJSON unmarshals from JSON assuming Bech32 encoding. +func (aa *AccAddress) UnmarshalJSON(data []byte) error { var s string err := json.Unmarshal(data, &s) if err != nil { return nil } - bz2, err := AccAddressFromBech32(s) + aa2, err := AccAddressFromBech32(s) if err != nil { return err } - *bz = bz2 + + *aa = aa2 return nil } -// Allow it to fulfill various interfaces in light-client, etc... -func (bz AccAddress) Bytes() []byte { - return bz +// Bytes returns the raw address bytes. +func (aa AccAddress) Bytes() []byte { + return aa } -func (bz AccAddress) String() string { - bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixAccAddr, bz.Bytes()) +// String implements the Stringer interface. +func (aa AccAddress) String() string { + bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixAccAddr, aa.Bytes()) if err != nil { panic(err) } + return bech32Addr } -// For Printf / Sprintf, returns bech32 when using %s -func (bz AccAddress) Format(s fmt.State, verb rune) { +// Format implements the fmt.Formatter interface. +func (aa AccAddress) Format(s fmt.State, verb rune) { switch verb { case 's': - s.Write([]byte(fmt.Sprintf("%s", bz.String()))) + s.Write([]byte(fmt.Sprintf("%s", aa.String()))) case 'p': - s.Write([]byte(fmt.Sprintf("%p", bz))) + s.Write([]byte(fmt.Sprintf("%p", aa))) default: - s.Write([]byte(fmt.Sprintf("%X", []byte(bz)))) + s.Write([]byte(fmt.Sprintf("%X", []byte(aa)))) } } -// Returns boolean for whether two AccAddresses are Equal -func (bz AccAddress) Equals(bz2 AccAddress) bool { - if bz.Empty() && bz2.Empty() { - return true - } - return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0 -} +// ---------------------------------------------------------------------------- +// validator owner +// ---------------------------------------------------------------------------- -// Returns boolean for whether an AccAddress is empty -func (bz AccAddress) Empty() bool { - if bz == nil { - return true - } - bz2 := AccAddress{} - return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0 -} - -//__________________________________________________________ - -// AccAddress a wrapper around bytes meant to represent a validator address -// (from over ABCI). When marshaled to a string or json, it uses bech32 +// ValAddress defines a wrapper around bytes meant to present a validator's +// operator. When marshaled to a string or JSON, it uses Bech32. type ValAddress []byte -// create a ValAddress from a hex string +// ValAddressFromHex creates a ValAddress from a hex string. func ValAddressFromHex(address string) (addr ValAddress, err error) { if len(address) == 0 { - return addr, errors.New("decoding bech32 address failed: must provide an address") + return addr, errors.New("decoding Bech32 address failed: must provide an address") } + bz, err := hex.DecodeString(address) if err != nil { return nil, err } + return ValAddress(bz), nil } -// create a ValAddress from a bech32 string +// ValAddressFromBech32 creates a ValAddress from a Bech32 string. func ValAddressFromBech32(address string) (addr ValAddress, err error) { bz, err := GetFromBech32(address, Bech32PrefixValAddr) if err != nil { return nil, err } + return ValAddress(bz), nil } -// Marshal needed for protobuf compatibility -func (bz ValAddress) Marshal() ([]byte, error) { - return bz, nil +// Returns boolean for whether two ValAddresses are Equal +func (va ValAddress) Equals(va2 ValAddress) bool { + if va.Empty() && va2.Empty() { + return true + } + + return bytes.Compare(va.Bytes(), va2.Bytes()) == 0 } -// Unmarshal needed for protobuf compatibility -func (bz *ValAddress) Unmarshal(data []byte) error { - *bz = data +// Returns boolean for whether an AccAddress is empty +func (va ValAddress) Empty() bool { + if va == nil { + return true + } + + va2 := ValAddress{} + return bytes.Compare(va.Bytes(), va2.Bytes()) == 0 +} + +// Marshal returns the raw address bytes. It is needed for protobuf +// compatibility. +func (va ValAddress) Marshal() ([]byte, error) { + return va, nil +} + +// Unmarshal sets the address to the given data. It is needed for protobuf +// compatibility. +func (va *ValAddress) Unmarshal(data []byte) error { + *va = data return nil } -// Marshals to JSON using Bech32 -func (bz ValAddress) MarshalJSON() ([]byte, error) { - return json.Marshal(bz.String()) +// MarshalJSON marshals to JSON using Bech32. +func (va ValAddress) MarshalJSON() ([]byte, error) { + return json.Marshal(va.String()) } -// Unmarshals from JSON assuming Bech32 encoding -func (bz *ValAddress) UnmarshalJSON(data []byte) error { +// UnmarshalJSON unmarshals from JSON assuming Bech32 encoding. +func (va *ValAddress) UnmarshalJSON(data []byte) error { var s string + err := json.Unmarshal(data, &s) if err != nil { return nil } - bz2, err := ValAddressFromBech32(s) + va2, err := ValAddressFromBech32(s) if err != nil { return err } - *bz = bz2 + + *va = va2 return nil } -// Allow it to fulfill various interfaces in light-client, etc... -func (bz ValAddress) Bytes() []byte { - return bz +// Bytes returns the raw address bytes. +func (va ValAddress) Bytes() []byte { + return va } -func (bz ValAddress) String() string { - bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixValAddr, bz.Bytes()) +// String implements the Stringer interface. +func (va ValAddress) String() string { + bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixValAddr, va.Bytes()) if err != nil { panic(err) } + return bech32Addr } -// For Printf / Sprintf, returns bech32 when using %s -func (bz ValAddress) Format(s fmt.State, verb rune) { +// Format implements the fmt.Formatter interface. +func (va ValAddress) Format(s fmt.State, verb rune) { switch verb { case 's': - s.Write([]byte(fmt.Sprintf("%s", bz.String()))) + s.Write([]byte(fmt.Sprintf("%s", va.String()))) case 'p': - s.Write([]byte(fmt.Sprintf("%p", bz))) + s.Write([]byte(fmt.Sprintf("%p", va))) default: - s.Write([]byte(fmt.Sprintf("%X", []byte(bz)))) + s.Write([]byte(fmt.Sprintf("%X", []byte(va)))) } } -// Returns boolean for whether two ValAddresses are Equal -func (bz ValAddress) Equals(bz2 ValAddress) bool { - if bz.Empty() && bz2.Empty() { +// ---------------------------------------------------------------------------- +// consensus node +// ---------------------------------------------------------------------------- + +// ConsAddress defines a wrapper around bytes meant to present a consensus node. +// When marshaled to a string or JSON, it uses Bech32. +type ConsAddress []byte + +// ConsAddressFromHex creates a ConsAddress from a hex string. +func ConsAddressFromHex(address string) (addr ConsAddress, err error) { + if len(address) == 0 { + return addr, errors.New("decoding Bech32 address failed: must provide an address") + } + + bz, err := hex.DecodeString(address) + if err != nil { + return nil, err + } + + return ConsAddress(bz), nil +} + +// ConsAddressFromBech32 creates a ConsAddress from a Bech32 string. +func ConsAddressFromBech32(address string) (addr ConsAddress, err error) { + bz, err := GetFromBech32(address, Bech32PrefixConsAddr) + if err != nil { + return nil, err + } + + return ConsAddress(bz), nil +} + +// Returns boolean for whether two ConsAddress are Equal +func (ca ConsAddress) Equals(ca2 ConsAddress) bool { + if ca.Empty() && ca2.Empty() { return true } - return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0 + + return bytes.Compare(ca.Bytes(), ca2.Bytes()) == 0 } -// Returns boolean for whether an AccAddress is empty -func (bz ValAddress) Empty() bool { - if bz == nil { +// Returns boolean for whether an ConsAddress is empty +func (ca ConsAddress) Empty() bool { + if ca == nil { return true } - bz2 := ValAddress{} - return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0 + + ca2 := ConsAddress{} + return bytes.Compare(ca.Bytes(), ca2.Bytes()) == 0 } -// Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string +// Marshal returns the raw address bytes. It is needed for protobuf +// compatibility. +func (ca ConsAddress) Marshal() ([]byte, error) { + return ca, nil +} + +// Unmarshal sets the address to the given data. It is needed for protobuf +// compatibility. +func (ca *ConsAddress) Unmarshal(data []byte) error { + *ca = data + return nil +} + +// MarshalJSON marshals to JSON using Bech32. +func (ca ConsAddress) MarshalJSON() ([]byte, error) { + return json.Marshal(ca.String()) +} + +// UnmarshalJSON unmarshals from JSON assuming Bech32 encoding. +func (ca *ConsAddress) UnmarshalJSON(data []byte) error { + var s string + + err := json.Unmarshal(data, &s) + if err != nil { + return nil + } + + ca2, err := ConsAddressFromBech32(s) + if err != nil { + return err + } + + *ca = ca2 + return nil +} + +// Bytes returns the raw address bytes. +func (ca ConsAddress) Bytes() []byte { + return ca +} + +// String implements the Stringer interface. +func (ca ConsAddress) String() string { + bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixConsAddr, ca.Bytes()) + if err != nil { + panic(err) + } + + return bech32Addr +} + +// Format implements the fmt.Formatter interface. +func (ca ConsAddress) Format(s fmt.State, verb rune) { + switch verb { + case 's': + s.Write([]byte(fmt.Sprintf("%s", ca.String()))) + case 'p': + s.Write([]byte(fmt.Sprintf("%p", ca))) + default: + s.Write([]byte(fmt.Sprintf("%X", []byte(ca)))) + } +} + +// ---------------------------------------------------------------------------- +// auxiliary +// ---------------------------------------------------------------------------- + +// Bech32ifyAccPub returns a Bech32 encoded string containing the +// Bech32PrefixAccPub prefix for a given account PubKey. func Bech32ifyAccPub(pub crypto.PubKey) (string, error) { return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes()) } -// MustBech32ifyAccPub panics on bech32-encoding failure +// MustBech32ifyAccPub returns the result of Bech32ifyAccPub panicing on failure. func MustBech32ifyAccPub(pub crypto.PubKey) string { enc, err := Bech32ifyAccPub(pub) if err != nil { panic(err) } + return enc } -// Bech32ifyValPub returns the bech32 encoded string for a validator pubkey +// Bech32ifyValPub returns a Bech32 encoded string containing the +// Bech32PrefixValPub prefix for a given validator operator's PubKey. func Bech32ifyValPub(pub crypto.PubKey) (string, error) { return bech32.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes()) } -// MustBech32ifyValPub panics on bech32-encoding failure +// MustBech32ifyValPub returns the result of Bech32ifyValPub panicing on failure. func MustBech32ifyValPub(pub crypto.PubKey) string { enc, err := Bech32ifyValPub(pub) if err != nil { panic(err) } + return enc } -// create a Pubkey from a string -func GetAccPubKeyBech32(address string) (pk crypto.PubKey, err error) { - bz, err := GetFromBech32(address, Bech32PrefixAccPub) +// Bech32ifyConsPub returns a Bech32 encoded string containing the +// Bech32PrefixConsPub prefixfor a given consensus node's PubKey. +func Bech32ifyConsPub(pub crypto.PubKey) (string, error) { + return bech32.ConvertAndEncode(Bech32PrefixConsPub, pub.Bytes()) +} + +// MustBech32ifyConsPub returns the result of Bech32ifyConsPub panicing on +// failure. +func MustBech32ifyConsPub(pub crypto.PubKey) string { + enc, err := Bech32ifyConsPub(pub) + if err != nil { + panic(err) + } + + return enc +} + +// GetAccPubKeyBech32 creates a PubKey for an account with a given public key +// string using the Bech32 Bech32PrefixAccPub prefix. +func GetAccPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) { + bz, err := GetFromBech32(pubkey, Bech32PrefixAccPub) if err != nil { return nil, err } @@ -270,16 +441,19 @@ func GetAccPubKeyBech32(address string) (pk crypto.PubKey, err error) { return pk, nil } -// create an Pubkey from a string, panics on error -func MustGetAccPubKeyBech32(address string) (pk crypto.PubKey) { - pk, err := GetAccPubKeyBech32(address) +// MustGetAccPubKeyBech32 returns the result of GetAccPubKeyBech32 panicing on +// failure. +func MustGetAccPubKeyBech32(pubkey string) (pk crypto.PubKey) { + pk, err := GetAccPubKeyBech32(pubkey) if err != nil { panic(err) } + return pk } -// decode a validator public key into a PubKey +// GetValPubKeyBech32 creates a PubKey for a validator's operator with a given +// public key string using the Bech32 Bech32PrefixValPub prefix. func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) { bz, err := GetFromBech32(pubkey, Bech32PrefixValPub) if err != nil { @@ -294,27 +468,57 @@ func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) { return pk, nil } -// create an Pubkey from a string, panics on error -func MustGetValPubKeyBech32(address string) (pk crypto.PubKey) { - pk, err := GetValPubKeyBech32(address) +// MustGetValPubKeyBech32 returns the result of GetValPubKeyBech32 panicing on +// failure. +func MustGetValPubKeyBech32(pubkey string) (pk crypto.PubKey) { + pk, err := GetValPubKeyBech32(pubkey) if err != nil { panic(err) } + return pk } -// decode a bytestring from a bech32-encoded string +// GetConsPubKeyBech32 creates a PubKey for a consensus node with a given public +// key string using the Bech32 Bech32PrefixConsPub prefix. +func GetConsPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) { + bz, err := GetFromBech32(pubkey, Bech32PrefixConsPub) + if err != nil { + return nil, err + } + + pk, err = cryptoAmino.PubKeyFromBytes(bz) + if err != nil { + return nil, err + } + + return pk, nil +} + +// MustGetConsPubKeyBech32 returns the result of GetConsPubKeyBech32 panicing on +// failure. +func MustGetConsPubKeyBech32(pubkey string) (pk crypto.PubKey) { + pk, err := GetConsPubKeyBech32(pubkey) + if err != nil { + panic(err) + } + + return pk +} + +// GetFromBech32 decodes a bytestring from a Bech32 encoded string. func GetFromBech32(bech32str, prefix string) ([]byte, error) { if len(bech32str) == 0 { - return nil, errors.New("decoding bech32 address failed: must provide an address") + return nil, errors.New("decoding Bech32 address failed: must provide an address") } + hrp, bz, err := bech32.DecodeAndConvert(bech32str) if err != nil { return nil, err } if hrp != prefix { - return nil, fmt.Errorf("invalid bech32 prefix. Expected %s, Got %s", prefix, hrp) + return nil, fmt.Errorf("invalid Bech32 prefix; expected %s, got %s", prefix, hrp) } return bz, nil diff --git a/types/account_test.go b/types/account_test.go index aa222ee7e9..e2ec36876c 100644 --- a/types/account_test.go +++ b/types/account_test.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/types" ) -var invalidstrs = []string{ +var invalidStrs = []string{ "", "hello, world!", "0xAA", @@ -21,6 +21,8 @@ var invalidstrs = []string{ types.Bech32PrefixAccPub + "1234", types.Bech32PrefixValAddr + "5678", types.Bech32PrefixValPub + "BBAB", + types.Bech32PrefixConsAddr + "FF04", + types.Bech32PrefixConsPub + "6789", } func testMarshal(t *testing.T, original interface{}, res interface{}, marshal func() ([]byte, error), unmarshal func([]byte) error) { @@ -37,27 +39,38 @@ func TestRandBech32PubkeyConsistency(t *testing.T) { for i := 0; i < 1000; i++ { rand.Read(pub[:]) - mustbech32accpub := types.MustBech32ifyAccPub(pub) - bech32accpub, err := types.Bech32ifyAccPub(pub) + mustBech32AccPub := types.MustBech32ifyAccPub(pub) + bech32AccPub, err := types.Bech32ifyAccPub(pub) require.Nil(t, err) - require.Equal(t, bech32accpub, mustbech32accpub) + require.Equal(t, bech32AccPub, mustBech32AccPub) - mustbech32valpub := types.MustBech32ifyValPub(pub) - bech32valpub, err := types.Bech32ifyValPub(pub) + mustBech32ValPub := types.MustBech32ifyValPub(pub) + bech32ValPub, err := types.Bech32ifyValPub(pub) require.Nil(t, err) - require.Equal(t, bech32valpub, mustbech32valpub) + require.Equal(t, bech32ValPub, mustBech32ValPub) - mustaccpub := types.MustGetAccPubKeyBech32(bech32accpub) - accpub, err := types.GetAccPubKeyBech32(bech32accpub) + mustBech32ConsPub := types.MustBech32ifyConsPub(pub) + bech32ConsPub, err := types.Bech32ifyConsPub(pub) require.Nil(t, err) - require.Equal(t, accpub, mustaccpub) + require.Equal(t, bech32ConsPub, mustBech32ConsPub) - mustvalpub := types.MustGetValPubKeyBech32(bech32valpub) - valpub, err := types.GetValPubKeyBech32(bech32valpub) + mustAccPub := types.MustGetAccPubKeyBech32(bech32AccPub) + accPub, err := types.GetAccPubKeyBech32(bech32AccPub) require.Nil(t, err) - require.Equal(t, valpub, mustvalpub) + require.Equal(t, accPub, mustAccPub) - require.Equal(t, valpub, accpub) + mustValPub := types.MustGetValPubKeyBech32(bech32ValPub) + valPub, err := types.GetValPubKeyBech32(bech32ValPub) + require.Nil(t, err) + require.Equal(t, valPub, mustValPub) + + mustConsPub := types.MustGetConsPubKeyBech32(bech32ConsPub) + consPub, err := types.GetConsPubKeyBech32(bech32ConsPub) + require.Nil(t, err) + require.Equal(t, consPub, mustConsPub) + + require.Equal(t, valPub, accPub) + require.Equal(t, valPub, consPub) } } @@ -84,7 +97,7 @@ func TestRandBech32AccAddrConsistency(t *testing.T) { require.Equal(t, acc, res) } - for _, str := range invalidstrs { + for _, str := range invalidStrs { _, err := types.AccAddressFromHex(str) require.NotNil(t, err) @@ -119,7 +132,7 @@ func TestValAddr(t *testing.T) { require.Equal(t, acc, res) } - for _, str := range invalidstrs { + for _, str := range invalidStrs { _, err := types.ValAddressFromHex(str) require.NotNil(t, err) @@ -130,3 +143,38 @@ func TestValAddr(t *testing.T) { require.NotNil(t, err) } } + +func TestConsAddress(t *testing.T) { + var pub ed25519.PubKeyEd25519 + + for i := 0; i < 20; i++ { + rand.Read(pub[:]) + + acc := types.ConsAddress(pub.Address()) + res := types.ConsAddress{} + + testMarshal(t, &acc, &res, acc.MarshalJSON, (&res).UnmarshalJSON) + testMarshal(t, &acc, &res, acc.Marshal, (&res).Unmarshal) + + str := acc.String() + res, err := types.ConsAddressFromBech32(str) + require.Nil(t, err) + require.Equal(t, acc, res) + + str = hex.EncodeToString(acc) + res, err = types.ConsAddressFromHex(str) + require.Nil(t, err) + require.Equal(t, acc, res) + } + + for _, str := range invalidStrs { + _, err := types.ConsAddressFromHex(str) + require.NotNil(t, err) + + _, err = types.ConsAddressFromBech32(str) + require.NotNil(t, err) + + err = (*types.ConsAddress)(nil).UnmarshalJSON([]byte("\"" + str + "\"")) + require.NotNil(t, err) + } +} diff --git a/types/stake.go b/types/stake.go index d872277256..f411251775 100644 --- a/types/stake.go +++ b/types/stake.go @@ -40,7 +40,7 @@ type Validator interface { GetJailed() bool // whether the validator is jailed GetMoniker() string // moniker of the validator GetStatus() BondStatus // status of the validator - GetOperator() AccAddress // owner AccAddress to receive/return validators coins + GetOperator() ValAddress // owner address to receive/return validators coins GetPubKey() crypto.PubKey // validation pubkey GetPower() Dec // validation power GetTokens() Dec // validation tokens @@ -67,7 +67,7 @@ type ValidatorSet interface { IterateValidatorsBonded(Context, func(index int64, validator Validator) (stop bool)) - Validator(Context, AccAddress) Validator // get a particular validator by owner AccAddress + Validator(Context, ValAddress) Validator // get a particular validator by operator ValidatorByPubKey(Context, crypto.PubKey) Validator // get a particular validator by signing PubKey TotalPower(Context) Dec // total power of the validator set @@ -82,7 +82,7 @@ type ValidatorSet interface { // delegation bond for a delegated proof of stake system type Delegation interface { GetDelegator() AccAddress // delegator AccAddress for the bond - GetValidator() AccAddress // validator owner AccAddress for the bond + GetValidator() ValAddress // validator operator address GetBondShares() Dec // amount of validator's shares } diff --git a/x/bank/msgs_test.go b/x/bank/msgs_test.go index ac16b1d0b1..e082bdac42 100644 --- a/x/bank/msgs_test.go +++ b/x/bank/msgs_test.go @@ -187,7 +187,7 @@ func TestMsgSendGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - expected := `{"inputs":[{"address":"cosmosaccaddr1d9h8qat5e4ehc5","coins":[{"amount":"10","denom":"atom"}]}],"outputs":[{"address":"cosmosaccaddr1da6hgur4wse3jx32","coins":[{"amount":"10","denom":"atom"}]}]}` + expected := `{"inputs":[{"address":"cosmos1d9h8qat57ljhcm","coins":[{"amount":"10","denom":"atom"}]}],"outputs":[{"address":"cosmos1da6hgur4wsmpnjyg","coins":[{"amount":"10","denom":"atom"}]}]}` require.Equal(t, expected, string(res)) } @@ -257,7 +257,7 @@ func TestMsgIssueGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - expected := `{"banker":"cosmosaccaddr1d9h8qat5e4ehc5","outputs":[{"address":"cosmosaccaddr1d3hkzm3dveex7mfdvfsku6cwsauqd","coins":[{"amount":"10","denom":"atom"}]}]}` + expected := `{"banker":"cosmos1d9h8qat57ljhcm","outputs":[{"address":"cosmos1d3hkzm3dveex7mfdvfsku6cjngpcj","coins":[{"amount":"10","denom":"atom"}]}]}` require.Equal(t, expected, string(res)) } diff --git a/x/gov/endblocker_test.go b/x/gov/endblocker_test.go index 9dd241aabd..710ecb1dba 100644 --- a/x/gov/endblocker_test.go +++ b/x/gov/endblocker_test.go @@ -178,12 +178,17 @@ func TestSlashing(t *testing.T) { govHandler := NewHandler(keeper) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:3], []int64{25, 6, 7}) + valAddrs := make([]sdk.ValAddress, len(addrs[:3])) + for i, addr := range addrs[:3] { + valAddrs[i] = sdk.ValAddress(addr) + } + + createValidators(t, stakeHandler, ctx, valAddrs, []int64{25, 6, 7}) initTotalPower := keeper.ds.GetValidatorSet().TotalPower(ctx) - val0Initial := keeper.ds.GetValidatorSet().Validator(ctx, addrs[0]).GetPower().Quo(initTotalPower) - val1Initial := keeper.ds.GetValidatorSet().Validator(ctx, addrs[1]).GetPower().Quo(initTotalPower) - val2Initial := keeper.ds.GetValidatorSet().Validator(ctx, addrs[2]).GetPower().Quo(initTotalPower) + val0Initial := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[0])).GetPower().Quo(initTotalPower) + val1Initial := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[1])).GetPower().Quo(initTotalPower) + val2Initial := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[2])).GetPower().Quo(initTotalPower) newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 15)}) @@ -209,9 +214,9 @@ func TestSlashing(t *testing.T) { require.False(t, keeper.GetProposal(ctx, proposalID).GetTallyResult().Equals(EmptyTallyResult())) endTotalPower := keeper.ds.GetValidatorSet().TotalPower(ctx) - val0End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[0]).GetPower().Quo(endTotalPower) - val1End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[1]).GetPower().Quo(endTotalPower) - val2End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[2]).GetPower().Quo(endTotalPower) + val0End := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[0])).GetPower().Quo(endTotalPower) + val1End := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[1])).GetPower().Quo(endTotalPower) + val2End := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[2])).GetPower().Quo(endTotalPower) require.True(t, val0End.GTE(val0Initial)) require.True(t, val1End.LT(val1Initial)) diff --git a/x/gov/handler.go b/x/gov/handler.go index 4fa3887296..6424bb0a10 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -114,8 +114,8 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { resTags.AppendTag(tags.Action, tags.ActionProposalDropped) resTags.AppendTag(tags.ProposalID, proposalIDBytes) - logger.Info("Proposal %d - \"%s\" - didn't mean minimum deposit (had only %s), deleted", - inactiveProposal.GetProposalID(), inactiveProposal.GetTitle(), inactiveProposal.GetTotalDeposit()) + logger.Info(fmt.Sprintf("Proposal %d - \"%s\" - didn't mean minimum deposit (had only %s), deleted", + inactiveProposal.GetProposalID(), inactiveProposal.GetTitle(), inactiveProposal.GetTotalDeposit())) } // Check if earliest Active Proposal ended voting period yet @@ -143,8 +143,8 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { activeProposal.SetTallyResult(tallyResults) keeper.SetProposal(ctx, activeProposal) - logger.Info("Proposal %d - \"%s\" - tallied, passed: %v", - activeProposal.GetProposalID(), activeProposal.GetTitle(), passes) + logger.Info(fmt.Sprintf("Proposal %d - \"%s\" - tallied, passed: %v", + activeProposal.GetProposalID(), activeProposal.GetTitle(), passes)) for _, valAddr := range nonVotingVals { val := keeper.ds.GetValidatorSet().Validator(ctx, valAddr) diff --git a/x/gov/tally.go b/x/gov/tally.go index b6c9ee2a14..a756eaf926 100644 --- a/x/gov/tally.go +++ b/x/gov/tally.go @@ -6,14 +6,14 @@ import ( // validatorGovInfo used for tallying type validatorGovInfo struct { - Address sdk.AccAddress // sdk.AccAddress of the validator owner + Address sdk.ValAddress // address of the validator operator Power sdk.Dec // Power of a Validator DelegatorShares sdk.Dec // Total outstanding delegator shares Minus sdk.Dec // Minus of validator, used to compute validator's voting power Vote VoteOption // Vote of the validator } -func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tallyResults TallyResult, nonVoting []sdk.AccAddress) { +func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tallyResults TallyResult, nonVoting []sdk.ValAddress) { results := make(map[VoteOption]sdk.Dec) results[OptionYes] = sdk.ZeroDec() results[OptionAbstain] = sdk.ZeroDec() @@ -43,15 +43,18 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall // if validator, just record it in the map // if delegator tally voting power - if val, ok := currValidators[vote.Voter.String()]; ok { + valAddrStr := sdk.ValAddress(vote.Voter).String() + if val, ok := currValidators[valAddrStr]; ok { val.Vote = vote.Option - currValidators[vote.Voter.String()] = val + currValidators[valAddrStr] = val } else { keeper.ds.IterateDelegations(ctx, vote.Voter, func(index int64, delegation sdk.Delegation) (stop bool) { - if val, ok := currValidators[delegation.GetValidator().String()]; ok { + valAddrStr := delegation.GetValidator().String() + + if val, ok := currValidators[valAddrStr]; ok { val.Minus = val.Minus.Add(delegation.GetBondShares()) - currValidators[delegation.GetValidator().String()] = val + currValidators[valAddrStr] = val delegatorShare := delegation.GetBondShares().Quo(val.DelegatorShares) votingPower := val.Power.Mul(delegatorShare) @@ -59,6 +62,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall results[vote.Option] = results[vote.Option].Add(votingPower) totalVotingPower = totalVotingPower.Add(votingPower) } + return false }) } @@ -66,13 +70,15 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall keeper.deleteVote(ctx, vote.ProposalID, vote.Voter) } - // Iterate over the validators again to tally their voting power and see who didn't vote - nonVoting = []sdk.AccAddress{} + // iterate over the validators again to tally their voting power and see + // who didn't vote + nonVoting = []sdk.ValAddress{} for _, val := range currValidators { if val.Vote == OptionEmpty { nonVoting = append(nonVoting, val.Address) continue } + sharesAfterMinus := val.DelegatorShares.Sub(val.Minus) percentAfterMinus := sharesAfterMinus.Quo(val.DelegatorShares) votingPower := val.Power.Mul(percentAfterMinus) @@ -104,7 +110,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall } // If more than 1/2 of non-abstaining voters vote No, proposal fails - SortAddresses(nonVoting) + SortValAddresses(nonVoting) return false, tallyResults, nonVoting } diff --git a/x/gov/tally_test.go b/x/gov/tally_test.go index 157f594401..24740731f0 100644 --- a/x/gov/tally_test.go +++ b/x/gov/tally_test.go @@ -17,7 +17,7 @@ var ( pubkeys = []crypto.PubKey{ed25519.GenPrivKey().PubKey(), ed25519.GenPrivKey().PubKey(), ed25519.GenPrivKey().PubKey()} ) -func createValidators(t *testing.T, stakeHandler sdk.Handler, ctx sdk.Context, addrs []sdk.AccAddress, coinAmt []int64) { +func createValidators(t *testing.T, stakeHandler sdk.Handler, ctx sdk.Context, addrs []sdk.ValAddress, coinAmt []int64) { require.True(t, len(addrs) <= len(pubkeys), "Not enough pubkeys specified at top of file.") dummyDescription := stake.NewDescription("T", "E", "S", "T") for i := 0; i < len(addrs); i++ { @@ -33,7 +33,12 @@ func TestTallyNoOneVotes(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:2], []int64{5, 5}) + valAddrs := make([]sdk.ValAddress, len(addrs[:2])) + for i, addr := range addrs[:2] { + valAddrs[i] = sdk.ValAddress(addr) + } + + createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 5}) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -52,7 +57,12 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:2], []int64{5, 5}) + valAddrs := make([]sdk.ValAddress, len(addrs[:2])) + for i, addr := range addrs[:2] { + valAddrs[i] = sdk.ValAddress(addr) + } + + createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 5}) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -76,7 +86,12 @@ func TestTallyOnlyValidators51No(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:2], []int64{5, 6}) + valAddrs := make([]sdk.ValAddress, len(addrs[:2])) + for i, addr := range addrs[:2] { + valAddrs[i] = sdk.ValAddress(addr) + } + + createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6}) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -99,7 +114,12 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:3], []int64{6, 6, 7}) + valAddrs := make([]sdk.ValAddress, len(addrs[:3])) + for i, addr := range addrs[:3] { + valAddrs[i] = sdk.ValAddress(addr) + } + + createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7}) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -125,7 +145,12 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:3], []int64{6, 6, 7}) + valAddrs := make([]sdk.ValAddress, len(addrs[:3])) + for i, addr := range addrs[:3] { + valAddrs[i] = sdk.ValAddress(addr) + } + + createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7}) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -151,7 +176,12 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:3], []int64{6, 6, 7}) + valAddrs := make([]sdk.ValAddress, len(addrs[:3])) + for i, addr := range addrs[:3] { + valAddrs[i] = sdk.ValAddress(addr) + } + + createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7}) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -177,7 +207,12 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:3], []int64{6, 6, 7}) + valAddrs := make([]sdk.ValAddress, len(addrs[:3])) + for i, addr := range addrs[:3] { + valAddrs[i] = sdk.ValAddress(addr) + } + + createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7}) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -203,7 +238,12 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:3], []int64{6, 6, 7}) + valAddrs := make([]sdk.ValAddress, len(addrs[:3])) + for i, addr := range addrs[:3] { + valAddrs[i] = sdk.ValAddress(addr) + } + + createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7}) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -219,7 +259,7 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { require.False(t, passes) require.Equal(t, 1, len(nonVoting)) - require.Equal(t, addrs[0], nonVoting[0]) + require.Equal(t, sdk.ValAddress(addrs[0]), nonVoting[0]) require.False(t, tallyResults.Equals(EmptyTallyResult())) } @@ -229,9 +269,14 @@ func TestTallyDelgatorOverride(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:3], []int64{5, 6, 7}) + valAddrs := make([]sdk.ValAddress, len(addrs[:3])) + for i, addr := range addrs[:3] { + valAddrs[i] = sdk.ValAddress(addr) + } - delegator1Msg := stake.NewMsgDelegate(addrs[3], addrs[2], sdk.NewInt64Coin("steak", 30)) + createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7}) + + delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30)) stakeHandler(ctx, delegator1Msg) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) @@ -260,9 +305,14 @@ func TestTallyDelgatorInherit(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:3], []int64{5, 6, 7}) + valAddrs := make([]sdk.ValAddress, len(addrs[:3])) + for i, addr := range addrs[:3] { + valAddrs[i] = sdk.ValAddress(addr) + } - delegator1Msg := stake.NewMsgDelegate(addrs[3], addrs[2], sdk.NewInt64Coin("steak", 30)) + createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7}) + + delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30)) stakeHandler(ctx, delegator1Msg) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) @@ -290,11 +340,16 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:3], []int64{5, 6, 7}) + valAddrs := make([]sdk.ValAddress, len(addrs[:3])) + for i, addr := range addrs[:3] { + valAddrs[i] = sdk.ValAddress(addr) + } - delegator1Msg := stake.NewMsgDelegate(addrs[3], addrs[2], sdk.NewInt64Coin("steak", 10)) + createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7}) + + delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10)) stakeHandler(ctx, delegator1Msg) - delegator1Msg2 := stake.NewMsgDelegate(addrs[3], addrs[1], sdk.NewInt64Coin("steak", 10)) + delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10)) stakeHandler(ctx, delegator1Msg2) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) @@ -324,16 +379,26 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { stakeHandler := stake.NewHandler(sk) dummyDescription := stake.NewDescription("T", "E", "S", "T") - val1CreateMsg := stake.NewMsgCreateValidator(addrs[0], ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 25), dummyDescription) + + val1CreateMsg := stake.NewMsgCreateValidator( + sdk.ValAddress(addrs[0]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 25), dummyDescription, + ) stakeHandler(ctx, val1CreateMsg) - val2CreateMsg := stake.NewMsgCreateValidator(addrs[1], ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 6), dummyDescription) + + val2CreateMsg := stake.NewMsgCreateValidator( + sdk.ValAddress(addrs[1]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 6), dummyDescription, + ) stakeHandler(ctx, val2CreateMsg) - val3CreateMsg := stake.NewMsgCreateValidator(addrs[2], ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 7), dummyDescription) + + val3CreateMsg := stake.NewMsgCreateValidator( + sdk.ValAddress(addrs[2]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 7), dummyDescription, + ) stakeHandler(ctx, val3CreateMsg) - delegator1Msg := stake.NewMsgDelegate(addrs[3], addrs[2], sdk.NewInt64Coin("steak", 10)) + delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10)) stakeHandler(ctx, delegator1Msg) - delegator1Msg2 := stake.NewMsgDelegate(addrs[3], addrs[1], sdk.NewInt64Coin("steak", 10)) + + delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10)) stakeHandler(ctx, delegator1Msg2) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) @@ -360,13 +425,20 @@ func TestTallyJailedValidator(t *testing.T) { ctx := mapp.BaseApp.NewContext(false, abci.Header{}) stakeHandler := stake.NewHandler(sk) - createValidators(t, stakeHandler, ctx, addrs[:3], []int64{25, 6, 7}) - delegator1Msg := stake.NewMsgDelegate(addrs[3], addrs[2], sdk.NewInt64Coin("steak", 10)) + valAddrs := make([]sdk.ValAddress, len(addrs[:3])) + for i, addr := range addrs[:3] { + valAddrs[i] = sdk.ValAddress(addr) + } + + createValidators(t, stakeHandler, ctx, valAddrs, []int64{25, 6, 7}) + + delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10)) stakeHandler(ctx, delegator1Msg) - delegator1Msg2 := stake.NewMsgDelegate(addrs[3], addrs[1], sdk.NewInt64Coin("steak", 10)) + + delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10)) stakeHandler(ctx, delegator1Msg2) - val2, found := sk.GetValidator(ctx, addrs[1]) + val2, found := sk.GetValidator(ctx, sdk.ValAddress(addrs[1])) require.True(t, found) sk.Jail(ctx, val2.PubKey) diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 5e7977b50c..502cfbbf04 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -77,6 +77,20 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakeKeeper stake.Keeper) sdk } } +// TODO: Remove once address interface has been implemented (ref: #2186) +func SortValAddresses(addrs []sdk.ValAddress) { + var byteAddrs [][]byte + for _, addr := range addrs { + byteAddrs = append(byteAddrs, addr.Bytes()) + } + + SortByteArrays(byteAddrs) + + for i, byteAddr := range byteAddrs { + addrs[i] = byteAddr + } +} + // Sorts Addresses func SortAddresses(addrs []sdk.AccAddress) { var byteAddrs [][]byte diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 86d350a84b..f9ec0833fa 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -73,7 +73,7 @@ func getInitChainer(mapp *mock.App, keeper stake.Keeper) sdk.InitChainer { func checkValidator(t *testing.T, mapp *mock.App, keeper stake.Keeper, addr sdk.AccAddress, expFound bool) stake.Validator { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - validator, found := keeper.GetValidator(ctxCheck, addr1) + validator, found := keeper.GetValidator(ctxCheck, sdk.ValAddress(addr1)) require.Equal(t, expFound, found) return validator } @@ -100,17 +100,17 @@ func TestSlashingMsgs(t *testing.T) { mock.SetGenesis(mapp, accs) description := stake.NewDescription("foo_moniker", "", "", "") createValidatorMsg := stake.NewMsgCreateValidator( - addr1, priv1.PubKey(), bondCoin, description, + sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description, ) mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1) mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin.Minus(bondCoin)}) mapp.BeginBlock(abci.RequestBeginBlock{}) validator := checkValidator(t, mapp, stakeKeeper, addr1, true) - require.Equal(t, addr1, validator.Operator) + require.Equal(t, sdk.ValAddress(addr1), validator.Operator) require.Equal(t, sdk.Bonded, validator.Status) require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) - unjailMsg := MsgUnjail{ValidatorAddr: sdk.AccAddress(validator.PubKey.Address())} + unjailMsg := MsgUnjail{ValidatorAddr: sdk.ValAddress(validator.PubKey.Address())} // no signing info yet checkValidatorSigningInfo(t, mapp, keeper, sdk.ValAddress(addr1), false) diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 0901eef970..9f6d834dda 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -20,7 +20,7 @@ func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command { Short: "Query a validator's signing information", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - pk, err := sdk.GetValPubKeyBech32(args[0]) + pk, err := sdk.GetConsPubKeyBech32(args[0]) if err != nil { return err } diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index 2fdd65c6c3..4234e52ce8 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -27,12 +27,12 @@ func GetCmdUnjail(cdc *wire.Codec) *cobra.Command { WithLogger(os.Stdout). WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - validatorAddr, err := cliCtx.GetFromAddress() + valAddr, err := cliCtx.GetFromAddress() if err != nil { return err } - msg := slashing.NewMsgUnjail(validatorAddr) + msg := slashing.NewMsgUnjail(sdk.ValAddress(valAddr)) return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) }, diff --git a/x/slashing/client/rest/query.go b/x/slashing/client/rest/query.go index 5509ed1a8d..291679375b 100644 --- a/x/slashing/client/rest/query.go +++ b/x/slashing/client/rest/query.go @@ -23,7 +23,7 @@ func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *wire return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - pk, err := sdk.GetValPubKeyBech32(vars["validator"]) + pk, err := sdk.GetConsPubKeyBech32(vars["validator"]) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index 26412ebc00..c7efdc97e9 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -56,13 +56,13 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI return } - validatorAddr, err := sdk.AccAddressFromBech32(m.ValidatorAddr) + valAddr, err := sdk.ValAddressFromBech32(m.ValidatorAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } - if !bytes.Equal(info.GetPubKey().Address(), validatorAddr) { + if !bytes.Equal(info.GetPubKey().Address(), valAddr) { utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own validator address") return } @@ -75,7 +75,7 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI Gas: m.Gas, } - msg := slashing.NewMsgUnjail(validatorAddr) + msg := slashing.NewMsgUnjail(valAddr) if m.Gas == 0 { newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg}) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 4408d3c09d..8e3b719f49 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -15,15 +15,15 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { slh := NewHandler(keeper) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) - msg := newTestMsgCreateValidator(addr, val, amt) + msg := newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt) got := stake.NewHandler(sk)(ctx, msg) require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower())) // assert non-jailed validator can't be unjailed - got = slh(ctx, NewMsgUnjail(addr)) + got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr))) require.False(t, got.IsOK(), "allowed unjail of non-jailed validator") require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotJailed), got.Code) } diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 808c82014e..3bdb043a82 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -26,12 +26,12 @@ func TestHandleDoubleSign(t *testing.T) { ctx, ck, sk, _, keeper := createTestInput(t) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) - got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) + got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt)) require.True(t, got.IsOK()) validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower())) // handle a signature to set signing info keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true) @@ -40,16 +40,22 @@ func TestHandleDoubleSign(t *testing.T) { keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt) // should be jailed - require.True(t, sk.Validator(ctx, addr).GetJailed()) + require.True(t, sk.Validator(ctx, sdk.ValAddress(addr)).GetJailed()) // unjail to measure power sk.Unjail(ctx, val) // power should be reduced - require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) + require.Equal( + t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), + sk.Validator(ctx, sdk.ValAddress(addr)).GetPower(), + ) ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.MaxEvidenceAge(ctx))}) // double sign past max age keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt) - require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower()) + require.Equal( + t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), + sk.Validator(ctx, sdk.ValAddress(addr)).GetPower(), + ) } // Test a validator through uptime, downtime, revocation, @@ -62,12 +68,12 @@ func TestHandleAbsentValidator(t *testing.T) { addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) sh := stake.NewHandler(sk) slh := NewHandler(keeper) - got := sh(ctx, newTestMsgCreateValidator(addr, val, amt)) + got := sh(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt)) require.True(t, got.IsOK()) validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower())) info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.False(t, found) require.Equal(t, int64(0), info.StartHeight) @@ -117,12 +123,12 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, sdk.Unbonded, validator.GetStatus()) // unrevocation should fail prior to jail expiration - got = slh(ctx, NewMsgUnjail(addr)) + got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr))) require.False(t, got.IsOK()) // unrevocation should succeed after jail expiration ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.DowntimeUnbondDuration(ctx))}) - got = slh(ctx, NewMsgUnjail(addr)) + got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr))) require.True(t, got.IsOK()) // validator should be rebonded now @@ -172,12 +178,12 @@ func TestHandleNewValidator(t *testing.T) { ctx, ck, sk, _, keeper := createTestInput(t) addr, val, amt := addrs[0], pks[0], int64(100) sh := stake.NewHandler(sk) - got := sh(ctx, newTestMsgCreateValidator(addr, val, sdk.NewInt(amt))) + got := sh(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, sdk.NewInt(amt))) require.True(t, got.IsOK()) validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}}) - require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, addr).GetPower()) + require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, sdk.ValAddress(addr)).GetPower()) // 1000 first blocks not a validator ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) @@ -210,7 +216,7 @@ func TestHandleAlreadyJailed(t *testing.T) { amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) sh := stake.NewHandler(sk) - got := sh(ctx, newTestMsgCreateValidator(addr, val, amt)) + got := sh(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt)) require.True(t, got.IsOK()) validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) diff --git a/x/slashing/msg.go b/x/slashing/msg.go index e22eca7bdd..7791012185 100644 --- a/x/slashing/msg.go +++ b/x/slashing/msg.go @@ -15,18 +15,20 @@ var _ sdk.Msg = &MsgUnjail{} // MsgUnjail - struct for unjailing jailed validator type MsgUnjail struct { - ValidatorAddr sdk.AccAddress `json:"address"` // address of the validator owner + ValidatorAddr sdk.ValAddress `json:"address"` // address of the validator owner } -func NewMsgUnjail(validatorAddr sdk.AccAddress) MsgUnjail { +func NewMsgUnjail(validatorAddr sdk.ValAddress) MsgUnjail { return MsgUnjail{ ValidatorAddr: validatorAddr, } } //nolint -func (msg MsgUnjail) Type() string { return MsgType } -func (msg MsgUnjail) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.ValidatorAddr} } +func (msg MsgUnjail) Type() string { return MsgType } +func (msg MsgUnjail) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{sdk.AccAddress(msg.ValidatorAddr)} +} // get the bytes for the message signer to sign on func (msg MsgUnjail) GetSignBytes() []byte { diff --git a/x/slashing/msg_test.go b/x/slashing/msg_test.go index ef2e673c86..ff8619041e 100644 --- a/x/slashing/msg_test.go +++ b/x/slashing/msg_test.go @@ -10,7 +10,7 @@ import ( func TestMsgUnjailGetSignBytes(t *testing.T) { addr := sdk.AccAddress("abcd") - msg := NewMsgUnjail(addr) + msg := NewMsgUnjail(sdk.ValAddress(addr)) bytes := msg.GetSignBytes() - require.Equal(t, string(bytes), `{"address":"cosmosaccaddr1v93xxeqhyqz5v"}`) + require.Equal(t, string(bytes), `{"address":"cosmosval1v93xxeq7xkcrf"}`) } diff --git a/x/slashing/simulation/msgs.go b/x/slashing/simulation/msgs.go index e4900889e3..dc7f63ba64 100644 --- a/x/slashing/simulation/msgs.go +++ b/x/slashing/simulation/msgs.go @@ -19,7 +19,7 @@ import ( func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation { return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) { key := simulation.RandomKey(r, keys) - address := sdk.AccAddress(key.PubKey().Address()) + address := sdk.ValAddress(key.PubKey().Address()) msg := slashing.NewMsgUnjail(address) require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) ctx, write := ctx.CacheContext() diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 50c501d7e3..1053823786 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -99,10 +99,10 @@ func testAddr(addr string) sdk.AccAddress { return res } -func newTestMsgCreateValidator(address sdk.AccAddress, pubKey crypto.PubKey, amt sdk.Int) stake.MsgCreateValidator { +func newTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt sdk.Int) stake.MsgCreateValidator { return stake.MsgCreateValidator{ Description: stake.Description{}, - DelegatorAddr: address, + DelegatorAddr: sdk.AccAddress(address), ValidatorAddr: address, PubKey: pubKey, Delegation: sdk.Coin{"steak", amt}, diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index 78d2695494..9eb956e671 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -17,12 +17,12 @@ func TestBeginBlocker(t *testing.T) { addr, pk, amt := addrs[2], pks[2], sdk.NewInt(100) // bond the validator - got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, pk, amt)) + got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), pk, amt)) require.True(t, got.IsOK()) validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) - require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower())) val := abci.Validator{ Address: pk.Address(), diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 65c64fdef2..587e90b465 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -79,7 +79,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { //__________________________________________________________________________________________ func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper, - addr sdk.AccAddress, expFound bool) Validator { + addr sdk.ValAddress, expFound bool) Validator { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) validator, found := keeper.GetValidator(ctxCheck, addr) @@ -89,8 +89,8 @@ func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper, } func checkDelegation( - t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr, - validatorAddr sdk.AccAddress, expFound bool, expShares sdk.Dec, + t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr sdk.AccAddress, + validatorAddr sdk.ValAddress, expFound bool, expShares sdk.Dec, ) { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) @@ -128,55 +128,57 @@ func TestStakeMsgs(t *testing.T) { // create validator description := NewDescription("foo_moniker", "", "", "") createValidatorMsg := NewMsgCreateValidator( - addr1, priv1.PubKey(), bondCoin, description, + sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description, ) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1) mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin)}) mApp.BeginBlock(abci.RequestBeginBlock{}) - validator := checkValidator(t, mApp, keeper, addr1, true) - require.Equal(t, addr1, validator.Operator) + validator := checkValidator(t, mApp, keeper, sdk.ValAddress(addr1), true) + require.Equal(t, sdk.ValAddress(addr1), validator.Operator) require.Equal(t, sdk.Bonded, validator.Status) require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens())) // addr1 create validator on behalf of addr2 - createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf(addr1, addr2, priv2.PubKey(), bondCoin, description) + createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf( + addr1, sdk.ValAddress(addr2), priv2.PubKey(), bondCoin, description, + ) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []int64{0, 1}, []int64{1, 0}, true, priv1, priv2) mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin).Minus(bondCoin)}) mApp.BeginBlock(abci.RequestBeginBlock{}) - validator = checkValidator(t, mApp, keeper, addr2, true) - require.Equal(t, addr2, validator.Operator) + validator = checkValidator(t, mApp, keeper, sdk.ValAddress(addr2), true) + require.Equal(t, sdk.ValAddress(addr2), validator.Operator) require.Equal(t, sdk.Bonded, validator.Status) require.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) // check the bond that should have been created as well - checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewDec(10)) + checkDelegation(t, mApp, keeper, addr1, sdk.ValAddress(addr1), true, sdk.NewDec(10)) // edit the validator description = NewDescription("bar_moniker", "", "", "") - editValidatorMsg := NewMsgEditValidator(addr1, description) + editValidatorMsg := NewMsgEditValidator(sdk.ValAddress(addr1), description) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{2}, true, priv1) - validator = checkValidator(t, mApp, keeper, addr1, true) + validator = checkValidator(t, mApp, keeper, sdk.ValAddress(addr1), true) require.Equal(t, description, validator.Description) // delegate mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin}) - delegateMsg := NewMsgDelegate(addr2, addr1, bondCoin) + delegateMsg := NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, priv2) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) - checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewDec(10)) + checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), true, sdk.NewDec(10)) // begin unbonding - beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewDec(10)) + beginUnbondingMsg := NewMsgBeginUnbonding(addr2, sdk.ValAddress(addr1), sdk.NewDec(10)) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, priv2) // delegation should exist anymore - checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Dec{}) + checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), false, sdk.Dec{}) // balance should be the same because bonding not yet complete mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index d58ea39381..9a017fb590 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -17,11 +17,11 @@ import ( // GetCmdQueryValidator implements the validator query command. func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "validator [owner-addr]", + Use: "validator [operator-addr]", Short: "Query a validator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - addr, err := sdk.AccAddressFromBech32(args[0]) + addr, err := sdk.ValAddressFromBech32(args[0]) if err != nil { return err } @@ -120,7 +120,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { Use: "delegation", Short: "Query a delegation based on address and validator address", RunE: func(cmd *cobra.Command, args []string) error { - valAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator)) + valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err } @@ -222,7 +222,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co Use: "unbonding-delegation", Short: "Query an unbonding-delegation record based on delegator and validator address", RunE: func(cmd *cobra.Command, args []string) error { - valAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator)) + valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err } @@ -321,12 +321,12 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command { Use: "redelegation", Short: "Query a redelegation record based on delegator and a source and destination validator address", RunE: func(cmd *cobra.Command, args []string) error { - valSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc)) + valSrcAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorSrc)) if err != nil { return err } - valDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst)) + valDstAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorDst)) if err != nil { return err } diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 9f04f2ed2d..defc2b1e23 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -40,7 +40,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { return err } - validatorAddr, err := cliCtx.GetFromAddress() + valAddr, err := cliCtx.GetFromAddress() if err != nil { return err } @@ -50,7 +50,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { return fmt.Errorf("must use --pubkey flag") } - pk, err := sdk.GetValPubKeyBech32(pkStr) + pk, err := sdk.GetConsPubKeyBech32(pkStr) if err != nil { return err } @@ -68,14 +68,14 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { var msg sdk.Msg if viper.GetString(FlagAddressDelegator) != "" { - delegatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator)) + delAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator)) if err != nil { return err } - msg = stake.NewMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, amount, description) + msg = stake.NewMsgCreateValidatorOnBehalfOf(delAddr, sdk.ValAddress(valAddr), pk, amount, description) } else { - msg = stake.NewMsgCreateValidator(validatorAddr, pk, amount, description) + msg = stake.NewMsgCreateValidator(sdk.ValAddress(valAddr), pk, amount, description) } // build and sign the transaction, then broadcast to Tendermint @@ -103,7 +103,7 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { WithLogger(os.Stdout). WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - validatorAddr, err := cliCtx.GetFromAddress() + valAddr, err := cliCtx.GetFromAddress() if err != nil { return err } @@ -114,7 +114,8 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command { Website: viper.GetString(FlagWebsite), Details: viper.GetString(FlagDetails), } - msg := stake.NewMsgEditValidator(validatorAddr, description) + + msg := stake.NewMsgEditValidator(sdk.ValAddress(valAddr), description) // build and sign the transaction, then broadcast to Tendermint return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) @@ -143,17 +144,17 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command { return err } - delegatorAddr, err := cliCtx.GetFromAddress() + delAddr, err := cliCtx.GetFromAddress() if err != nil { return err } - validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator)) + valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err } - msg := stake.NewMsgDelegate(delegatorAddr, validatorAddr, amount) + msg := stake.NewMsgDelegate(delAddr, valAddr, amount) // build and sign the transaction, then broadcast to Tendermint return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) @@ -195,17 +196,18 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) var err error - delegatorAddr, err := cliCtx.GetFromAddress() + + delAddr, err := cliCtx.GetFromAddress() if err != nil { return err } - validatorSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc)) + valSrcAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorSrc)) if err != nil { return err } - validatorDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst)) + valDstAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorDst)) if err != nil { return err } @@ -215,13 +217,13 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { sharesPercentStr := viper.GetString(FlagSharesPercent) sharesAmount, err := getShares( storeName, cdc, sharesAmountStr, sharesPercentStr, - delegatorAddr, validatorSrcAddr, + delAddr, valSrcAddr, ) if err != nil { return err } - msg := stake.NewMsgBeginRedelegate(delegatorAddr, validatorSrcAddr, validatorDstAddr, sharesAmount) + msg := stake.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, sharesAmount) // build and sign the transaction, then broadcast to Tendermint return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) @@ -238,7 +240,7 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command { // TODO: Make this pass gocyclo linting func getShares( storeName string, cdc *wire.Codec, sharesAmountStr, - sharesPercentStr string, delegatorAddr, validatorAddr sdk.AccAddress, + sharesPercentStr string, delAddr sdk.AccAddress, valAddr sdk.ValAddress, ) (sharesAmount sdk.Dec, err error) { switch { case sharesAmountStr != "" && sharesPercentStr != "": @@ -264,7 +266,7 @@ func getShares( } // make a query to get the existing delegation shares - key := stake.GetDelegationKey(delegatorAddr, validatorAddr) + key := stake.GetDelegationKey(delAddr, valAddr) cliCtx := context.NewCLIContext(). WithCodec(cdc). WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) @@ -294,22 +296,22 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command { WithLogger(os.Stdout). WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - delegatorAddr, err := cliCtx.GetFromAddress() + delAddr, err := cliCtx.GetFromAddress() if err != nil { return err } - validatorSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc)) + valSrcAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorSrc)) if err != nil { return err } - validatorDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst)) + valDstAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorDst)) if err != nil { return err } - msg := stake.NewMsgCompleteRedelegate(delegatorAddr, validatorSrcAddr, validatorDstAddr) + msg := stake.NewMsgCompleteRedelegate(delAddr, valSrcAddr, valDstAddr) // build and sign the transaction, then broadcast to Tendermint return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) @@ -349,12 +351,12 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command { WithLogger(os.Stdout). WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - delegatorAddr, err := cliCtx.GetFromAddress() + delAddr, err := cliCtx.GetFromAddress() if err != nil { return err } - validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator)) + valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err } @@ -364,13 +366,13 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command { sharesPercentStr := viper.GetString(FlagSharesPercent) sharesAmount, err := getShares( storeName, cdc, sharesAmountStr, sharesPercentStr, - delegatorAddr, validatorAddr, + delAddr, valAddr, ) if err != nil { return err } - msg := stake.NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sharesAmount) + msg := stake.NewMsgBeginUnbonding(delAddr, valAddr, sharesAmount) // build and sign the transaction, then broadcast to Tendermint return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) @@ -395,17 +397,17 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command { WithLogger(os.Stdout). WithAccountDecoder(authcmd.GetAccountDecoder(cdc)) - delegatorAddr, err := cliCtx.GetFromAddress() + delAddr, err := cliCtx.GetFromAddress() if err != nil { return err } - validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator)) + valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator)) if err != nil { return err } - msg := stake.NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) + msg := stake.NewMsgCompleteUnbonding(delAddr, valAddr) // build and sign the transaction, then broadcast to Tendermint return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg}) diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index a040c7541c..bf929387dd 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -87,7 +87,7 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Cod // defines a delegation without type Rat for shares type DelegationWithoutRat struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` - ValidatorAddr sdk.AccAddress `json:"validator_addr"` + ValidatorAddr sdk.ValAddress `json:"validator_addr"` Shares string `json:"shares"` Height int64 `json:"height"` } @@ -103,14 +103,14 @@ type DelegationSummary struct { func delegatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var validatorAddr sdk.AccAddress + var valAddr sdk.ValAddress var delegationSummary = DelegationSummary{} // read parameters vars := mux.Vars(r) bech32delegator := vars["delegatorAddr"] - delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) + delAddr, err := sdk.AccAddressFromBech32(bech32delegator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) @@ -126,10 +126,10 @@ func delegatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handler } for _, validator := range validators { - validatorAddr = validator.Operator + valAddr = validator.Operator // Delegations - delegations, statusCode, errMsg, err := getDelegatorDelegations(cliCtx, cdc, delegatorAddr, validatorAddr) + delegations, statusCode, errMsg, err := getDelegatorDelegations(cliCtx, cdc, delAddr, valAddr) if err != nil { w.WriteHeader(statusCode) w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) @@ -140,7 +140,7 @@ func delegatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handler } // Undelegations - unbondingDelegation, statusCode, errMsg, err := getDelegatorUndelegations(cliCtx, cdc, delegatorAddr, validatorAddr) + unbondingDelegation, statusCode, errMsg, err := getDelegatorUndelegations(cliCtx, cdc, delAddr, valAddr) if err != nil { w.WriteHeader(statusCode) w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) @@ -153,7 +153,7 @@ func delegatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handler // Redelegations // only querying redelegations to a validator as this should give us already all relegations // if we also would put in redelegations from, we would have every redelegation double - redelegations, statusCode, errMsg, err := getDelegatorRedelegations(cliCtx, cdc, delegatorAddr, validatorAddr) + redelegations, statusCode, errMsg, err := getDelegatorRedelegations(cliCtx, cdc, delAddr, valAddr) if err != nil { w.WriteHeader(statusCode) w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) @@ -259,22 +259,21 @@ func unbondingDelegationsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) h bech32delegator := vars["delegatorAddr"] bech32validator := vars["validatorAddr"] - delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) + delAddr, err := sdk.AccAddressFromBech32(bech32delegator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - validatorAddr, err := sdk.AccAddressFromBech32(bech32validator) + valAddr, err := sdk.ValAddressFromBech32(bech32validator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - validatorAddrAcc := sdk.AccAddress(validatorAddr) - key := stake.GetUBDKey(delegatorAddr, validatorAddrAcc) + key := stake.GetUBDKey(delAddr, valAddr) res, err := cliCtx.QueryStore(key, storeName) if err != nil { @@ -318,22 +317,21 @@ func delegationHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handle bech32delegator := vars["delegatorAddr"] bech32validator := vars["validatorAddr"] - delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) + delAddr, err := sdk.AccAddressFromBech32(bech32delegator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - validatorAddr, err := sdk.AccAddressFromBech32(bech32validator) + valAddr, err := sdk.ValAddressFromBech32(bech32validator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) return } - validatorAddrAcc := sdk.AccAddress(validatorAddr) - key := stake.GetDelegationKey(delegatorAddr, validatorAddrAcc) + key := stake.GetDelegationKey(delAddr, valAddr) res, err := cliCtx.QueryStore(key, storeName) if err != nil { @@ -377,7 +375,7 @@ func delegationHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handle func delegatorValidatorsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var validatorAccAddr sdk.AccAddress + var valAddr sdk.ValAddress var bondedValidators []types.BechValidator // read parameters @@ -412,9 +410,9 @@ func delegatorValidatorsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) ht for _, validator := range validators { // get all transactions from the delegator to val and append - validatorAccAddr = validator.Operator + valAddr = validator.Operator - validator, statusCode, errMsg, errRes := getDelegatorValidator(cliCtx, cdc, delegatorAddr, validatorAccAddr) + validator, statusCode, errMsg, errRes := getDelegatorValidator(cliCtx, cdc, delegatorAddr, valAddr) if errRes != nil { w.WriteHeader(statusCode) w.Write([]byte(fmt.Sprintf("%s%s", errMsg, errRes.Error()))) @@ -444,8 +442,8 @@ func delegatorValidatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) htt bech32delegator := vars["delegatorAddr"] bech32validator := vars["validatorAddr"] - delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator) - validatorAccAddr, err := sdk.AccAddressFromBech32(bech32validator) + delAddr, err := sdk.AccAddressFromBech32(bech32delegator) + valAddr, err := sdk.ValAddressFromBech32(bech32validator) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) @@ -454,7 +452,7 @@ func delegatorValidatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) htt // Check if there if the delegator is bonded or redelegated to the validator - validator, statusCode, errMsg, err := getDelegatorValidator(cliCtx, cdc, delegatorAddr, validatorAccAddr) + validator, statusCode, errMsg, err := getDelegatorValidator(cliCtx, cdc, delAddr, valAddr) if err != nil { w.WriteHeader(statusCode) w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error()))) @@ -516,14 +514,15 @@ func validatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handler // read parameters vars := mux.Vars(r) bech32validatorAddr := vars["addr"] - valAddress, err := sdk.AccAddressFromBech32(bech32validatorAddr) + + valAddr, err := sdk.ValAddressFromBech32(bech32validatorAddr) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("error: %s", err.Error()))) return } - key := stake.GetValidatorKey(valAddress) + key := stake.GetValidatorKey(valAddr) res, err := cliCtx.QueryStore(key, storeName) if err != nil { @@ -538,7 +537,7 @@ func validatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handler return } - validator, err := types.UnmarshalValidator(cdc, valAddress, res) + validator, err := types.UnmarshalValidator(cdc, valAddr, res) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte(err.Error())) diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 3d7d419a3a..24a8c38752 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -104,26 +104,26 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex i := 0 for _, msg := range m.Delegations { - delegatorAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) + delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) return } - validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr) + valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } - if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { + if !bytes.Equal(info.GetPubKey().Address(), delAddr) { utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address") return } messages[i] = stake.MsgDelegate{ - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, Delegation: msg.Delegation, } @@ -131,23 +131,23 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex } for _, msg := range m.BeginRedelegates { - delegatorAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) + delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } - if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { + if !bytes.Equal(info.GetPubKey().Address(), delAddr) { utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address") return } - validatorSrcAddr, err := sdk.AccAddressFromBech32(msg.ValidatorSrcAddr) + valSrcAddr, err := sdk.ValAddressFromBech32(msg.ValidatorSrcAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } - validatorDstAddr, err := sdk.AccAddressFromBech32(msg.ValidatorDstAddr) + valDstAddr, err := sdk.ValAddressFromBech32(msg.ValidatorDstAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return @@ -160,9 +160,9 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex } messages[i] = stake.MsgBeginRedelegate{ - DelegatorAddr: delegatorAddr, - ValidatorSrcAddr: validatorSrcAddr, - ValidatorDstAddr: validatorDstAddr, + DelegatorAddr: delAddr, + ValidatorSrcAddr: valSrcAddr, + ValidatorDstAddr: valDstAddr, SharesAmount: shares, } @@ -170,50 +170,51 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex } for _, msg := range m.CompleteRedelegates { - delegatorAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) + delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) return } - validatorSrcAddr, err := sdk.AccAddressFromBech32(msg.ValidatorSrcAddr) - if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) - return - } - validatorDstAddr, err := sdk.AccAddressFromBech32(msg.ValidatorDstAddr) + valSrcAddr, err := sdk.ValAddressFromBech32(msg.ValidatorSrcAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } - if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { + valDstAddr, err := sdk.ValAddressFromBech32(msg.ValidatorDstAddr) + if err != nil { + utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) + return + } + + if !bytes.Equal(info.GetPubKey().Address(), delAddr) { utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address") return } messages[i] = stake.MsgCompleteRedelegate{ - DelegatorAddr: delegatorAddr, - ValidatorSrcAddr: validatorSrcAddr, - ValidatorDstAddr: validatorDstAddr, + DelegatorAddr: delAddr, + ValidatorSrcAddr: valSrcAddr, + ValidatorDstAddr: valDstAddr, } i++ } for _, msg := range m.BeginUnbondings { - delegatorAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) + delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) return } - if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { + if !bytes.Equal(info.GetPubKey().Address(), delAddr) { utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address") return } - validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr) + valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return @@ -226,8 +227,8 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex } messages[i] = stake.MsgBeginUnbonding{ - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, SharesAmount: shares, } @@ -235,26 +236,26 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex } for _, msg := range m.CompleteUnbondings { - delegatorAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) + delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) return } - validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr) + valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } - if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) { + if !bytes.Equal(info.GetPubKey().Address(), delAddr) { utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address") return } messages[i] = stake.MsgCompleteUnbonding{ - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, } i++ diff --git a/x/stake/client/rest/utils.go b/x/stake/client/rest/utils.go index 96588f73b5..171ded2b35 100644 --- a/x/stake/client/rest/utils.go +++ b/x/stake/client/rest/utils.go @@ -24,10 +24,10 @@ func contains(stringSlice []string, txType string) bool { return false } -func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) ( +func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( bech32Validator types.BechValidator, httpStatusCode int, errMsg string, err error) { - key := stake.GetDelegationKey(delegatorAddr, validatorAddr) + key := stake.GetDelegationKey(delAddr, valAddr) res, err := cliCtx.QueryStore(key, storeName) if err != nil { return types.BechValidator{}, http.StatusInternalServerError, "couldn't query delegation. Error: ", err @@ -36,7 +36,7 @@ func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delegator return types.BechValidator{}, http.StatusNoContent, "", nil } - key = stake.GetValidatorKey(validatorAddr) + key = stake.GetValidatorKey(valAddr) res, err = cliCtx.QueryStore(key, storeName) if err != nil { return types.BechValidator{}, http.StatusInternalServerError, "couldn't query validator. Error: ", err @@ -44,7 +44,7 @@ func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delegator if len(res) == 0 { return types.BechValidator{}, http.StatusNoContent, "", nil } - validator, err := types.UnmarshalValidator(cdc, validatorAddr, res) + validator, err := types.UnmarshalValidator(cdc, valAddr, res) if err != nil { return types.BechValidator{}, http.StatusBadRequest, "", err } @@ -56,9 +56,11 @@ func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delegator return bech32Validator, http.StatusOK, "", nil } -func getDelegatorDelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) ( +func getDelegatorDelegations( + cliCtx context.CLIContext, cdc *wire.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( outputDelegation DelegationWithoutRat, httpStatusCode int, errMsg string, err error) { - delegationKey := stake.GetDelegationKey(delegatorAddr, validatorAddr) + + delegationKey := stake.GetDelegationKey(delAddr, valAddr) marshalledDelegation, err := cliCtx.QueryStore(delegationKey, storeName) if err != nil { return DelegationWithoutRat{}, http.StatusInternalServerError, "couldn't query delegation. Error: ", err @@ -83,9 +85,11 @@ func getDelegatorDelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegat return outputDelegation, http.StatusOK, "", nil } -func getDelegatorUndelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) ( +func getDelegatorUndelegations( + cliCtx context.CLIContext, cdc *wire.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( unbonds types.UnbondingDelegation, httpStatusCode int, errMsg string, err error) { - undelegationKey := stake.GetUBDKey(delegatorAddr, validatorAddr) + + undelegationKey := stake.GetUBDKey(delAddr, valAddr) marshalledUnbondingDelegation, err := cliCtx.QueryStore(undelegationKey, storeName) if err != nil { return types.UnbondingDelegation{}, http.StatusInternalServerError, "couldn't query unbonding-delegation. Error: ", err @@ -102,10 +106,11 @@ func getDelegatorUndelegations(cliCtx context.CLIContext, cdc *wire.Codec, deleg return unbondingDelegation, http.StatusOK, "", nil } -func getDelegatorRedelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) ( +func getDelegatorRedelegations( + cliCtx context.CLIContext, cdc *wire.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( regelegations types.Redelegation, httpStatusCode int, errMsg string, err error) { - key := stake.GetREDsByDelToValDstIndexKey(delegatorAddr, validatorAddr) + key := stake.GetREDsByDelToValDstIndexKey(delAddr, valAddr) marshalledRedelegations, err := cliCtx.QueryStore(key, storeName) if err != nil { return types.Redelegation{}, http.StatusInternalServerError, "couldn't query redelegation. Error: ", err diff --git a/x/stake/genesis_test.go b/x/stake/genesis_test.go index 9cdbe19826..ddd29f6f84 100644 --- a/x/stake/genesis_test.go +++ b/x/stake/genesis_test.go @@ -23,8 +23,8 @@ func TestInitGenesis(t *testing.T) { var delegations []Delegation validators := []Validator{ - NewValidator(keep.Addrs[0], keep.PKs[0], Description{Moniker: "hoop"}), - NewValidator(keep.Addrs[1], keep.PKs[1], Description{Moniker: "bloop"}), + NewValidator(sdk.ValAddress(keep.Addrs[0]), keep.PKs[0], Description{Moniker: "hoop"}), + NewValidator(sdk.ValAddress(keep.Addrs[1]), keep.PKs[1], Description{Moniker: "bloop"}), } genesisState := types.NewGenesisState(pool, params, validators, delegations) _, err := InitGenesis(ctx, keeper, genesisState) @@ -43,12 +43,12 @@ func TestInitGenesis(t *testing.T) { require.NoError(t, err) // now make sure the validators are bonded and intra-tx counters are correct - resVal, found := keeper.GetValidator(ctx, keep.Addrs[0]) + resVal, found := keeper.GetValidator(ctx, sdk.ValAddress(keep.Addrs[0])) require.True(t, found) require.Equal(t, sdk.Bonded, resVal.Status) require.Equal(t, int16(0), resVal.BondIntraTxCounter) - resVal, found = keeper.GetValidator(ctx, keep.Addrs[1]) + resVal, found = keeper.GetValidator(ctx, sdk.ValAddress(keep.Addrs[1])) require.True(t, found) require.Equal(t, sdk.Bonded, resVal.Status) require.Equal(t, int16(1), resVal.BondIntraTxCounter) @@ -76,7 +76,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { validators := make([]Validator, size) for i := range validators { - validators[i] = NewValidator(keep.Addrs[i], keep.PKs[i], Description{Moniker: fmt.Sprintf("#%d", i)}) + validators[i] = NewValidator(sdk.ValAddress(keep.Addrs[i]), keep.PKs[i], Description{Moniker: fmt.Sprintf("#%d", i)}) validators[i].Status = sdk.Bonded if i < 100 { diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 6ab54e48c2..f7d01bcfc7 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -16,23 +16,23 @@ import ( //______________________________________________________________________ -func newTestMsgCreateValidator(address sdk.AccAddress, pubKey crypto.PubKey, amt int64) MsgCreateValidator { +func newTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt int64) MsgCreateValidator { return types.NewMsgCreateValidator(address, pubKey, sdk.Coin{"steak", sdk.NewInt(amt)}, Description{}) } -func newTestMsgDelegate(delegatorAddr, validatorAddr sdk.AccAddress, amt int64) MsgDelegate { +func newTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt int64) MsgDelegate { return MsgDelegate{ - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, Delegation: sdk.Coin{"steak", sdk.NewInt(amt)}, } } -func newTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr sdk.AccAddress, valPubKey crypto.PubKey, amt int64) MsgCreateValidator { +func newTestMsgCreateValidatorOnBehalfOf(delAddr sdk.AccAddress, valAddr sdk.ValAddress, valPubKey crypto.PubKey, amt int64) MsgCreateValidator { return MsgCreateValidator{ Description: Description{}, - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, PubKey: valPubKey, Delegation: sdk.Coin{"steak", sdk.NewInt(amt)}, } @@ -49,7 +49,7 @@ func setInstantUnbondPeriod(keeper keep.Keeper, ctx sdk.Context) types.Params { //______________________________________________________________________ func TestValidatorByPowerIndex(t *testing.T) { - validatorAddr, validatorAddr3 := keep.Addrs[0], keep.Addrs[1] + validatorAddr, validatorAddr3 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) initBond := int64(1000000) ctx, _, keeper := keep.CreateTestInput(t, false, initBond) @@ -61,7 +61,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // verify the self-delegation exists - bond, found := keeper.GetDelegation(ctx, validatorAddr, validatorAddr) + bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) require.True(t, found) gotBond := bond.Shares.RoundInt64() require.Equal(t, initBond, gotBond, @@ -110,8 +110,8 @@ func TestValidatorByPowerIndex(t *testing.T) { require.Equal(t, power2, power3) // unbond self-delegation - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(1000000)) - msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) + msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(1000000)) + msgCompleteUnbonding := NewMsgCompleteUnbonding(sdk.AccAddress(validatorAddr), validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper) @@ -126,7 +126,7 @@ func TestValidatorByPowerIndex(t *testing.T) { func TestDuplicatesMsgCreateValidator(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - addr1, addr2 := keep.Addrs[0], keep.Addrs[1] + addr1, addr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) pk1, pk2 := keep.PKs[0], keep.PKs[1] msgCreateValidator1 := newTestMsgCreateValidator(addr1, pk1, 10) @@ -170,7 +170,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr := keep.Addrs[0] + validatorAddr := sdk.ValAddress(keep.Addrs[0]) delegatorAddr := keep.Addrs[1] pk := keep.PKs[0] msgCreateValidatorOnBehalfOf := newTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, 10) @@ -199,7 +199,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { params := keeper.GetParams(ctx) bondAmount := int64(10) - validatorAddr, delegatorAddr := keep.Addrs[0], keep.Addrs[1] + validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] // first create validator msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], bondAmount) @@ -215,7 +215,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { _, found = keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) require.False(t, found) - bond, found := keeper.GetDelegation(ctx, validatorAddr, validatorAddr) + bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) require.True(t, found) require.Equal(t, bondAmount, bond.Shares.RoundInt64()) @@ -271,7 +271,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { denom := params.BondDenom // create validator, delegate - validatorAddr, delegatorAddr := keep.Addrs[0], keep.Addrs[1] + validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) @@ -367,7 +367,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { ctx, accMapper, keeper := keep.CreateTestInput(t, false, initBond) params := setInstantUnbondPeriod(keeper, ctx) - validatorAddrs := []sdk.AccAddress{keep.Addrs[0], keep.Addrs[1], keep.Addrs[2]} + validatorAddrs := []sdk.ValAddress{sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), sdk.ValAddress(keep.Addrs[2])} delegatorAddrs := []sdk.AccAddress{keep.Addrs[3], keep.Addrs[4], keep.Addrs[5]} // bond them all @@ -414,7 +414,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { func TestMultipleMsgDelegate(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr, delegatorAddrs := keep.Addrs[0], keep.Addrs[1:] + validatorAddr, delegatorAddrs := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1:] _ = setInstantUnbondPeriod(keeper, ctx) //first make a validator @@ -451,7 +451,7 @@ func TestMultipleMsgDelegate(t *testing.T) { func TestJailValidator(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr, delegatorAddr := keep.Addrs[0], keep.Addrs[1] + validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] _ = setInstantUnbondPeriod(keeper, ctx) // create the validator @@ -467,8 +467,8 @@ func TestJailValidator(t *testing.T) { validator, _ := keeper.GetValidator(ctx, validatorAddr) // unbond the validators bond portion - msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) - msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) + msgBeginUnbondingValidator := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10)) + msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(sdk.AccAddress(validatorAddr), validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper) require.True(t, got.IsOK(), "expected no error") got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbondingValidator, keeper) @@ -497,7 +497,7 @@ func TestJailValidator(t *testing.T) { func TestUnbondingPeriod(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr := keep.Addrs[0] + validatorAddr := sdk.ValAddress(keep.Addrs[0]) // set the unbonding time params := keeper.GetParams(ctx) @@ -510,12 +510,12 @@ func TestUnbondingPeriod(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin unbonding - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10)) + msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error") // cannot complete unbonding at same time - msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) + msgCompleteUnbonding := NewMsgCompleteUnbonding(sdk.AccAddress(validatorAddr), validatorAddr) got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper) require.True(t, !got.IsOK(), "expected an error") @@ -537,7 +537,7 @@ func TestUnbondingPeriod(t *testing.T) { func TestRedelegationPeriod(t *testing.T) { ctx, AccMapper, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr, validatorAddr2 := keep.Addrs[0], keep.Addrs[1] + validatorAddr, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) denom := keeper.GetParams(ctx).BondDenom // set the unbonding time @@ -549,32 +549,32 @@ func TestRedelegationPeriod(t *testing.T) { msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10) // initial balance - amt1 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins().AmountOf(denom) + amt1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom) got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // balance should have been subtracted after creation - amt2 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins().AmountOf(denom) + amt2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom) require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted") msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 10) got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") - bal1 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins() + bal1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins() // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) + msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) // origin account should not lose tokens as with a regular delegation - bal2 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins() + bal2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins() require.Equal(t, bal1, bal2) // cannot complete redelegation at same time - msgCompleteRedelegate := NewMsgCompleteRedelegate(validatorAddr, validatorAddr, validatorAddr2) + msgCompleteRedelegate := NewMsgCompleteRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper) require.True(t, !got.IsOK(), "expected an error") @@ -596,7 +596,9 @@ func TestRedelegationPeriod(t *testing.T) { func TestTransitiveRedelegation(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr, validatorAddr2, validatorAddr3 := keep.Addrs[0], keep.Addrs[1], keep.Addrs[2] + validatorAddr := sdk.ValAddress(keep.Addrs[0]) + validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) + validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) // set the unbonding time params := keeper.GetParams(ctx) @@ -617,17 +619,17 @@ func TestTransitiveRedelegation(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10)) + msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) // cannot redelegation to next validator while first delegation exists - msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewDec(10)) + msgBeginRedelegate = NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, sdk.NewDec(10)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate) // complete first redelegation - msgCompleteRedelegate := NewMsgCompleteRedelegate(validatorAddr, validatorAddr, validatorAddr2) + msgCompleteRedelegate := NewMsgCompleteRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2) got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper) require.True(t, got.IsOK(), "expected no error") @@ -638,7 +640,9 @@ func TestTransitiveRedelegation(t *testing.T) { func TestUnbondingWhenExcessValidators(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr1, validatorAddr2, validatorAddr3 := keep.Addrs[0], keep.Addrs[1], keep.Addrs[2] + validatorAddr1 := sdk.ValAddress(keep.Addrs[0]) + validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) + validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) // set the unbonding time params := keeper.GetParams(ctx) @@ -663,7 +667,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx))) // unbond the valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) + msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr2), validatorAddr2, sdk.NewDec(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -679,7 +683,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { func TestJoiningAsCliffValidator(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr1, validatorAddr2 := keep.Addrs[0], keep.Addrs[1] + validatorAddr1, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) // make sure that the cliff validator is nil to begin with cliffVal := keeper.GetCliffValidator(ctx) @@ -712,7 +716,7 @@ func TestJoiningAsCliffValidator(t *testing.T) { func TestJoiningToCreateFirstCliffValidator(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr1, validatorAddr2 := keep.Addrs[0], keep.Addrs[1] + validatorAddr1, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) // make sure that the cliff validator is nil to begin with cliffVal := keeper.GetCliffValidator(ctx) @@ -745,7 +749,9 @@ func TestJoiningToCreateFirstCliffValidator(t *testing.T) { func TestCliffValidator(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr1, validatorAddr2, validatorAddr3 := keep.Addrs[0], keep.Addrs[1], keep.Addrs[2] + validatorAddr1 := sdk.ValAddress(keep.Addrs[0]) + validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) + validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) // make sure that the cliff validator is nil to begin with cliffVal := keeper.GetCliffValidator(ctx) @@ -785,7 +791,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr2.Bytes(), cliffVal) // unbond valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30)) + msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr2), validatorAddr2, sdk.NewDec(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -798,7 +804,7 @@ func TestCliffValidator(t *testing.T) { require.Equal(t, validatorAddr3.Bytes(), cliffVal) // unbond valdator-1 - msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewDec(50)) + msgBeginUnbonding = NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr1), validatorAddr1, sdk.NewDec(50)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") @@ -813,7 +819,7 @@ func TestCliffValidator(t *testing.T) { func TestBondUnbondRedelegateSlashTwice(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - valA, valB, del := keep.Addrs[0], keep.Addrs[1], keep.Addrs[2] + valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2] msgCreateValidator := newTestMsgCreateValidator(valA, keep.PKs[0], 10) got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index a6e48517c9..9f7a402fc2 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -9,10 +9,11 @@ import ( // load a delegation func (k Keeper) GetDelegation(ctx sdk.Context, - delegatorAddr, validatorAddr sdk.AccAddress) (delegation types.Delegation, found bool) { + delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( + delegation types.Delegation, found bool) { store := ctx.KVStore(k.storeKey) - key := GetDelegationKey(delegatorAddr, validatorAddr) + key := GetDelegationKey(delAddr, valAddr) value := store.Get(key) if value == nil { return delegation, false @@ -79,10 +80,10 @@ func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) { // load a unbonding delegation func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, - DelegatorAddr, ValidatorAddr sdk.AccAddress) (ubd types.UnbondingDelegation, found bool) { + delAddr sdk.AccAddress, valAddr sdk.ValAddress) (ubd types.UnbondingDelegation, found bool) { store := ctx.KVStore(k.storeKey) - key := GetUBDKey(DelegatorAddr, ValidatorAddr) + key := GetUBDKey(delAddr, valAddr) value := store.Get(key) if value == nil { return ubd, false @@ -93,7 +94,7 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, } // load all unbonding delegations from a particular validator -func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.AccAddress) (ubds []types.UnbondingDelegation) { +func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAddress) (ubds []types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr)) for { @@ -147,10 +148,10 @@ func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDe // load a redelegation func (k Keeper) GetRedelegation(ctx sdk.Context, - DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr sdk.AccAddress) (red types.Redelegation, found bool) { + delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) (red types.Redelegation, found bool) { store := ctx.KVStore(k.storeKey) - key := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr) + key := GetREDKey(delAddr, valSrcAddr, valDstAddr) value := store.Get(key) if value == nil { return red, false @@ -161,7 +162,7 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, } // load all redelegations from a particular validator -func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.AccAddress) (reds []types.Redelegation) { +func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAddress) (reds []types.Redelegation) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr)) for { @@ -180,10 +181,10 @@ func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.AccAd // has a redelegation func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, - DelegatorAddr, ValidatorDstAddr sdk.AccAddress) bool { + delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) bool { store := ctx.KVStore(k.storeKey) - prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr) + prefix := GetREDsByDelToValDstIndexKey(delAddr, valDstAddr) iterator := sdk.KVStorePrefixIterator(store, prefix) //smallest to largest found := false @@ -217,14 +218,14 @@ func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) { //_____________________________________________________________________________________ // Perform a delegation, set/update everything necessary within the store. -func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt sdk.Coin, +func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Coin, validator types.Validator, subtractAccount bool) (newShares sdk.Dec, err sdk.Error) { // Get or create the delegator delegation - delegation, found := k.GetDelegation(ctx, delegatorAddr, validator.Operator) + delegation, found := k.GetDelegation(ctx, delAddr, validator.Operator) if !found { delegation = types.Delegation{ - DelegatorAddr: delegatorAddr, + DelegatorAddr: delAddr, ValidatorAddr: validator.Operator, Shares: sdk.ZeroDec(), } @@ -253,11 +254,11 @@ func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt } // unbond the the delegation return -func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, +func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, shares sdk.Dec) (amount sdk.Dec, err sdk.Error) { // check if delegation has any shares in it unbond - delegation, found := k.GetDelegation(ctx, delegatorAddr, validatorAddr) + delegation, found := k.GetDelegation(ctx, delAddr, valAddr) if !found { err = types.ErrNoDelegatorForAddress(k.Codespace()) return @@ -270,7 +271,7 @@ func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddr } // get validator - validator, found := k.GetValidator(ctx, validatorAddr) + validator, found := k.GetValidator(ctx, valAddr) if !found { err = types.ErrNoValidatorFound(k.Codespace()) return @@ -312,15 +313,16 @@ func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddr //______________________________________________________________________________________________________ // complete unbonding an unbonding record -func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Dec) sdk.Error { +func (k Keeper) BeginUnbonding(ctx sdk.Context, + delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) sdk.Error { // TODO quick fix, instead we should use an index, see https://github.com/cosmos/cosmos-sdk/issues/1402 - _, found := k.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) + _, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr) if found { return types.ErrExistingUnbondingDelegation(k.Codespace()) } - returnAmount, err := k.unbond(ctx, delegatorAddr, validatorAddr, sharesAmount) + returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount) if err != nil { return err } @@ -331,8 +333,8 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk balance := sdk.Coin{params.BondDenom, returnAmount.RoundInt()} ubd := types.UnbondingDelegation{ - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, MinTime: minTime, Balance: balance, InitialBalance: balance, @@ -342,9 +344,9 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk } // complete unbonding an unbonding record -func (k Keeper) CompleteUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress) sdk.Error { +func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) sdk.Error { - ubd, found := k.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) + ubd, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr) if !found { return types.ErrNoUnbondingDelegation(k.Codespace()) } @@ -364,26 +366,26 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr } // complete unbonding an unbonding record -func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.AccAddress, sharesAmount sdk.Dec) sdk.Error { +func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, + valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) sdk.Error { // check if this is a transitive redelegation - if k.HasReceivingRedelegation(ctx, delegatorAddr, validatorSrcAddr) { + if k.HasReceivingRedelegation(ctx, delAddr, valSrcAddr) { return types.ErrTransitiveRedelegation(k.Codespace()) } - returnAmount, err := k.unbond(ctx, delegatorAddr, validatorSrcAddr, sharesAmount) + returnAmount, err := k.unbond(ctx, delAddr, valSrcAddr, sharesAmount) if err != nil { return err } params := k.GetParams(ctx) returnCoin := sdk.Coin{params.BondDenom, returnAmount.RoundInt()} - dstValidator, found := k.GetValidator(ctx, validatorDstAddr) + dstValidator, found := k.GetValidator(ctx, valDstAddr) if !found { return types.ErrBadRedelegationDst(k.Codespace()) } - sharesCreated, err := k.Delegate(ctx, delegatorAddr, returnCoin, dstValidator, false) + sharesCreated, err := k.Delegate(ctx, delAddr, returnCoin, dstValidator, false) if err != nil { return err } @@ -392,9 +394,9 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAd minTime := ctx.BlockHeader().Time.Add(params.UnbondingTime) red := types.Redelegation{ - DelegatorAddr: delegatorAddr, - ValidatorSrcAddr: validatorSrcAddr, - ValidatorDstAddr: validatorDstAddr, + DelegatorAddr: delAddr, + ValidatorSrcAddr: valSrcAddr, + ValidatorDstAddr: valDstAddr, MinTime: minTime, SharesDst: sharesCreated, SharesSrc: sharesAmount, @@ -406,9 +408,10 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAd } // complete unbonding an ongoing redelegation -func (k Keeper) CompleteRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) sdk.Error { +func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, + valSrcAddr, valDstAddr sdk.ValAddress) sdk.Error { - red, found := k.GetRedelegation(ctx, delegatorAddr, validatorSrcAddr, validatorDstAddr) + red, found := k.GetRedelegation(ctx, delAddr, valSrcAddr, valDstAddr) if !found { return types.ErrNoRedelegation(k.Codespace()) } diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 958de62ed5..d539c35d05 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -36,8 +36,8 @@ const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch // gets the key for the validator with address // VALUE: stake/types.Validator -func GetValidatorKey(ownerAddr sdk.AccAddress) []byte { - return append(ValidatorsKey, ownerAddr.Bytes()...) +func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { + return append(ValidatorsKey, operatorAddr.Bytes()...) } // gets the key for the validator with pubkey @@ -48,8 +48,8 @@ func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte { // gets the key for the current validator group // VALUE: none (key rearrangement with GetValKeyFromValBondedIndexKey) -func GetValidatorsBondedIndexKey(ownerAddr sdk.AccAddress) []byte { - return append(ValidatorsBondedIndexKey, ownerAddr.Bytes()...) +func GetValidatorsBondedIndexKey(operatorAddr sdk.ValAddress) []byte { + return append(ValidatorsBondedIndexKey, operatorAddr.Bytes()...) } // Get the validator owner address from ValBondedIndexKey @@ -97,37 +97,37 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { // get the key for the accumulated update validators // VALUE: abci.Validator // note records using these keys should never persist between blocks -func GetTendermintUpdatesKey(ownerAddr sdk.AccAddress) []byte { - return append(TendermintUpdatesKey, ownerAddr.Bytes()...) +func GetTendermintUpdatesKey(operatorAddr sdk.ValAddress) []byte { + return append(TendermintUpdatesKey, operatorAddr.Bytes()...) } //______________________________________________________________________________ // gets the key for delegator bond with validator // VALUE: stake/types.Delegation -func GetDelegationKey(delegatorAddr, validatorAddr sdk.AccAddress) []byte { - return append(GetDelegationsKey(delegatorAddr), validatorAddr.Bytes()...) +func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { + return append(GetDelegationsKey(delAddr), valAddr.Bytes()...) } // gets the prefix for a delegator for all validators -func GetDelegationsKey(delegatorAddr sdk.AccAddress) []byte { - return append(DelegationKey, delegatorAddr.Bytes()...) +func GetDelegationsKey(delAddr sdk.AccAddress) []byte { + return append(DelegationKey, delAddr.Bytes()...) } //______________________________________________________________________________ // gets the key for an unbonding delegation by delegator and validator addr // VALUE: stake/types.UnbondingDelegation -func GetUBDKey(delegatorAddr, validatorAddr sdk.AccAddress) []byte { +func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { return append( - GetUBDsKey(delegatorAddr.Bytes()), - validatorAddr.Bytes()...) + GetUBDsKey(delAddr.Bytes()), + valAddr.Bytes()...) } // gets the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) -func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.AccAddress) []byte { - return append(GetUBDsByValIndexKey(validatorAddr), delegatorAddr.Bytes()...) +func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { + return append(GetUBDsByValIndexKey(valAddr), delAddr.Bytes()...) } // rearranges the ValIndexKey to get the UBDKey @@ -144,42 +144,42 @@ func GetUBDKeyFromValIndexKey(IndexKey []byte) []byte { //______________ // gets the prefix for all unbonding delegations from a delegator -func GetUBDsKey(delegatorAddr sdk.AccAddress) []byte { - return append(UnbondingDelegationKey, delegatorAddr.Bytes()...) +func GetUBDsKey(delAddr sdk.AccAddress) []byte { + return append(UnbondingDelegationKey, delAddr.Bytes()...) } // gets the prefix keyspace for the indexes of unbonding delegations for a validator -func GetUBDsByValIndexKey(validatorAddr sdk.AccAddress) []byte { - return append(UnbondingDelegationByValIndexKey, validatorAddr.Bytes()...) +func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { + return append(UnbondingDelegationByValIndexKey, valAddr.Bytes()...) } //________________________________________________________________________________ // gets the key for a redelegation // VALUE: stake/types.RedelegationKey -func GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) []byte { +func GetREDKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { return append(append( - GetREDsKey(delegatorAddr.Bytes()), - validatorSrcAddr.Bytes()...), - validatorDstAddr.Bytes()...) + GetREDsKey(delAddr.Bytes()), + valSrcAddr.Bytes()...), + valDstAddr.Bytes()...) } // gets the index-key for a redelegation, stored by source-validator-index // VALUE: none (key rearrangement used) -func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) []byte { +func GetREDByValSrcIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { return append(append( - GetREDsFromValSrcIndexKey(validatorSrcAddr), - delegatorAddr.Bytes()...), - validatorDstAddr.Bytes()...) + GetREDsFromValSrcIndexKey(valSrcAddr), + delAddr.Bytes()...), + valDstAddr.Bytes()...) } // gets the index-key for a redelegation, stored by destination-validator-index // VALUE: none (key rearrangement used) -func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) []byte { +func GetREDByValDstIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { return append(append( - GetREDsToValDstIndexKey(validatorDstAddr), - delegatorAddr.Bytes()...), - validatorSrcAddr.Bytes()...) + GetREDsToValDstIndexKey(valDstAddr), + delAddr.Bytes()...), + valSrcAddr.Bytes()...) } // rearranges the ValSrcIndexKey to get the REDKey @@ -210,24 +210,24 @@ func GetREDKeyFromValDstIndexKey(IndexKey []byte) []byte { //______________ // gets the prefix keyspace for redelegations from a delegator -func GetREDsKey(delegatorAddr sdk.AccAddress) []byte { - return append(RedelegationKey, delegatorAddr.Bytes()...) +func GetREDsKey(delAddr sdk.AccAddress) []byte { + return append(RedelegationKey, delAddr.Bytes()...) } // gets the prefix keyspace for all redelegations redelegating away from a source validator -func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.AccAddress) []byte { - return append(RedelegationByValSrcIndexKey, validatorSrcAddr.Bytes()...) +func GetREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte { + return append(RedelegationByValSrcIndexKey, valSrcAddr.Bytes()...) } // gets the prefix keyspace for all redelegations redelegating towards a destination validator -func GetREDsToValDstIndexKey(validatorDstAddr sdk.AccAddress) []byte { - return append(RedelegationByValDstIndexKey, validatorDstAddr.Bytes()...) +func GetREDsToValDstIndexKey(valDstAddr sdk.ValAddress) []byte { + return append(RedelegationByValDstIndexKey, valDstAddr.Bytes()...) } // gets the prefix keyspace for all redelegations redelegating towards a destination validator // from a particular delegator -func GetREDsByDelToValDstIndexKey(delegatorAddr, validatorDstAddr sdk.AccAddress) []byte { +func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) []byte { return append( - GetREDsToValDstIndexKey(validatorDstAddr), - delegatorAddr.Bytes()...) + GetREDsToValDstIndexKey(valDstAddr), + delAddr.Bytes()...) } diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index aeec44fae9..480df701b1 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -51,7 +51,7 @@ func (k Keeper) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, va } // get the sdk.validator for a particular address -func (k Keeper) Validator(ctx sdk.Context, address sdk.AccAddress) sdk.Validator { +func (k Keeper) Validator(ctx sdk.Context, address sdk.ValAddress) sdk.Validator { val, found := k.GetValidator(ctx, address) if !found { return nil @@ -86,7 +86,7 @@ func (k Keeper) GetValidatorSet() sdk.ValidatorSet { } // get the delegation for a particular set of delegator and validator addresses -func (k Keeper) Delegation(ctx sdk.Context, addrDel sdk.AccAddress, addrVal sdk.AccAddress) sdk.Delegation { +func (k Keeper) Delegation(ctx sdk.Context, addrDel sdk.AccAddress, addrVal sdk.ValAddress) sdk.Delegation { bond, ok := k.GetDelegation(ctx, addrDel, addrVal) if !ok { return nil diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 0470c28988..b84ce9d93a 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -33,12 +33,12 @@ var ( Addrs[0], Addrs[1], } - addrVals = []sdk.AccAddress{ - Addrs[2], - Addrs[3], - Addrs[4], - Addrs[5], - Addrs[6], + addrVals = []sdk.ValAddress{ + sdk.ValAddress(Addrs[2]), + sdk.ValAddress(Addrs[3]), + sdk.ValAddress(Addrs[4]), + sdk.ValAddress(Addrs[5]), + sdk.ValAddress(Addrs[6]), } ) diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index e933a6d236..cb225df6cc 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -12,7 +12,7 @@ import ( ) // get a single validator -func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.AccAddress) (validator types.Validator, found bool) { +func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator types.Validator, found bool) { store := ctx.KVStore(k.storeKey) value := store.Get(GetValidatorKey(addr)) if value == nil { @@ -223,7 +223,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type store.Set(GetTendermintUpdatesKey(validator.Operator), bz) if cliffPower != nil { - cliffAddr := sdk.AccAddress(k.GetCliffValidator(ctx)) + cliffAddr := sdk.ValAddress(k.GetCliffValidator(ctx)) if bytes.Equal(cliffAddr, validator.Operator) { k.updateCliffValidator(ctx, validator) } @@ -273,7 +273,7 @@ func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validato store := ctx.KVStore(k.storeKey) pool := k.GetPool(ctx) - cliffAddr := sdk.AccAddress(k.GetCliffValidator(ctx)) + cliffAddr := sdk.ValAddress(k.GetCliffValidator(ctx)) oldCliffVal, found := k.GetValidator(ctx, cliffAddr) if !found { @@ -621,7 +621,7 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. } // remove the validator record and associated indexes -func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.AccAddress) { +func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { // first retrieve the old validator record validator, found := k.GetValidator(ctx, address) diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 9e92ca33e7..e4a2663ae6 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -109,7 +109,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { validators := make([]types.Validator, numVals) for i := 0; i < len(validators); i++ { moniker := fmt.Sprintf("val#%d", int64(i)) - val := types.NewValidator(Addrs[i], PKs[i], types.Description{Moniker: moniker}) + val := types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) val.BondHeight = int64(i) val.BondIntraTxCounter = int16(i) val, pool, _ = val.AddTokensFromDel(pool, sdk.NewInt(int64((i+1)*10))) @@ -129,7 +129,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { // require the cliff validator has changed cliffVal := validators[numVals-maxVals-1] - require.Equal(t, cliffVal.Operator, sdk.AccAddress(keeper.GetCliffValidator(ctx))) + require.Equal(t, cliffVal.Operator, sdk.ValAddress(keeper.GetCliffValidator(ctx))) // require the cliff validator power has changed cliffPower := keeper.GetCliffValidatorPower(ctx) @@ -172,7 +172,7 @@ func TestCliffValidatorChange(t *testing.T) { validators := make([]types.Validator, numVals) for i := 0; i < len(validators); i++ { moniker := fmt.Sprintf("val#%d", int64(i)) - val := types.NewValidator(Addrs[i], PKs[i], types.Description{Moniker: moniker}) + val := types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) val.BondHeight = int64(i) val.BondIntraTxCounter = int16(i) val, pool, _ = val.AddTokensFromDel(pool, sdk.NewInt(int64((i+1)*10))) @@ -190,7 +190,7 @@ func TestCliffValidatorChange(t *testing.T) { // assert new cliff validator to be set to the second lowest bonded validator by power newCliffVal := validators[numVals-maxVals+1] - require.Equal(t, newCliffVal.Operator, sdk.AccAddress(keeper.GetCliffValidator(ctx))) + require.Equal(t, newCliffVal.Operator, sdk.ValAddress(keeper.GetCliffValidator(ctx))) // assert cliff validator power should have been updated cliffPower := keeper.GetCliffValidatorPower(ctx) @@ -203,7 +203,7 @@ func TestCliffValidatorChange(t *testing.T) { // assert cliff validator has not change but increased in power cliffPower = keeper.GetCliffValidatorPower(ctx) - require.Equal(t, newCliffVal.Operator, sdk.AccAddress(keeper.GetCliffValidator(ctx))) + require.Equal(t, newCliffVal.Operator, sdk.ValAddress(keeper.GetCliffValidator(ctx))) require.Equal(t, GetValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) // add enough power to cliff validator to be equal in rank to next validator @@ -213,7 +213,7 @@ func TestCliffValidatorChange(t *testing.T) { // assert new cliff validator due to power rank construction newCliffVal = validators[numVals-maxVals+2] - require.Equal(t, newCliffVal.Operator, sdk.AccAddress(keeper.GetCliffValidator(ctx))) + require.Equal(t, newCliffVal.Operator, sdk.ValAddress(keeper.GetCliffValidator(ctx))) // assert cliff validator power should have been updated cliffPower = keeper.GetCliffValidatorPower(ctx) @@ -329,7 +329,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { n := len(amts) var validators [5]types.Validator for i, amt := range amts { - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i].Status = sdk.Bonded validators[i].Tokens = sdk.NewDec(amt) validators[i].DelegatorShares = sdk.NewDec(amt) @@ -412,7 +412,7 @@ func GetValidatorSortingMixed(t *testing.T) { n := len(amts) var validators [5]types.Validator for i, amt := range amts { - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i].DelegatorShares = sdk.NewDec(amt) } @@ -431,15 +431,15 @@ func GetValidatorSortingMixed(t *testing.T) { for i := range amts { keeper.UpdateValidator(ctx, validators[i]) } - val0, found := keeper.GetValidator(ctx, Addrs[0]) + val0, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[0])) require.True(t, found) - val1, found := keeper.GetValidator(ctx, Addrs[1]) + val1, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[1])) require.True(t, found) - val2, found := keeper.GetValidator(ctx, Addrs[2]) + val2, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[2])) require.True(t, found) - val3, found := keeper.GetValidator(ctx, Addrs[3]) + val3, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[3])) require.True(t, found) - val4, found := keeper.GetValidator(ctx, Addrs[4]) + val4, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[4])) require.True(t, found) require.Equal(t, sdk.Unbonded, val0.Status) require.Equal(t, sdk.Unbonded, val1.Status) @@ -479,7 +479,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { for i, amt := range amts { pool := keeper.GetPool(ctx) moniker := fmt.Sprintf("val#%d", int64(i)) - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{Moniker: moniker}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) validators[i] = keeper.UpdateValidator(ctx, validators[i]) @@ -553,9 +553,9 @@ func TestValidatorBondHeight(t *testing.T) { // initialize some validators into the state var validators [3]types.Validator - validators[0] = types.NewValidator(Addrs[0], PKs[0], types.Description{}) - validators[1] = types.NewValidator(Addrs[1], PKs[1], types.Description{}) - validators[2] = types.NewValidator(Addrs[2], PKs[2], types.Description{}) + validators[0] = types.NewValidator(sdk.ValAddress(Addrs[0]), PKs[0], types.Description{}) + validators[1] = types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{}) + validators[2] = types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{}) validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(200)) validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(100)) @@ -600,7 +600,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { var validators [5]types.Validator for i, amt := range amts { pool := keeper.GetPool(ctx) - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) keeper.UpdateValidator(ctx, validators[i]) @@ -639,7 +639,7 @@ func TestClearTendermintUpdates(t *testing.T) { validators := make([]types.Validator, len(amts)) for i, amt := range amts { pool := keeper.GetPool(ctx) - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) keeper.UpdateValidator(ctx, validators[i]) @@ -659,7 +659,7 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) { var validators [2]types.Validator for i, amt := range amts { pool := keeper.GetPool(ctx) - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } @@ -698,7 +698,7 @@ func TestGetTendermintUpdatesIdentical(t *testing.T) { var validators [2]types.Validator for i, amt := range amts { pool := keeper.GetPool(ctx) - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } @@ -721,7 +721,7 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { var validators [2]types.Validator for i, amt := range amts { pool := keeper.GetPool(ctx) - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } @@ -749,7 +749,7 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) { var validators [2]types.Validator for i, amt := range amts { pool := keeper.GetPool(ctx) - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } @@ -780,7 +780,7 @@ func TestGetTendermintUpdatesInserted(t *testing.T) { var validators [5]types.Validator for i, amt := range amts { pool := keeper.GetPool(ctx) - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } @@ -823,7 +823,7 @@ func TestGetTendermintUpdatesWithCliffValidator(t *testing.T) { var validators [5]types.Validator for i, amt := range amts { pool := keeper.GetPool(ctx) - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } @@ -861,7 +861,7 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { var validators [2]types.Validator for i, amt := range amts { pool := keeper.GetPool(ctx) - validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{}) + validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } diff --git a/x/stake/simulation/msgs.go b/x/stake/simulation/msgs.go index 4280e70c13..97ed112c01 100644 --- a/x/stake/simulation/msgs.go +++ b/x/stake/simulation/msgs.go @@ -26,8 +26,8 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation } key := simulation.RandomKey(r, keys) pubkey := key.PubKey() - address := sdk.AccAddress(pubkey.Address()) - amount := m.GetAccount(ctx, address).GetCoins().AmountOf(denom) + address := sdk.ValAddress(pubkey.Address()) + amount := m.GetAccount(ctx, sdk.AccAddress(address)).GetCoins().AmountOf(denom) if amount.GT(sdk.ZeroInt()) { amount = simulation.RandomAmount(r, amount) } @@ -37,7 +37,7 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation msg := stake.MsgCreateValidator{ Description: description, ValidatorAddr: address, - DelegatorAddr: address, + DelegatorAddr: sdk.AccAddress(address), PubKey: pubkey, Delegation: sdk.NewCoin(denom, amount), } @@ -65,7 +65,7 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation { } key := simulation.RandomKey(r, keys) pubkey := key.PubKey() - address := sdk.AccAddress(pubkey.Address()) + address := sdk.ValAddress(pubkey.Address()) msg := stake.MsgEditValidator{ Description: description, ValidatorAddr: address, @@ -87,7 +87,7 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) { denom := k.GetParams(ctx).BondDenom validatorKey := simulation.RandomKey(r, keys) - validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address()) + validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address()) delegatorKey := simulation.RandomKey(r, keys) delegatorAddress := sdk.AccAddress(delegatorKey.PubKey().Address()) amount := m.GetAccount(ctx, delegatorAddress).GetCoins().AmountOf(denom) @@ -119,7 +119,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) { denom := k.GetParams(ctx).BondDenom validatorKey := simulation.RandomKey(r, keys) - validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address()) + validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address()) delegatorKey := simulation.RandomKey(r, keys) delegatorAddress := sdk.AccAddress(delegatorKey.PubKey().Address()) amount := m.GetAccount(ctx, delegatorAddress).GetCoins().AmountOf(denom) @@ -150,7 +150,7 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation. func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation { return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) { validatorKey := simulation.RandomKey(r, keys) - validatorAddress := sdk.AccAddress(validatorKey.PubKey().Address()) + validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address()) delegatorKey := simulation.RandomKey(r, keys) delegatorAddress := sdk.AccAddress(delegatorKey.PubKey().Address()) msg := stake.MsgCompleteUnbonding{ @@ -174,9 +174,9 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) { denom := k.GetParams(ctx).BondDenom sourceValidatorKey := simulation.RandomKey(r, keys) - sourceValidatorAddress := sdk.AccAddress(sourceValidatorKey.PubKey().Address()) + sourceValidatorAddress := sdk.ValAddress(sourceValidatorKey.PubKey().Address()) destValidatorKey := simulation.RandomKey(r, keys) - destValidatorAddress := sdk.AccAddress(destValidatorKey.PubKey().Address()) + destValidatorAddress := sdk.ValAddress(destValidatorKey.PubKey().Address()) delegatorKey := simulation.RandomKey(r, keys) delegatorAddress := sdk.AccAddress(delegatorKey.PubKey().Address()) // TODO @@ -209,9 +209,9 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation { return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) { validatorSrcKey := simulation.RandomKey(r, keys) - validatorSrcAddress := sdk.AccAddress(validatorSrcKey.PubKey().Address()) + validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address()) validatorDstKey := simulation.RandomKey(r, keys) - validatorDstAddress := sdk.AccAddress(validatorDstKey.PubKey().Address()) + validatorDstAddress := sdk.ValAddress(validatorDstKey.PubKey().Address()) delegatorKey := simulation.RandomKey(r, keys) delegatorAddress := sdk.AccAddress(delegatorKey.PubKey().Address()) msg := stake.MsgCompleteRedelegate{ diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index e3227c3ed1..5a2274c3ae 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -14,7 +14,7 @@ import ( // pubKey. type Delegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` - ValidatorAddr sdk.AccAddress `json:"validator_addr"` + ValidatorAddr sdk.ValAddress `json:"validator_addr"` Shares sdk.Dec `json:"shares"` Height int64 `json:"height"` // Last height bond updated } @@ -56,8 +56,9 @@ func UnmarshalDelegation(cdc *wire.Codec, key, value []byte) (delegation Delegat err = fmt.Errorf("%v", ErrBadDelegationAddr(DefaultCodespace).Data()) return } + delAddr := sdk.AccAddress(addrs[:sdk.AddrLen]) - valAddr := sdk.AccAddress(addrs[sdk.AddrLen:]) + valAddr := sdk.ValAddress(addrs[sdk.AddrLen:]) return Delegation{ DelegatorAddr: delAddr, @@ -80,7 +81,7 @@ var _ sdk.Delegation = Delegation{} // nolint - for sdk.Delegation func (d Delegation) GetDelegator() sdk.AccAddress { return d.DelegatorAddr } -func (d Delegation) GetValidator() sdk.AccAddress { return d.ValidatorAddr } +func (d Delegation) GetValidator() sdk.ValAddress { return d.ValidatorAddr } func (d Delegation) GetBondShares() sdk.Dec { return d.Shares } // HumanReadableString returns a human readable string representation of a @@ -99,7 +100,7 @@ func (d Delegation) HumanReadableString() (string, error) { // UnbondingDelegation reflects a delegation's passive unbonding queue. type UnbondingDelegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator - ValidatorAddr sdk.AccAddress `json:"validator_addr"` // validator unbonding from owner addr + ValidatorAddr sdk.ValAddress `json:"validator_addr"` // validator unbonding from operator addr CreationHeight int64 `json:"creation_height"` // height which the unbonding took place MinTime time.Time `json:"min_time"` // unix time for unbonding completion InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion @@ -147,7 +148,7 @@ func UnmarshalUBD(cdc *wire.Codec, key, value []byte) (ubd UnbondingDelegation, return } delAddr := sdk.AccAddress(addrs[:sdk.AddrLen]) - valAddr := sdk.AccAddress(addrs[sdk.AddrLen:]) + valAddr := sdk.ValAddress(addrs[sdk.AddrLen:]) return UnbondingDelegation{ DelegatorAddr: delAddr, @@ -184,8 +185,8 @@ func (d UnbondingDelegation) HumanReadableString() (string, error) { // Redelegation reflects a delegation's passive re-delegation queue. type Redelegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator - ValidatorSrcAddr sdk.AccAddress `json:"validator_src_addr"` // validator redelegation source owner addr - ValidatorDstAddr sdk.AccAddress `json:"validator_dst_addr"` // validator redelegation destination owner addr + ValidatorSrcAddr sdk.ValAddress `json:"validator_src_addr"` // validator redelegation source operator addr + ValidatorDstAddr sdk.ValAddress `json:"validator_dst_addr"` // validator redelegation destination operator addr CreationHeight int64 `json:"creation_height"` // height which the redelegation took place MinTime time.Time `json:"min_time"` // unix time for redelegation completion InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started @@ -239,8 +240,8 @@ func UnmarshalRED(cdc *wire.Codec, key, value []byte) (red Redelegation, err err return } delAddr := sdk.AccAddress(addrs[:sdk.AddrLen]) - valSrcAddr := sdk.AccAddress(addrs[sdk.AddrLen : 2*sdk.AddrLen]) - valDstAddr := sdk.AccAddress(addrs[2*sdk.AddrLen:]) + valSrcAddr := sdk.ValAddress(addrs[sdk.AddrLen : 2*sdk.AddrLen]) + valDstAddr := sdk.ValAddress(addrs[2*sdk.AddrLen:]) return Redelegation{ DelegatorAddr: delAddr, diff --git a/x/stake/types/delegation_test.go b/x/stake/types/delegation_test.go index 5624b71015..8e0dda7e24 100644 --- a/x/stake/types/delegation_test.go +++ b/x/stake/types/delegation_test.go @@ -10,12 +10,12 @@ import ( func TestDelegationEqual(t *testing.T) { d1 := Delegation{ - DelegatorAddr: addr1, + DelegatorAddr: sdk.AccAddress(addr1), ValidatorAddr: addr2, Shares: sdk.NewDec(100), } d2 := Delegation{ - DelegatorAddr: addr1, + DelegatorAddr: sdk.AccAddress(addr1), ValidatorAddr: addr2, Shares: sdk.NewDec(100), } @@ -23,7 +23,7 @@ func TestDelegationEqual(t *testing.T) { ok := d1.Equal(d2) require.True(t, ok) - d2.ValidatorAddr = addr3 + d2.ValidatorAddr = sdk.ValAddress(addr3) d2.Shares = sdk.NewDec(200) ok = d1.Equal(d2) @@ -32,7 +32,7 @@ func TestDelegationEqual(t *testing.T) { func TestDelegationHumanReadableString(t *testing.T) { d := Delegation{ - DelegatorAddr: addr1, + DelegatorAddr: sdk.AccAddress(addr1), ValidatorAddr: addr2, Shares: sdk.NewDec(100), } @@ -46,18 +46,18 @@ func TestDelegationHumanReadableString(t *testing.T) { func TestUnbondingDelegationEqual(t *testing.T) { ud1 := UnbondingDelegation{ - DelegatorAddr: addr1, + DelegatorAddr: sdk.AccAddress(addr1), ValidatorAddr: addr2, } ud2 := UnbondingDelegation{ - DelegatorAddr: addr1, + DelegatorAddr: sdk.AccAddress(addr1), ValidatorAddr: addr2, } ok := ud1.Equal(ud2) require.True(t, ok) - ud2.ValidatorAddr = addr3 + ud2.ValidatorAddr = sdk.ValAddress(addr3) ud2.MinTime = time.Unix(20*20*2, 0) ok = ud1.Equal(ud2) @@ -66,7 +66,7 @@ func TestUnbondingDelegationEqual(t *testing.T) { func TestUnbondingDelegationHumanReadableString(t *testing.T) { ud := UnbondingDelegation{ - DelegatorAddr: addr1, + DelegatorAddr: sdk.AccAddress(addr1), ValidatorAddr: addr2, } @@ -79,12 +79,12 @@ func TestUnbondingDelegationHumanReadableString(t *testing.T) { func TestRedelegationEqual(t *testing.T) { r1 := Redelegation{ - DelegatorAddr: addr1, + DelegatorAddr: sdk.AccAddress(addr1), ValidatorSrcAddr: addr2, ValidatorDstAddr: addr3, } r2 := Redelegation{ - DelegatorAddr: addr1, + DelegatorAddr: sdk.AccAddress(addr1), ValidatorSrcAddr: addr2, ValidatorDstAddr: addr3, } @@ -102,7 +102,7 @@ func TestRedelegationEqual(t *testing.T) { func TestRedelegationHumanReadableString(t *testing.T) { r := Redelegation{ - DelegatorAddr: addr1, + DelegatorAddr: sdk.AccAddress(addr1), ValidatorSrcAddr: addr2, ValidatorDstAddr: addr3, SharesDst: sdk.NewDec(10), diff --git a/x/stake/types/msg.go b/x/stake/types/msg.go index 282000294b..71a8c86314 100644 --- a/x/stake/types/msg.go +++ b/x/stake/types/msg.go @@ -1,7 +1,7 @@ package types import ( - "reflect" + "bytes" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/crypto" @@ -21,30 +21,27 @@ var _, _ sdk.Msg = &MsgBeginRedelegate{}, &MsgCompleteRedelegate{} type MsgCreateValidator struct { Description DelegatorAddr sdk.AccAddress `json:"delegator_address"` - ValidatorAddr sdk.AccAddress `json:"validator_address"` + ValidatorAddr sdk.ValAddress `json:"validator_address"` PubKey crypto.PubKey `json:"pubkey"` Delegation sdk.Coin `json:"delegation"` } // Default way to create validator. Delegator address and validator address are the same -func NewMsgCreateValidator(validatorAddr sdk.AccAddress, pubkey crypto.PubKey, +func NewMsgCreateValidator(valAddr sdk.ValAddress, pubkey crypto.PubKey, selfDelegation sdk.Coin, description Description) MsgCreateValidator { - return MsgCreateValidator{ - Description: description, - DelegatorAddr: validatorAddr, - ValidatorAddr: validatorAddr, - PubKey: pubkey, - Delegation: selfDelegation, - } + + return NewMsgCreateValidatorOnBehalfOf( + sdk.AccAddress(valAddr), valAddr, pubkey, selfDelegation, description, + ) } // Creates validator msg by delegator address on behalf of validator address -func NewMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr sdk.AccAddress, pubkey crypto.PubKey, - delegation sdk.Coin, description Description) MsgCreateValidator { +func NewMsgCreateValidatorOnBehalfOf(delAddr sdk.AccAddress, valAddr sdk.ValAddress, + pubkey crypto.PubKey, delegation sdk.Coin, description Description) MsgCreateValidator { return MsgCreateValidator{ Description: description, - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, PubKey: pubkey, Delegation: delegation, } @@ -57,9 +54,11 @@ func (msg MsgCreateValidator) Type() string { return MsgType } func (msg MsgCreateValidator) GetSigners() []sdk.AccAddress { // delegator is first signer so delegator pays fees addrs := []sdk.AccAddress{msg.DelegatorAddr} - if !reflect.DeepEqual(msg.DelegatorAddr, msg.ValidatorAddr) { - // if validator addr is not same as delegator addr, validator must sign msg as well - addrs = append(addrs, msg.ValidatorAddr) + + if !bytes.Equal(msg.DelegatorAddr.Bytes(), msg.ValidatorAddr.Bytes()) { + // if validator addr is not same as delegator addr, validator must sign + // msg as well + addrs = append(addrs, sdk.AccAddress(msg.ValidatorAddr)) } return addrs } @@ -69,13 +68,13 @@ func (msg MsgCreateValidator) GetSignBytes() []byte { b, err := MsgCdc.MarshalJSON(struct { Description DelegatorAddr sdk.AccAddress `json:"delegator_address"` - ValidatorAddr sdk.AccAddress `json:"validator_address"` + ValidatorAddr sdk.ValAddress `json:"validator_address"` PubKey string `json:"pubkey"` Delegation sdk.Coin `json:"delegation"` }{ Description: msg.Description, ValidatorAddr: msg.ValidatorAddr, - PubKey: sdk.MustBech32ifyValPub(msg.PubKey), + PubKey: sdk.MustBech32ifyConsPub(msg.PubKey), Delegation: msg.Delegation, }) if err != nil { @@ -107,27 +106,27 @@ func (msg MsgCreateValidator) ValidateBasic() sdk.Error { // MsgEditValidator - struct for editing a validator type MsgEditValidator struct { Description - ValidatorAddr sdk.AccAddress `json:"address"` + ValidatorAddr sdk.ValAddress `json:"address"` } -func NewMsgEditValidator(validatorAddr sdk.AccAddress, description Description) MsgEditValidator { +func NewMsgEditValidator(valAddr sdk.ValAddress, description Description) MsgEditValidator { return MsgEditValidator{ Description: description, - ValidatorAddr: validatorAddr, + ValidatorAddr: valAddr, } } //nolint func (msg MsgEditValidator) Type() string { return MsgType } func (msg MsgEditValidator) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.ValidatorAddr} + return []sdk.AccAddress{sdk.AccAddress(msg.ValidatorAddr)} } // get the bytes for the message signer to sign on func (msg MsgEditValidator) GetSignBytes() []byte { b, err := MsgCdc.MarshalJSON(struct { Description - ValidatorAddr sdk.AccAddress `json:"address"` + ValidatorAddr sdk.ValAddress `json:"address"` }{ Description: msg.Description, ValidatorAddr: msg.ValidatorAddr, @@ -155,14 +154,14 @@ func (msg MsgEditValidator) ValidateBasic() sdk.Error { // MsgDelegate - struct for bonding transactions type MsgDelegate struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` - ValidatorAddr sdk.AccAddress `json:"validator_addr"` + ValidatorAddr sdk.ValAddress `json:"validator_addr"` Delegation sdk.Coin `json:"delegation"` } -func NewMsgDelegate(delegatorAddr, validatorAddr sdk.AccAddress, delegation sdk.Coin) MsgDelegate { +func NewMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, delegation sdk.Coin) MsgDelegate { return MsgDelegate{ - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, Delegation: delegation, } } @@ -201,18 +200,18 @@ func (msg MsgDelegate) ValidateBasic() sdk.Error { // MsgDelegate - struct for bonding transactions type MsgBeginRedelegate struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` - ValidatorSrcAddr sdk.AccAddress `json:"validator_src_addr"` - ValidatorDstAddr sdk.AccAddress `json:"validator_dst_addr"` + ValidatorSrcAddr sdk.ValAddress `json:"validator_src_addr"` + ValidatorDstAddr sdk.ValAddress `json:"validator_dst_addr"` SharesAmount sdk.Dec `json:"shares_amount"` } -func NewMsgBeginRedelegate(delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.AccAddress, sharesAmount sdk.Dec) MsgBeginRedelegate { +func NewMsgBeginRedelegate(delAddr sdk.AccAddress, valSrcAddr, + valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) MsgBeginRedelegate { return MsgBeginRedelegate{ - DelegatorAddr: delegatorAddr, - ValidatorSrcAddr: validatorSrcAddr, - ValidatorDstAddr: validatorDstAddr, + DelegatorAddr: delAddr, + ValidatorSrcAddr: valSrcAddr, + ValidatorDstAddr: valDstAddr, SharesAmount: sharesAmount, } } @@ -227,8 +226,8 @@ func (msg MsgBeginRedelegate) GetSigners() []sdk.AccAddress { func (msg MsgBeginRedelegate) GetSignBytes() []byte { b, err := MsgCdc.MarshalJSON(struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` - ValidatorSrcAddr sdk.AccAddress `json:"validator_src_addr"` - ValidatorDstAddr sdk.AccAddress `json:"validator_dst_addr"` + ValidatorSrcAddr sdk.ValAddress `json:"validator_src_addr"` + ValidatorDstAddr sdk.ValAddress `json:"validator_dst_addr"` SharesAmount string `json:"shares"` }{ DelegatorAddr: msg.DelegatorAddr, @@ -262,17 +261,15 @@ func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error { // MsgDelegate - struct for bonding transactions type MsgCompleteRedelegate struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` - ValidatorSrcAddr sdk.AccAddress `json:"validator_source_addr"` - ValidatorDstAddr sdk.AccAddress `json:"validator_destination_addr"` + ValidatorSrcAddr sdk.ValAddress `json:"validator_source_addr"` + ValidatorDstAddr sdk.ValAddress `json:"validator_destination_addr"` } -func NewMsgCompleteRedelegate(delegatorAddr, validatorSrcAddr, - validatorDstAddr sdk.AccAddress) MsgCompleteRedelegate { - +func NewMsgCompleteRedelegate(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) MsgCompleteRedelegate { return MsgCompleteRedelegate{ - DelegatorAddr: delegatorAddr, - ValidatorSrcAddr: validatorSrcAddr, - ValidatorDstAddr: validatorDstAddr, + DelegatorAddr: delAddr, + ValidatorSrcAddr: valSrcAddr, + ValidatorDstAddr: valDstAddr, } } @@ -310,14 +307,14 @@ func (msg MsgCompleteRedelegate) ValidateBasic() sdk.Error { // MsgBeginUnbonding - struct for unbonding transactions type MsgBeginUnbonding struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` - ValidatorAddr sdk.AccAddress `json:"validator_addr"` + ValidatorAddr sdk.ValAddress `json:"validator_addr"` SharesAmount sdk.Dec `json:"shares_amount"` } -func NewMsgBeginUnbonding(delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Dec) MsgBeginUnbonding { +func NewMsgBeginUnbonding(delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) MsgBeginUnbonding { return MsgBeginUnbonding{ - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, SharesAmount: sharesAmount, } } @@ -330,7 +327,7 @@ func (msg MsgBeginUnbonding) GetSigners() []sdk.AccAddress { return []sdk.AccAdd func (msg MsgBeginUnbonding) GetSignBytes() []byte { b, err := MsgCdc.MarshalJSON(struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` - ValidatorAddr sdk.AccAddress `json:"validator_addr"` + ValidatorAddr sdk.ValAddress `json:"validator_addr"` SharesAmount string `json:"shares_amount"` }{ DelegatorAddr: msg.DelegatorAddr, @@ -360,13 +357,13 @@ func (msg MsgBeginUnbonding) ValidateBasic() sdk.Error { // MsgCompleteUnbonding - struct for unbonding transactions type MsgCompleteUnbonding struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` - ValidatorAddr sdk.AccAddress `json:"validator_addr"` + ValidatorAddr sdk.ValAddress `json:"validator_addr"` } -func NewMsgCompleteUnbonding(delegatorAddr, validatorAddr sdk.AccAddress) MsgCompleteUnbonding { +func NewMsgCompleteUnbonding(delAddr sdk.AccAddress, valAddr sdk.ValAddress) MsgCompleteUnbonding { return MsgCompleteUnbonding{ - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, } } diff --git a/x/stake/types/msg_test.go b/x/stake/types/msg_test.go index 2be34fb207..eb66c04220 100644 --- a/x/stake/types/msg_test.go +++ b/x/stake/types/msg_test.go @@ -19,7 +19,7 @@ var ( func TestMsgCreateValidator(t *testing.T) { tests := []struct { name, moniker, identity, website, details string - validatorAddr sdk.AccAddress + validatorAddr sdk.ValAddress pubkey crypto.PubKey bond sdk.Coin expectPass bool @@ -49,7 +49,7 @@ func TestMsgCreateValidator(t *testing.T) { func TestMsgEditValidator(t *testing.T) { tests := []struct { name, moniker, identity, website, details string - validatorAddr sdk.AccAddress + validatorAddr sdk.ValAddress expectPass bool }{ {"basic good", "a", "b", "c", "d", addr1, true}, @@ -74,20 +74,20 @@ func TestMsgCreateValidatorOnBehalfOf(t *testing.T) { tests := []struct { name, moniker, identity, website, details string delegatorAddr sdk.AccAddress - validatorAddr sdk.AccAddress + validatorAddr sdk.ValAddress validatorPubKey crypto.PubKey bond sdk.Coin expectPass bool }{ - {"basic good", "a", "b", "c", "d", addr1, addr2, pk2, coinPos, true}, - {"partial description", "", "", "c", "", addr1, addr2, pk2, coinPos, true}, - {"empty description", "", "", "", "", addr1, addr2, pk2, coinPos, false}, - {"empty delegator address", "a", "b", "c", "d", emptyAddr, addr2, pk2, coinPos, false}, - {"empty validator address", "a", "b", "c", "d", addr1, emptyAddr, pk2, coinPos, false}, - {"empty pubkey", "a", "b", "c", "d", addr1, addr2, emptyPubkey, coinPos, true}, - {"empty bond", "a", "b", "c", "d", addr1, addr2, pk2, coinZero, false}, - {"negative bond", "a", "b", "c", "d", addr1, addr2, pk2, coinNeg, false}, - {"negative bond", "a", "b", "c", "d", addr1, addr2, pk2, coinNeg, false}, + {"basic good", "a", "b", "c", "d", sdk.AccAddress(addr1), addr2, pk2, coinPos, true}, + {"partial description", "", "", "c", "", sdk.AccAddress(addr1), addr2, pk2, coinPos, true}, + {"empty description", "", "", "", "", sdk.AccAddress(addr1), addr2, pk2, coinPos, false}, + {"empty delegator address", "a", "b", "c", "d", sdk.AccAddress(emptyAddr), addr2, pk2, coinPos, false}, + {"empty validator address", "a", "b", "c", "d", sdk.AccAddress(addr1), emptyAddr, pk2, coinPos, false}, + {"empty pubkey", "a", "b", "c", "d", sdk.AccAddress(addr1), addr2, emptyPubkey, coinPos, true}, + {"empty bond", "a", "b", "c", "d", sdk.AccAddress(addr1), addr2, pk2, coinZero, false}, + {"negative bond", "a", "b", "c", "d", sdk.AccAddress(addr1), addr2, pk2, coinNeg, false}, + {"negative bond", "a", "b", "c", "d", sdk.AccAddress(addr1), addr2, pk2, coinNeg, false}, } for _, tc := range tests { @@ -102,11 +102,11 @@ func TestMsgCreateValidatorOnBehalfOf(t *testing.T) { msg := NewMsgCreateValidator(addr1, pk1, coinPos, Description{}) addrs := msg.GetSigners() - require.Equal(t, []sdk.AccAddress{addr1}, addrs, "Signers on default msg is wrong") + require.Equal(t, []sdk.AccAddress{sdk.AccAddress(addr1)}, addrs, "Signers on default msg is wrong") - msg = NewMsgCreateValidatorOnBehalfOf(addr2, addr1, pk1, coinPos, Description{}) + msg = NewMsgCreateValidatorOnBehalfOf(sdk.AccAddress(addr2), addr1, pk1, coinPos, Description{}) addrs = msg.GetSigners() - require.Equal(t, []sdk.AccAddress{addr2, addr1}, addrs, "Signers for onbehalfof msg is wrong") + require.Equal(t, []sdk.AccAddress{sdk.AccAddress(addr2), sdk.AccAddress(addr1)}, addrs, "Signers for onbehalfof msg is wrong") } // test ValidateBasic for MsgDelegate @@ -114,16 +114,16 @@ func TestMsgDelegate(t *testing.T) { tests := []struct { name string delegatorAddr sdk.AccAddress - validatorAddr sdk.AccAddress + validatorAddr sdk.ValAddress bond sdk.Coin expectPass bool }{ - {"basic good", addr1, addr2, coinPos, true}, - {"self bond", addr1, addr1, coinPos, true}, - {"empty delegator", emptyAddr, addr1, coinPos, false}, - {"empty validator", addr1, emptyAddr, coinPos, false}, - {"empty bond", addr1, addr2, coinZero, false}, - {"negative bond", addr1, addr2, coinNeg, false}, + {"basic good", sdk.AccAddress(addr1), addr2, coinPos, true}, + {"self bond", sdk.AccAddress(addr1), addr1, coinPos, true}, + {"empty delegator", sdk.AccAddress(emptyAddr), addr1, coinPos, false}, + {"empty validator", sdk.AccAddress(addr1), emptyAddr, coinPos, false}, + {"empty bond", sdk.AccAddress(addr1), addr2, coinZero, false}, + {"negative bond", sdk.AccAddress(addr1), addr2, coinNeg, false}, } for _, tc := range tests { @@ -141,17 +141,17 @@ func TestMsgBeginRedelegate(t *testing.T) { tests := []struct { name string delegatorAddr sdk.AccAddress - validatorSrcAddr sdk.AccAddress - validatorDstAddr sdk.AccAddress + validatorSrcAddr sdk.ValAddress + validatorDstAddr sdk.ValAddress sharesAmount sdk.Dec expectPass bool }{ - {"regular", addr1, addr2, addr3, sdk.NewDecWithPrec(1, 1), true}, - {"negative decimal", addr1, addr2, addr3, sdk.NewDecWithPrec(-1, 1), false}, - {"zero amount", addr1, addr2, addr3, sdk.ZeroDec(), false}, - {"empty delegator", emptyAddr, addr1, addr3, sdk.NewDecWithPrec(1, 1), false}, - {"empty source validator", addr1, emptyAddr, addr3, sdk.NewDecWithPrec(1, 1), false}, - {"empty destination validator", addr1, addr2, emptyAddr, sdk.NewDecWithPrec(1, 1), false}, + {"regular", sdk.AccAddress(addr1), addr2, addr3, sdk.NewDecWithPrec(1, 1), true}, + {"negative decimal", sdk.AccAddress(addr1), addr2, addr3, sdk.NewDecWithPrec(-1, 1), false}, + {"zero amount", sdk.AccAddress(addr1), addr2, addr3, sdk.ZeroDec(), false}, + {"empty delegator", sdk.AccAddress(emptyAddr), addr1, addr3, sdk.NewDecWithPrec(1, 1), false}, + {"empty source validator", sdk.AccAddress(addr1), emptyAddr, addr3, sdk.NewDecWithPrec(1, 1), false}, + {"empty destination validator", sdk.AccAddress(addr1), addr2, emptyAddr, sdk.NewDecWithPrec(1, 1), false}, } for _, tc := range tests { @@ -169,14 +169,14 @@ func TestMsgCompleteRedelegate(t *testing.T) { tests := []struct { name string delegatorAddr sdk.AccAddress - validatorSrcAddr sdk.AccAddress - validatorDstAddr sdk.AccAddress + validatorSrcAddr sdk.ValAddress + validatorDstAddr sdk.ValAddress expectPass bool }{ - {"regular", addr1, addr2, addr3, true}, - {"empty delegator", emptyAddr, addr1, addr3, false}, - {"empty source validator", addr1, emptyAddr, addr3, false}, - {"empty destination validator", addr1, addr2, emptyAddr, false}, + {"regular", sdk.AccAddress(addr1), addr2, addr3, true}, + {"empty delegator", sdk.AccAddress(emptyAddr), addr1, addr3, false}, + {"empty source validator", sdk.AccAddress(addr1), emptyAddr, addr3, false}, + {"empty destination validator", sdk.AccAddress(addr1), addr2, emptyAddr, false}, } for _, tc := range tests { @@ -194,15 +194,15 @@ func TestMsgBeginUnbonding(t *testing.T) { tests := []struct { name string delegatorAddr sdk.AccAddress - validatorAddr sdk.AccAddress + validatorAddr sdk.ValAddress sharesAmount sdk.Dec expectPass bool }{ - {"regular", addr1, addr2, sdk.NewDecWithPrec(1, 1), true}, - {"negative decimal", addr1, addr2, sdk.NewDecWithPrec(-1, 1), false}, - {"zero amount", addr1, addr2, sdk.ZeroDec(), false}, - {"empty delegator", emptyAddr, addr1, sdk.NewDecWithPrec(1, 1), false}, - {"empty validator", addr1, emptyAddr, sdk.NewDecWithPrec(1, 1), false}, + {"regular", sdk.AccAddress(addr1), addr2, sdk.NewDecWithPrec(1, 1), true}, + {"negative decimal", sdk.AccAddress(addr1), addr2, sdk.NewDecWithPrec(-1, 1), false}, + {"zero amount", sdk.AccAddress(addr1), addr2, sdk.ZeroDec(), false}, + {"empty delegator", sdk.AccAddress(emptyAddr), addr1, sdk.NewDecWithPrec(1, 1), false}, + {"empty validator", sdk.AccAddress(addr1), emptyAddr, sdk.NewDecWithPrec(1, 1), false}, } for _, tc := range tests { @@ -220,12 +220,12 @@ func TestMsgCompleteUnbonding(t *testing.T) { tests := []struct { name string delegatorAddr sdk.AccAddress - validatorAddr sdk.AccAddress + validatorAddr sdk.ValAddress expectPass bool }{ - {"regular", addr1, addr2, true}, - {"empty delegator", emptyAddr, addr1, false}, - {"empty validator", addr1, emptyAddr, false}, + {"regular", sdk.AccAddress(addr1), addr2, true}, + {"empty delegator", sdk.AccAddress(emptyAddr), addr1, false}, + {"empty validator", sdk.AccAddress(addr1), emptyAddr, false}, } for _, tc := range tests { diff --git a/x/stake/types/test_utils.go b/x/stake/types/test_utils.go index 02c4d4fca9..b9d77ce9f5 100644 --- a/x/stake/types/test_utils.go +++ b/x/stake/types/test_utils.go @@ -10,10 +10,10 @@ var ( pk1 = ed25519.GenPrivKey().PubKey() pk2 = ed25519.GenPrivKey().PubKey() pk3 = ed25519.GenPrivKey().PubKey() - addr1 = sdk.AccAddress(pk1.Address()) - addr2 = sdk.AccAddress(pk2.Address()) - addr3 = sdk.AccAddress(pk3.Address()) + addr1 = sdk.ValAddress(pk1.Address()) + addr2 = sdk.ValAddress(pk2.Address()) + addr3 = sdk.ValAddress(pk3.Address()) - emptyAddr sdk.AccAddress + emptyAddr sdk.ValAddress emptyPubkey crypto.PubKey ) diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 9d04357528..2cb952db28 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -20,7 +20,7 @@ import ( // exchange rate. Voting power can be calculated as total bonds multiplied by // exchange rate. type Validator struct { - Operator sdk.AccAddress `json:"operator"` // sender of BondTx - UnbondTx returns here + Operator sdk.ValAddress `json:"operator"` // sender of BondTx - UnbondTx returns here PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator Jailed bool `json:"jailed"` // has the validator been jailed from bonded status? @@ -43,7 +43,7 @@ type Validator struct { } // NewValidator - initialize a new validator -func NewValidator(operator sdk.AccAddress, pubKey crypto.PubKey, description Description) Validator { +func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Description) Validator { return Validator{ Operator: operator, PubKey: pubKey, @@ -147,14 +147,14 @@ func UnmarshalValidator(cdc *wire.Codec, operatorAddr, value []byte) (validator // validator. An error is returned if the operator or the operator's public key // cannot be converted to Bech32 format. func (v Validator) HumanReadableString() (string, error) { - bechVal, err := sdk.Bech32ifyValPub(v.PubKey) + bechConsPubKey, err := sdk.Bech32ifyConsPub(v.PubKey) if err != nil { return "", err } resp := "Validator \n" resp += fmt.Sprintf("Operator: %s\n", v.Operator) - resp += fmt.Sprintf("Validator: %s\n", bechVal) + resp += fmt.Sprintf("Validator: %s\n", bechConsPubKey) resp += fmt.Sprintf("Jailed: %v\n", v.Jailed) resp += fmt.Sprintf("Status: %s\n", sdk.BondStatusToString(v.Status)) resp += fmt.Sprintf("Tokens: %s\n", v.Tokens.String()) @@ -175,7 +175,7 @@ func (v Validator) HumanReadableString() (string, error) { // validator struct for bech output type BechValidator struct { - Operator sdk.AccAddress `json:"operator"` // in bech32 + Operator sdk.ValAddress `json:"operator"` // in bech32 PubKey string `json:"pub_key"` // in bech32 Jailed bool `json:"jailed"` // has the validator been jailed from bonded status? @@ -199,14 +199,14 @@ type BechValidator struct { // get the bech validator from the the regular validator func (v Validator) Bech32Validator() (BechValidator, error) { - bechValPubkey, err := sdk.Bech32ifyValPub(v.PubKey) + bechConsPubKey, err := sdk.Bech32ifyConsPub(v.PubKey) if err != nil { return BechValidator{}, err } return BechValidator{ Operator: v.Operator, - PubKey: bechValPubkey, + PubKey: bechConsPubKey, Jailed: v.Jailed, Status: v.Status, @@ -432,7 +432,7 @@ var _ sdk.Validator = Validator{} func (v Validator) GetJailed() bool { return v.Jailed } func (v Validator) GetMoniker() string { return v.Description.Moniker } func (v Validator) GetStatus() sdk.BondStatus { return v.Status } -func (v Validator) GetOperator() sdk.AccAddress { return v.Operator } +func (v Validator) GetOperator() sdk.ValAddress { return v.Operator } func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey } func (v Validator) GetPower() sdk.Dec { return v.BondedTokens() } func (v Validator) GetTokens() sdk.Dec { return v.Tokens } From df3345249074edefd15fd168d157fa7db85d192e Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> Date: Fri, 31 Aug 2018 00:10:51 -0400 Subject: [PATCH 14/28] Merge PR #2176: Ensure Legacy Validator Delegation Invariants * Test and allow jailed validator to self-bond * Implement TestJailedValidatorDelegations * Restructure TestJailedValidatorDelegations * Add Delegation to Validator type and update handleMsgUnjail accordingly * Update ErrMissingSelfDelegation error message * Update democoin mock validator set impl * Update pending log * Add comment to ValidatorSet --- PENDING.md | 1 + examples/democoin/mock/validator.go | 5 ++ types/stake.go | 4 ++ x/slashing/errors.go | 14 ++++- x/slashing/handler.go | 15 +++-- x/slashing/handler_test.go | 60 +++++++++++++++++++ x/slashing/test_common.go | 11 +++- x/stake/handler.go | 8 ++- x/stake/handler_test.go | 91 +++++++++++++++++++++++++++++ x/stake/keeper/delegation.go | 3 +- 10 files changed, 199 insertions(+), 13 deletions(-) diff --git a/PENDING.md b/PENDING.md index 832f25e8f4..3843be5fd5 100644 --- a/PENDING.md +++ b/PENDING.md @@ -73,6 +73,7 @@ IMPROVEMENTS * Gaia * [x/stake] [#2023](https://github.com/cosmos/cosmos-sdk/pull/2023) Terminate iteration loop in `UpdateBondedValidators` and `UpdateBondedValidatorsFull` when the first revoked validator is encountered and perform a sanity check. * [x/auth] Signature verification's gas cost now accounts for pubkey type. [#2046](https://github.com/tendermint/tendermint/pull/2046) + * [x/stake] [x/slashing] Ensure delegation invariants to jailed validators [#1883](https://github.com/cosmos/cosmos-sdk/issues/1883). * SDK * [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present. diff --git a/examples/democoin/mock/validator.go b/examples/democoin/mock/validator.go index f937e45dcc..3e552d44ad 100644 --- a/examples/democoin/mock/validator.go +++ b/examples/democoin/mock/validator.go @@ -135,3 +135,8 @@ func (vs *ValidatorSet) Jail(ctx sdk.Context, pubkey crypto.PubKey) { func (vs *ValidatorSet) Unjail(ctx sdk.Context, pubkey crypto.PubKey) { panic("not implemented") } + +// Implements sdk.ValidatorSet +func (vs *ValidatorSet) Delegation(ctx sdk.Context, addrDel, addrVal sdk.AccAddress) sdk.Delegation { + panic("not implemented") +} diff --git a/types/stake.go b/types/stake.go index f411251775..71386959e4 100644 --- a/types/stake.go +++ b/types/stake.go @@ -75,6 +75,10 @@ type ValidatorSet interface { Slash(Context, crypto.PubKey, int64, int64, Dec) Jail(Context, crypto.PubKey) // jail a validator Unjail(Context, crypto.PubKey) // unjail a validator + + // Delegation allows for getting a particular delegation for a given validator + // and delegator outside the scope of the staking module. + Delegation(Context, AccAddress, AccAddress) Delegation } //_______________________________________________________________________________ diff --git a/x/slashing/errors.go b/x/slashing/errors.go index 4573d5e145..77cb2d28e3 100644 --- a/x/slashing/errors.go +++ b/x/slashing/errors.go @@ -12,20 +12,28 @@ const ( // Default slashing codespace DefaultCodespace sdk.CodespaceType = 10 - CodeInvalidValidator CodeType = 101 - CodeValidatorJailed CodeType = 102 - CodeValidatorNotJailed CodeType = 103 + CodeInvalidValidator CodeType = 101 + CodeValidatorJailed CodeType = 102 + CodeValidatorNotJailed CodeType = 103 + CodeMissingSelfDelegation CodeType = 104 ) func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "that address is not associated with any known validator") } + func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address") } + func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeValidatorJailed, "validator still jailed, cannot yet be unjailed") } + func ErrValidatorNotJailed(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeValidatorNotJailed, "validator not jailed, cannot be unjailed") } + +func ErrMissingSelfDelegation(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeMissingSelfDelegation, "validator has no self-delegation; cannot be unjailed") +} diff --git a/x/slashing/handler.go b/x/slashing/handler.go index d79ea73c2d..94cfa41ff7 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -19,35 +19,38 @@ func NewHandler(k Keeper) sdk.Handler { // Validators must submit a transaction to unjail itself after // having been jailed (and thus unbonded) for downtime func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result { - - // Validator must exist validator := k.validatorSet.Validator(ctx, msg.ValidatorAddr) if validator == nil { return ErrNoValidatorForAddress(k.codespace).Result() } + // cannot be unjailed if no self-delegation exists + selfDel := k.validatorSet.Delegation(ctx, msg.ValidatorAddr, msg.ValidatorAddr) + if selfDel == nil { + return ErrMissingSelfDelegation(k.codespace).Result() + } + if !validator.GetJailed() { return ErrValidatorNotJailed(k.codespace).Result() } addr := sdk.ValAddress(validator.GetPubKey().Address()) - // Signing info must exist info, found := k.getValidatorSigningInfo(ctx, addr) if !found { return ErrNoValidatorForAddress(k.codespace).Result() } - // Cannot be unjailed until out of jail + // cannot be unjailed until out of jail if ctx.BlockHeader().Time.Before(info.JailedUntil) { return ErrValidatorJailed(k.codespace).Result() } - // Update the starting height (so the validator can't be immediately jailed again) + // update the starting height so the validator can't be immediately jailed + // again info.StartHeight = ctx.BlockHeight() k.setValidatorSigningInfo(ctx, addr, info) - // Unjail the validator k.validatorSet.Unjail(ctx, validator.GetPubKey()) tags := sdk.NewTags("action", []byte("unjail"), "validator", []byte(msg.ValidatorAddr.String())) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 8e3b719f49..cb764ec696 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -2,6 +2,7 @@ package slashing import ( "testing" + "time" "github.com/stretchr/testify/require" @@ -27,3 +28,62 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { require.False(t, got.IsOK(), "allowed unjail of non-jailed validator") require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotJailed), got.Code) } + +func TestJailedValidatorDelegations(t *testing.T) { + ctx, _, stakeKeeper, _, slashingKeeper := createTestInput(t) + + stakeParams := stakeKeeper.GetParams(ctx) + stakeParams.UnbondingTime = 0 + stakeKeeper.SetParams(ctx, stakeParams) + + // create a validator + amount := int64(10) + valAddr, valPubKey, bondAmount := addrs[0], pks[0], sdk.NewInt(amount) + msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount) + got := stake.NewHandler(stakeKeeper)(ctx, msgCreateVal) + require.True(t, got.IsOK(), "expected create validator msg to be ok, got: %v", got) + + // set dummy signing info + newInfo := ValidatorSigningInfo{ + StartHeight: int64(0), + IndexOffset: int64(0), + JailedUntil: time.Unix(0, 0), + SignedBlocksCounter: int64(0), + } + slashingKeeper.setValidatorSigningInfo(ctx, sdk.ValAddress(valAddr), newInfo) + + // delegate tokens to the validator + delAddr := addrs[1] + msgDelegate := newTestMsgDelegate(delAddr, valAddr, bondAmount) + got = stake.NewHandler(stakeKeeper)(ctx, msgDelegate) + require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + + unbondShares := sdk.NewDec(10) + + // unbond validator total self-delegations (which should jail the validator) + msgBeginUnbonding := stake.NewMsgBeginUnbonding(valAddr, valAddr, unbondShares) + got = stake.NewHandler(stakeKeeper)(ctx, msgBeginUnbonding) + require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got: %v", got) + + msgCompleteUnbonding := stake.NewMsgCompleteUnbonding(valAddr, valAddr) + got = stake.NewHandler(stakeKeeper)(ctx, msgCompleteUnbonding) + require.True(t, got.IsOK(), "expected complete unbonding validator msg to be ok, got: %v", got) + + // verify validator still exists and is jailed + validator, found := stakeKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.True(t, validator.GetJailed()) + + // verify the validator cannot unjail itself + got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) + require.False(t, got.IsOK(), "expected jailed validator to not be able to unjail, got: %v", got) + + // self-delegate to validator + msgSelfDelegate := newTestMsgDelegate(valAddr, valAddr, bondAmount) + got = stake.NewHandler(stakeKeeper)(ctx, msgSelfDelegate) + require.True(t, got.IsOK(), "expected delegation to not be ok, got %v", got) + + // verify the validator can now unjail itself + got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) + require.True(t, got.IsOK(), "expected jailed validator to be able to unjail, got: %v", got) +} diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 1053823786..d051a8cbc5 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "os" "testing" + "time" "github.com/stretchr/testify/require" @@ -61,7 +62,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) err := ms.LoadLatestVersion() require.Nil(t, err) - ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewTMLogger(os.Stdout)) + ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout)) cdc := createTestCodec() accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount) ck := bank.NewKeeper(accountMapper) @@ -108,3 +109,11 @@ func newTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt Delegation: sdk.Coin{"steak", amt}, } } + +func newTestMsgDelegate(delAddr, valAddr sdk.AccAddress, delAmount sdk.Int) stake.MsgDelegate { + return stake.MsgDelegate{ + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, + Delegation: sdk.Coin{"steak", delAmount}, + } +} diff --git a/x/stake/handler.go b/x/stake/handler.go index c8be6a835a..4b478fffd7 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -1,6 +1,7 @@ package stake import ( + "bytes" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -128,17 +129,19 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe } func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) sdk.Result { - validator, found := k.GetValidator(ctx, msg.ValidatorAddr) if !found { return ErrNoValidatorFound(k.Codespace()).Result() } + if msg.Delegation.Denom != k.GetParams(ctx).BondDenom { return ErrBadDenom(k.Codespace()).Result() } - if validator.Jailed { + + if validator.Jailed && !bytes.Equal(validator.Operator, msg.DelegatorAddr) { return ErrValidatorJailed(k.Codespace()).Result() } + _, err := k.Delegate(ctx, msg.DelegatorAddr, msg.Delegation, validator, true) if err != nil { return err.Result() @@ -149,6 +152,7 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) tags.Delegator, []byte(msg.DelegatorAddr.String()), tags.DstValidator, []byte(msg.ValidatorAddr.String()), ) + return sdk.Result{ Tags: tags, } diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index f7d01bcfc7..a5b70e054d 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -193,6 +193,97 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { require.False(t, got.IsOK(), "%v", got) } +func TestLegacyValidatorDelegations(t *testing.T) { + ctx, _, keeper := keep.CreateTestInput(t, false, int64(1000)) + setInstantUnbondPeriod(keeper, ctx) + + bondAmount := int64(10) + valAddr, valPubKey := keep.Addrs[0], keep.PKs[0] + delAddr := keep.Addrs[1] + + // create validator + msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount) + got := handleMsgCreateValidator(ctx, msgCreateVal, keeper) + require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) + + // verify the validator exists and has the correct attributes + validator, found := keeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, sdk.Bonded, validator.Status) + require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt64()) + require.Equal(t, bondAmount, validator.BondedTokens().RoundInt64()) + + // delegate tokens to the validator + msgDelegate := newTestMsgDelegate(delAddr, valAddr, bondAmount) + got = handleMsgDelegate(ctx, msgDelegate, keeper) + require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + + // verify validator bonded shares + validator, found = keeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, bondAmount*2, validator.DelegatorShares.RoundInt64()) + require.Equal(t, bondAmount*2, validator.BondedTokens().RoundInt64()) + + // unbond validator total self-delegations (which should jail the validator) + unbondShares := sdk.NewDec(10) + msgBeginUnbonding := NewMsgBeginUnbonding(valAddr, valAddr, unbondShares) + msgCompleteUnbonding := NewMsgCompleteUnbonding(valAddr, valAddr) + + got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) + require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got %v", got) + + got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper) + require.True(t, got.IsOK(), "expected complete unbonding validator msg to be ok, got %v", got) + + // verify the validator record still exists, is jailed, and has correct tokens + validator, found = keeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.True(t, validator.Jailed) + require.Equal(t, sdk.NewDec(10), validator.Tokens) + + // verify delegation still exists + bond, found := keeper.GetDelegation(ctx, delAddr, valAddr) + require.True(t, found) + require.Equal(t, bondAmount, bond.Shares.RoundInt64()) + require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt64()) + + // verify a delegator cannot create a new delegation to the now jailed validator + msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount) + got = handleMsgDelegate(ctx, msgDelegate, keeper) + require.False(t, got.IsOK(), "expected delegation to not be ok, got %v", got) + + // verify the validator can still self-delegate + msgSelfDelegate := newTestMsgDelegate(valAddr, valAddr, bondAmount) + got = handleMsgDelegate(ctx, msgSelfDelegate, keeper) + require.True(t, got.IsOK(), "expected delegation to not be ok, got %v", got) + + // verify validator bonded shares + validator, found = keeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, bondAmount*2, validator.DelegatorShares.RoundInt64()) + require.Equal(t, bondAmount*2, validator.Tokens.RoundInt64()) + + // unjail the validator now that is has non-zero self-delegated shares + keeper.Unjail(ctx, valPubKey) + + // verify the validator can now accept delegations + msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount) + got = handleMsgDelegate(ctx, msgDelegate, keeper) + require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + + // verify validator bonded shares + validator, found = keeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, bondAmount*3, validator.DelegatorShares.RoundInt64()) + require.Equal(t, bondAmount*3, validator.Tokens.RoundInt64()) + + // verify new delegation + bond, found = keeper.GetDelegation(ctx, delAddr, valAddr) + require.True(t, found) + require.Equal(t, bondAmount*2, bond.Shares.RoundInt64()) + require.Equal(t, bondAmount*3, validator.DelegatorShares.RoundInt64()) +} + func TestIncrementsMsgDelegate(t *testing.T) { initBond := int64(1000) ctx, accMapper, keeper := keep.CreateTestInput(t, false, initBond) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 9f7a402fc2..2c997b4633 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -288,6 +288,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA if bytes.Equal(delegation.DelegatorAddr, validator.Operator) && validator.Jailed == false { validator.Jailed = true } + k.RemoveDelegation(ctx, delegation) } else { // Update height @@ -307,7 +308,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA k.RemoveValidator(ctx, validator.Operator) } - return + return amount, nil } //______________________________________________________________________________________________________ From ee0434e5a7d724f5a14056b8fd96d5327dbaf93c Mon Sep 17 00:00:00 2001 From: Rigel <rigel.rozanski@gmail.com> Date: Fri, 31 Aug 2018 00:55:33 -0400 Subject: [PATCH 15/28] Revert "Merge PR #2176: Ensure Legacy Validator Delegation Invariants" (#2197) This reverts commit df3345249074edefd15fd168d157fa7db85d192e. --- PENDING.md | 1 - examples/democoin/mock/validator.go | 5 -- types/stake.go | 4 -- x/slashing/errors.go | 14 +---- x/slashing/handler.go | 15 ++--- x/slashing/handler_test.go | 60 ------------------- x/slashing/test_common.go | 11 +--- x/stake/handler.go | 8 +-- x/stake/handler_test.go | 91 ----------------------------- x/stake/keeper/delegation.go | 3 +- 10 files changed, 13 insertions(+), 199 deletions(-) diff --git a/PENDING.md b/PENDING.md index 3843be5fd5..832f25e8f4 100644 --- a/PENDING.md +++ b/PENDING.md @@ -73,7 +73,6 @@ IMPROVEMENTS * Gaia * [x/stake] [#2023](https://github.com/cosmos/cosmos-sdk/pull/2023) Terminate iteration loop in `UpdateBondedValidators` and `UpdateBondedValidatorsFull` when the first revoked validator is encountered and perform a sanity check. * [x/auth] Signature verification's gas cost now accounts for pubkey type. [#2046](https://github.com/tendermint/tendermint/pull/2046) - * [x/stake] [x/slashing] Ensure delegation invariants to jailed validators [#1883](https://github.com/cosmos/cosmos-sdk/issues/1883). * SDK * [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present. diff --git a/examples/democoin/mock/validator.go b/examples/democoin/mock/validator.go index 3e552d44ad..f937e45dcc 100644 --- a/examples/democoin/mock/validator.go +++ b/examples/democoin/mock/validator.go @@ -135,8 +135,3 @@ func (vs *ValidatorSet) Jail(ctx sdk.Context, pubkey crypto.PubKey) { func (vs *ValidatorSet) Unjail(ctx sdk.Context, pubkey crypto.PubKey) { panic("not implemented") } - -// Implements sdk.ValidatorSet -func (vs *ValidatorSet) Delegation(ctx sdk.Context, addrDel, addrVal sdk.AccAddress) sdk.Delegation { - panic("not implemented") -} diff --git a/types/stake.go b/types/stake.go index 71386959e4..f411251775 100644 --- a/types/stake.go +++ b/types/stake.go @@ -75,10 +75,6 @@ type ValidatorSet interface { Slash(Context, crypto.PubKey, int64, int64, Dec) Jail(Context, crypto.PubKey) // jail a validator Unjail(Context, crypto.PubKey) // unjail a validator - - // Delegation allows for getting a particular delegation for a given validator - // and delegator outside the scope of the staking module. - Delegation(Context, AccAddress, AccAddress) Delegation } //_______________________________________________________________________________ diff --git a/x/slashing/errors.go b/x/slashing/errors.go index 77cb2d28e3..4573d5e145 100644 --- a/x/slashing/errors.go +++ b/x/slashing/errors.go @@ -12,28 +12,20 @@ const ( // Default slashing codespace DefaultCodespace sdk.CodespaceType = 10 - CodeInvalidValidator CodeType = 101 - CodeValidatorJailed CodeType = 102 - CodeValidatorNotJailed CodeType = 103 - CodeMissingSelfDelegation CodeType = 104 + CodeInvalidValidator CodeType = 101 + CodeValidatorJailed CodeType = 102 + CodeValidatorNotJailed CodeType = 103 ) func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "that address is not associated with any known validator") } - func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address") } - func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeValidatorJailed, "validator still jailed, cannot yet be unjailed") } - func ErrValidatorNotJailed(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeValidatorNotJailed, "validator not jailed, cannot be unjailed") } - -func ErrMissingSelfDelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeMissingSelfDelegation, "validator has no self-delegation; cannot be unjailed") -} diff --git a/x/slashing/handler.go b/x/slashing/handler.go index 94cfa41ff7..d79ea73c2d 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -19,38 +19,35 @@ func NewHandler(k Keeper) sdk.Handler { // Validators must submit a transaction to unjail itself after // having been jailed (and thus unbonded) for downtime func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result { + + // Validator must exist validator := k.validatorSet.Validator(ctx, msg.ValidatorAddr) if validator == nil { return ErrNoValidatorForAddress(k.codespace).Result() } - // cannot be unjailed if no self-delegation exists - selfDel := k.validatorSet.Delegation(ctx, msg.ValidatorAddr, msg.ValidatorAddr) - if selfDel == nil { - return ErrMissingSelfDelegation(k.codespace).Result() - } - if !validator.GetJailed() { return ErrValidatorNotJailed(k.codespace).Result() } addr := sdk.ValAddress(validator.GetPubKey().Address()) + // Signing info must exist info, found := k.getValidatorSigningInfo(ctx, addr) if !found { return ErrNoValidatorForAddress(k.codespace).Result() } - // cannot be unjailed until out of jail + // Cannot be unjailed until out of jail if ctx.BlockHeader().Time.Before(info.JailedUntil) { return ErrValidatorJailed(k.codespace).Result() } - // update the starting height so the validator can't be immediately jailed - // again + // Update the starting height (so the validator can't be immediately jailed again) info.StartHeight = ctx.BlockHeight() k.setValidatorSigningInfo(ctx, addr, info) + // Unjail the validator k.validatorSet.Unjail(ctx, validator.GetPubKey()) tags := sdk.NewTags("action", []byte("unjail"), "validator", []byte(msg.ValidatorAddr.String())) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index cb764ec696..8e3b719f49 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -2,7 +2,6 @@ package slashing import ( "testing" - "time" "github.com/stretchr/testify/require" @@ -28,62 +27,3 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { require.False(t, got.IsOK(), "allowed unjail of non-jailed validator") require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotJailed), got.Code) } - -func TestJailedValidatorDelegations(t *testing.T) { - ctx, _, stakeKeeper, _, slashingKeeper := createTestInput(t) - - stakeParams := stakeKeeper.GetParams(ctx) - stakeParams.UnbondingTime = 0 - stakeKeeper.SetParams(ctx, stakeParams) - - // create a validator - amount := int64(10) - valAddr, valPubKey, bondAmount := addrs[0], pks[0], sdk.NewInt(amount) - msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount) - got := stake.NewHandler(stakeKeeper)(ctx, msgCreateVal) - require.True(t, got.IsOK(), "expected create validator msg to be ok, got: %v", got) - - // set dummy signing info - newInfo := ValidatorSigningInfo{ - StartHeight: int64(0), - IndexOffset: int64(0), - JailedUntil: time.Unix(0, 0), - SignedBlocksCounter: int64(0), - } - slashingKeeper.setValidatorSigningInfo(ctx, sdk.ValAddress(valAddr), newInfo) - - // delegate tokens to the validator - delAddr := addrs[1] - msgDelegate := newTestMsgDelegate(delAddr, valAddr, bondAmount) - got = stake.NewHandler(stakeKeeper)(ctx, msgDelegate) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) - - unbondShares := sdk.NewDec(10) - - // unbond validator total self-delegations (which should jail the validator) - msgBeginUnbonding := stake.NewMsgBeginUnbonding(valAddr, valAddr, unbondShares) - got = stake.NewHandler(stakeKeeper)(ctx, msgBeginUnbonding) - require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got: %v", got) - - msgCompleteUnbonding := stake.NewMsgCompleteUnbonding(valAddr, valAddr) - got = stake.NewHandler(stakeKeeper)(ctx, msgCompleteUnbonding) - require.True(t, got.IsOK(), "expected complete unbonding validator msg to be ok, got: %v", got) - - // verify validator still exists and is jailed - validator, found := stakeKeeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.True(t, validator.GetJailed()) - - // verify the validator cannot unjail itself - got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) - require.False(t, got.IsOK(), "expected jailed validator to not be able to unjail, got: %v", got) - - // self-delegate to validator - msgSelfDelegate := newTestMsgDelegate(valAddr, valAddr, bondAmount) - got = stake.NewHandler(stakeKeeper)(ctx, msgSelfDelegate) - require.True(t, got.IsOK(), "expected delegation to not be ok, got %v", got) - - // verify the validator can now unjail itself - got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) - require.True(t, got.IsOK(), "expected jailed validator to be able to unjail, got: %v", got) -} diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index d051a8cbc5..1053823786 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "os" "testing" - "time" "github.com/stretchr/testify/require" @@ -62,7 +61,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) err := ms.LoadLatestVersion() require.Nil(t, err) - ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout)) + ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewTMLogger(os.Stdout)) cdc := createTestCodec() accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount) ck := bank.NewKeeper(accountMapper) @@ -109,11 +108,3 @@ func newTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt Delegation: sdk.Coin{"steak", amt}, } } - -func newTestMsgDelegate(delAddr, valAddr sdk.AccAddress, delAmount sdk.Int) stake.MsgDelegate { - return stake.MsgDelegate{ - DelegatorAddr: delAddr, - ValidatorAddr: valAddr, - Delegation: sdk.Coin{"steak", delAmount}, - } -} diff --git a/x/stake/handler.go b/x/stake/handler.go index 4b478fffd7..c8be6a835a 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -1,7 +1,6 @@ package stake import ( - "bytes" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -129,19 +128,17 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe } func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) sdk.Result { + validator, found := k.GetValidator(ctx, msg.ValidatorAddr) if !found { return ErrNoValidatorFound(k.Codespace()).Result() } - if msg.Delegation.Denom != k.GetParams(ctx).BondDenom { return ErrBadDenom(k.Codespace()).Result() } - - if validator.Jailed && !bytes.Equal(validator.Operator, msg.DelegatorAddr) { + if validator.Jailed { return ErrValidatorJailed(k.Codespace()).Result() } - _, err := k.Delegate(ctx, msg.DelegatorAddr, msg.Delegation, validator, true) if err != nil { return err.Result() @@ -152,7 +149,6 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) tags.Delegator, []byte(msg.DelegatorAddr.String()), tags.DstValidator, []byte(msg.ValidatorAddr.String()), ) - return sdk.Result{ Tags: tags, } diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index a5b70e054d..f7d01bcfc7 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -193,97 +193,6 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { require.False(t, got.IsOK(), "%v", got) } -func TestLegacyValidatorDelegations(t *testing.T) { - ctx, _, keeper := keep.CreateTestInput(t, false, int64(1000)) - setInstantUnbondPeriod(keeper, ctx) - - bondAmount := int64(10) - valAddr, valPubKey := keep.Addrs[0], keep.PKs[0] - delAddr := keep.Addrs[1] - - // create validator - msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount) - got := handleMsgCreateValidator(ctx, msgCreateVal, keeper) - require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) - - // verify the validator exists and has the correct attributes - validator, found := keeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.Equal(t, sdk.Bonded, validator.Status) - require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt64()) - require.Equal(t, bondAmount, validator.BondedTokens().RoundInt64()) - - // delegate tokens to the validator - msgDelegate := newTestMsgDelegate(delAddr, valAddr, bondAmount) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) - - // verify validator bonded shares - validator, found = keeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.Equal(t, bondAmount*2, validator.DelegatorShares.RoundInt64()) - require.Equal(t, bondAmount*2, validator.BondedTokens().RoundInt64()) - - // unbond validator total self-delegations (which should jail the validator) - unbondShares := sdk.NewDec(10) - msgBeginUnbonding := NewMsgBeginUnbonding(valAddr, valAddr, unbondShares) - msgCompleteUnbonding := NewMsgCompleteUnbonding(valAddr, valAddr) - - got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) - require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got %v", got) - - got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper) - require.True(t, got.IsOK(), "expected complete unbonding validator msg to be ok, got %v", got) - - // verify the validator record still exists, is jailed, and has correct tokens - validator, found = keeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.True(t, validator.Jailed) - require.Equal(t, sdk.NewDec(10), validator.Tokens) - - // verify delegation still exists - bond, found := keeper.GetDelegation(ctx, delAddr, valAddr) - require.True(t, found) - require.Equal(t, bondAmount, bond.Shares.RoundInt64()) - require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt64()) - - // verify a delegator cannot create a new delegation to the now jailed validator - msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.False(t, got.IsOK(), "expected delegation to not be ok, got %v", got) - - // verify the validator can still self-delegate - msgSelfDelegate := newTestMsgDelegate(valAddr, valAddr, bondAmount) - got = handleMsgDelegate(ctx, msgSelfDelegate, keeper) - require.True(t, got.IsOK(), "expected delegation to not be ok, got %v", got) - - // verify validator bonded shares - validator, found = keeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.Equal(t, bondAmount*2, validator.DelegatorShares.RoundInt64()) - require.Equal(t, bondAmount*2, validator.Tokens.RoundInt64()) - - // unjail the validator now that is has non-zero self-delegated shares - keeper.Unjail(ctx, valPubKey) - - // verify the validator can now accept delegations - msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) - - // verify validator bonded shares - validator, found = keeper.GetValidator(ctx, valAddr) - require.True(t, found) - require.Equal(t, bondAmount*3, validator.DelegatorShares.RoundInt64()) - require.Equal(t, bondAmount*3, validator.Tokens.RoundInt64()) - - // verify new delegation - bond, found = keeper.GetDelegation(ctx, delAddr, valAddr) - require.True(t, found) - require.Equal(t, bondAmount*2, bond.Shares.RoundInt64()) - require.Equal(t, bondAmount*3, validator.DelegatorShares.RoundInt64()) -} - func TestIncrementsMsgDelegate(t *testing.T) { initBond := int64(1000) ctx, accMapper, keeper := keep.CreateTestInput(t, false, initBond) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 2c997b4633..9f7a402fc2 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -288,7 +288,6 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA if bytes.Equal(delegation.DelegatorAddr, validator.Operator) && validator.Jailed == false { validator.Jailed = true } - k.RemoveDelegation(ctx, delegation) } else { // Update height @@ -308,7 +307,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA k.RemoveValidator(ctx, validator.Operator) } - return amount, nil + return } //______________________________________________________________________________________________________ From b977baec73ea1cf51dc8d439e49a186fb6e8625b Mon Sep 17 00:00:00 2001 From: HaoyangLiu <lhy.0318@163.com> Date: Fri, 31 Aug 2018 13:31:24 +0800 Subject: [PATCH 16/28] IRISHUB-238: move certifier creation to a function --- client/context/context.go | 57 ++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index 2d9c9b90c9..da37795f08 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -2,7 +2,8 @@ package context import ( "io" - + "bytes" + "fmt" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" @@ -10,11 +11,9 @@ import ( "github.com/spf13/viper" "github.com/tendermint/tendermint/libs/cli" - tendermintLite "github.com/tendermint/tendermint/lite" tmlite "github.com/tendermint/tendermint/lite" - tendermintLiteProxy "github.com/tendermint/tendermint/lite/proxy" + tmliteProxy "github.com/tendermint/tendermint/lite/proxy" rpcclient "github.com/tendermint/tendermint/rpc/client" - "fmt" ) const ctxAccStoreName = "acc" @@ -50,22 +49,6 @@ func NewCLIContext() CLIContext { rpc = rpcclient.NewHTTP(nodeURI, "/websocket") } - trustNode := viper.GetBool(client.FlagTrustNode) - var certifier tendermintLite.Certifier - if !trustNode { - chainID := viper.GetString(client.FlagChainID) - home := viper.GetString(cli.HomeFlag) - if chainID != "" && home != "" && nodeURI != "" { - var err error - certifier, err = tendermintLiteProxy.GetCertifier(chainID, home, nodeURI) - if err != nil { - panic(err) - } - } else { - panic(fmt.Errorf("can't create certifier for distrust mode, values from these options may be empty: --chain-id, --home or --node")) - } - } - return CLIContext{ Client: rpc, NodeURI: nodeURI, @@ -74,15 +57,45 @@ func NewCLIContext() CLIContext { Height: viper.GetInt64(client.FlagHeight), Gas: viper.GetInt64(client.FlagGas), GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment), - TrustNode: trustNode, + TrustNode: viper.GetBool(client.FlagTrustNode), UseLedger: viper.GetBool(client.FlagUseLedger), Async: viper.GetBool(client.FlagAsync), JSON: viper.GetBool(client.FlagJson), PrintResponse: viper.GetBool(client.FlagPrintResponse), - Certifier: certifier, + Certifier: createCertifier(), } } +func createCertifier() tmlite.Certifier { + trustNode := viper.GetBool(client.FlagTrustNode) + if !trustNode { + chainID := viper.GetString(client.FlagChainID) + home := viper.GetString(cli.HomeFlag) + nodeURI := viper.GetString(client.FlagNode) + + var errMsg bytes.Buffer + if chainID == "" { + errMsg.WriteString("chain-id ") + } + if home == "" { + errMsg.WriteString("home ") + } + if nodeURI == "" { + errMsg.WriteString("node ") + } + // errMsg is not empty + if errMsg.Len() != 0 { + panic(fmt.Errorf("can't create certifier for distrust mode, empty values from these options: %s", errMsg.String())) + } + certifier, err := tmliteProxy.GetCertifier(chainID, home, nodeURI) + if err != nil { + panic(err) + } + return certifier + } + return nil +} + // WithCodec returns a copy of the context with an updated codec. func (ctx CLIContext) WithCodec(cdc *wire.Codec) CLIContext { ctx.Codec = cdc From de8ac6e2a982ceccfaa72061048e813304d05702 Mon Sep 17 00:00:00 2001 From: HaoyangLiu <lhy.0318@163.com> Date: Fri, 31 Aug 2018 14:06:53 +0800 Subject: [PATCH 17/28] IRISHUB-238: missing change a comment --- client/context/query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/context/query.go b/client/context/query.go index 31861a972e..4c1cad8777 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -347,7 +347,7 @@ func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error { return errors.Wrap(err, "failed to unmarshalBinary rangeProof") } - // Validate the substore commit hash against trusted appHash + // Verify the substore commit hash against trusted appHash substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(multiStoreProof.StoreName, multiStoreProof.StoreInfos, commit.Header.AppHash) if err != nil { From 959582476bd32b90d4375cd147638f11b86a0b9f Mon Sep 17 00:00:00 2001 From: HaoyangLiu <lhy.0318@163.com> Date: Fri, 31 Aug 2018 15:21:35 +0800 Subject: [PATCH 18/28] IRISHUB-238: fix test_lint failure --- Gopkg.lock | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index fa6fafb99d..5e40c17e6c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -34,7 +34,7 @@ [[projects]] branch = "master" - digest = "1:6aabc1566d6351115d561d038da82a4c19b46c3b6e17f4a0a2fa60260663dc79" + digest = "1:2c00f064ba355903866cbfbf3f7f4c0fe64af6638cc7d1b8bdcf3181bc67f1d8" name = "github.com/btcsuite/btcd" packages = ["btcec"] pruneopts = "UT" @@ -71,7 +71,7 @@ version = "v1.4.7" [[projects]] - digest = "1:fa30c0652956e159cdb97dcb2ef8b8db63ed668c02a5c3a40961c8f0641252fe" + digest = "1:fdf5169073fb0ad6dc12a70c249145e30f4058647bea25f0abd48b6d9f228a11" name = "github.com/go-kit/kit" packages = [ "log", @@ -103,7 +103,7 @@ version = "v1.7.0" [[projects]] - digest = "1:212285efb97b9ec2e20550d81f0446cb7897e57cbdfd7301b1363ab113d8be45" + digest = "1:35621fe20f140f05a0c4ef662c26c0ab4ee50bca78aa30fe87d33120bd28165e" name = "github.com/gogo/protobuf" packages = [ "gogoproto", @@ -118,7 +118,7 @@ version = "v1.1.1" [[projects]] - digest = "1:cb22af0ed7c72d495d8be1106233ee553898950f15fd3f5404406d44c2e86888" + digest = "1:17fe264ee908afc795734e8c4e63db2accabaf57326dbf21763a7d6b86096260" name = "github.com/golang/protobuf" packages = [ "proto", @@ -165,13 +165,12 @@ [[projects]] branch = "master" - digest = "1:ac64f01acc5eeea9dde40e326de6b6471e501392ec06524c3b51033aa50789bc" + digest = "1:12247a2e99a060cc692f6680e5272c8adf0b8f572e6bce0d7095e624c958a240" name = "github.com/hashicorp/hcl" packages = [ ".", "hcl/ast", "hcl/parser", - "hcl/printer", "hcl/scanner", "hcl/strconv", "hcl/token", @@ -263,7 +262,7 @@ version = "v1.0.0" [[projects]] - digest = "1:98225904b7abff96c052b669b25788f18225a36673fba022fb93514bb9a2a64e" + digest = "1:c1a04665f9613e082e1209cf288bf64f4068dcd6c87a64bf1c4ff006ad422ba0" name = "github.com/prometheus/client_golang" packages = [ "prometheus", @@ -274,7 +273,7 @@ [[projects]] branch = "master" - digest = "1:0f37e09b3e92aaeda5991581311f8dbf38944b36a3edec61cc2d1991f527554a" + digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4" name = "github.com/prometheus/client_model" packages = ["go"] pruneopts = "UT" @@ -282,7 +281,7 @@ [[projects]] branch = "master" - digest = "1:dad2e5a2153ee7a6c9ab8fc13673a16ee4fb64434a7da980965a3741b0c981a3" + digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5" name = "github.com/prometheus/common" packages = [ "expfmt", @@ -294,7 +293,7 @@ [[projects]] branch = "master" - digest = "1:a37c98f4b7a66bb5c539c0539f0915a74ef1c8e0b3b6f45735289d94cae92bfd" + digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290" name = "github.com/prometheus/procfs" packages = [ ".", @@ -313,7 +312,7 @@ revision = "e2704e165165ec55d062f5919b4b29494e9fa790" [[projects]] - digest = "1:37ace7f35375adec11634126944bdc45a673415e2fcc07382d03b75ec76ea94c" + digest = "1:bd1ae00087d17c5a748660b8e89e1043e1e5479d0fea743352cda2f8dd8c4f84" name = "github.com/spf13/afero" packages = [ ".", @@ -332,7 +331,7 @@ version = "v1.2.0" [[projects]] - digest = "1:627ab2f549a6a55c44f46fa24a4307f4d0da81bfc7934ed0473bf38b24051d26" + digest = "1:7ffc0983035bc7e297da3688d9fe19d60a420e9c38bef23f845c53788ed6a05e" name = "github.com/spf13/cobra" packages = ["."] pruneopts = "UT" @@ -364,7 +363,7 @@ version = "v1.0.0" [[projects]] - digest = "1:73697231b93fb74a73ebd8384b68b9a60c57ea6b13c56d2425414566a72c8e6d" + digest = "1:7e8d267900c7fa7f35129a2a37596e38ed0f11ca746d6d9ba727980ee138f9f6" name = "github.com/stretchr/testify" packages = [ "assert", @@ -376,7 +375,7 @@ [[projects]] branch = "master" - digest = "1:442d2ffa75ffae302ce8800bf4144696b92bef02917923ea132ce2d39efe7d65" + digest = "1:f2ffd421680b0a3f7887501b3c6974bcf19217ecd301d0e2c9b681940ec363d5" name = "github.com/syndtr/goleveldb" packages = [ "leveldb", @@ -397,7 +396,7 @@ [[projects]] branch = "master" - digest = "1:203b409c21115233a576f99e8f13d8e07ad82b25500491f7e1cca12588fb3232" + digest = "1:087aaa7920e5d0bf79586feb57ce01c35c830396ab4392798112e8aae8c47722" name = "github.com/tendermint/ed25519" packages = [ ".", @@ -424,7 +423,7 @@ version = "v0.9.2" [[projects]] - digest = "1:963f6c04345ce36f900c1d6367200eebc3cc2db6ee632ff865ea8dcf64b748a0" + digest = "1:4f15e95fe3888cc75dd34f407d6394cbc7fd3ff24920851b92b295f6a8b556e6" name = "github.com/tendermint/tendermint" packages = [ "abci/client", @@ -491,7 +490,7 @@ version = "v0.23.1-rc0" [[projects]] - digest = "1:ad879bb8c71020a3f92f0c61f414d93eae1d5dc2f37023b6abaa3cc84b00165e" + digest = "1:bf6d9a827ea3cad964c2f863302e4f6823170d0b5ed16f72cf1184a7c615067e" name = "github.com/tendermint/tmlibs" packages = ["cli"] pruneopts = "UT" @@ -507,7 +506,7 @@ [[projects]] branch = "master" - digest = "1:2a3ce1f08dcae8bac666deb6e4c88b5d7170c510da38fd746231144cac351704" + digest = "1:27507554c6d4f060d8d700c31c624a43d3a92baa634e178ddc044bdf7d13b44a" name = "golang.org/x/crypto" packages = [ "blowfish", @@ -529,7 +528,7 @@ revision = "614d502a4dac94afa3a6ce146bd1736da82514c6" [[projects]] - digest = "1:04dda8391c3e2397daf254ac68003f30141c069b228d06baec8324a5f81dc1e9" + digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1" name = "golang.org/x/net" packages = [ "context", @@ -546,7 +545,7 @@ [[projects]] branch = "master" - digest = "1:c8baf78f0ac6eb27c645e264fe5e8a74d5a50db188ab41a7ff3b275c112e0735" + digest = "1:86171d21d59449dcf7cee0b7d2da83dff989dab9b9b69bfe0a3d59c3c1ca6081" name = "golang.org/x/sys" packages = [ "cpu", @@ -556,7 +555,7 @@ revision = "11551d06cbcc94edc80a0facaccbda56473c19c1" [[projects]] - digest = "1:7509ba4347d1f8de6ae9be8818b0cd1abc3deeffe28aeaf4be6d4b6b5178d9ca" + digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" name = "golang.org/x/text" packages = [ "collate", @@ -587,7 +586,7 @@ revision = "c66870c02cf823ceb633bcd05be3c7cda29976f4" [[projects]] - digest = "1:4515e3030c440845b046354fd5d57671238428b820deebce2e9dabb5cd3c51ac" + digest = "1:2dab32a43451e320e49608ff4542fdfc653c95dcc35d0065ec9c6c3dd540ed74" name = "google.golang.org/grpc" packages = [ ".", @@ -664,6 +663,8 @@ "github.com/tendermint/tendermint/libs/common", "github.com/tendermint/tendermint/libs/db", "github.com/tendermint/tendermint/libs/log", + "github.com/tendermint/tendermint/lite", + "github.com/tendermint/tendermint/lite/proxy", "github.com/tendermint/tendermint/node", "github.com/tendermint/tendermint/p2p", "github.com/tendermint/tendermint/privval", From cb3e729582b6b7410d56f06077a24d9e9c545d2c Mon Sep 17 00:00:00 2001 From: HaoyangLiu <lhy.0318@163.com> Date: Fri, 31 Aug 2018 15:54:15 +0800 Subject: [PATCH 19/28] IRISHUB-238: fix test_lint failure in context.go --- client/context/context.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/context/context.go b/client/context/context.go index da37795f08..f05cf69f98 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -1,12 +1,12 @@ package context import ( - "io" "bytes" "fmt" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" + "io" "github.com/spf13/viper" From 67857d704bda708583bd95b94dce25f28c081121 Mon Sep 17 00:00:00 2001 From: HaoyangLiu <lhy.0318@163.com> Date: Fri, 31 Aug 2018 23:20:06 +0800 Subject: [PATCH 20/28] IRISHUB-238: change wait 3 second to wait tendermint new block. use MustUnmarshalBinary instead of UnmarshalBinary --- client/context/context.go | 50 +++++++++++++++++++------------------- client/lcd/test_helpers.go | 3 +-- store/multistoreproof.go | 21 ++++++---------- store/rootmultistore.go | 5 +--- tests/util.go | 12 +++++++++ 5 files changed, 46 insertions(+), 45 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index f05cf69f98..4122cbab30 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -68,32 +68,32 @@ func NewCLIContext() CLIContext { func createCertifier() tmlite.Certifier { trustNode := viper.GetBool(client.FlagTrustNode) - if !trustNode { - chainID := viper.GetString(client.FlagChainID) - home := viper.GetString(cli.HomeFlag) - nodeURI := viper.GetString(client.FlagNode) - - var errMsg bytes.Buffer - if chainID == "" { - errMsg.WriteString("chain-id ") - } - if home == "" { - errMsg.WriteString("home ") - } - if nodeURI == "" { - errMsg.WriteString("node ") - } - // errMsg is not empty - if errMsg.Len() != 0 { - panic(fmt.Errorf("can't create certifier for distrust mode, empty values from these options: %s", errMsg.String())) - } - certifier, err := tmliteProxy.GetCertifier(chainID, home, nodeURI) - if err != nil { - panic(err) - } - return certifier + if trustNode { + return nil } - return nil + chainID := viper.GetString(client.FlagChainID) + home := viper.GetString(cli.HomeFlag) + nodeURI := viper.GetString(client.FlagNode) + + var errMsg bytes.Buffer + if chainID == "" { + errMsg.WriteString("chain-id ") + } + if home == "" { + errMsg.WriteString("home ") + } + if nodeURI == "" { + errMsg.WriteString("node ") + } + // errMsg is not empty + if errMsg.Len() != 0 { + panic(fmt.Errorf("can't create certifier for distrust mode, empty values from these options: %s", errMsg.String())) + } + certifier, err := tmliteProxy.GetCertifier(chainID, home, nodeURI) + if err != nil { + panic(err) + } + return certifier } // WithCodec returns a copy of the context with an updated codec. diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 8a344976a1..7d9a46403c 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -37,7 +37,6 @@ import ( "github.com/tendermint/tendermint/proxy" tmrpc "github.com/tendermint/tendermint/rpc/lib/server" tmtypes "github.com/tendermint/tendermint/types" - "time" ) // makePathname creates a unique pathname for each test. It will panic if it @@ -191,7 +190,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress node, err := startTM(config, logger, genDoc, privVal, app) require.NoError(t, err) - time.Sleep(3 * time.Second) + tests.WaitForNextHeightTM(tests.ExtractPortFromAddress(config.RPC.ListenAddress)) lcd, err := startLCD(logger, listenAddr, cdc) require.NoError(t, err) diff --git a/store/multistoreproof.go b/store/multistoreproof.go index 05eb49730a..e25f1cc1f2 100644 --- a/store/multistoreproof.go +++ b/store/multistoreproof.go @@ -15,12 +15,9 @@ type MultiStoreProof struct { } // buildMultiStoreProof build MultiStoreProof based on iavl proof and storeInfos -func buildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []storeInfo) ([]byte, error) { +func buildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []storeInfo) []byte { var rangeProof iavl.RangeProof - err := cdc.UnmarshalBinary(iavlProof, &rangeProof) - if err != nil { - return nil, err - } + cdc.MustUnmarshalBinary(iavlProof, &rangeProof) msp := MultiStoreProof{ StoreInfos: storeInfos, @@ -28,12 +25,8 @@ func buildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []store RangeProof: rangeProof, } - proof, err := cdc.MarshalBinary(msp) - if err != nil { - return nil, err - } - - return proof, nil + proof := cdc.MustMarshalBinary(msp) + return proof } // VerifyMultiStoreCommitInfo verify multiStoreCommitInfo against appHash @@ -64,20 +57,20 @@ func VerifyMultiStoreCommitInfo(storeName string, storeInfos []storeInfo, appHas // VerifyRangeProof verify iavl RangeProof func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof *iavl.RangeProof) error { - // Verify the proof to ensure data integrity. + // verify the proof to ensure data integrity. err := rangeProof.Verify(substoreCommitHash) if err != nil { return errors.Wrap(err, "proof root hash doesn't equal to substore commit root hash") } if len(value) != 0 { - // Verify existence proof + // verify existence proof err = rangeProof.VerifyItem(key, value) if err != nil { return errors.Wrap(err, "failed in existence verification") } } else { - // Verify absence proof + // verify absence proof err = rangeProof.VerifyAbsence(key) if err != nil { return errors.Wrap(err, "failed in absence verification") diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 5f6b082832..d9cf8a29a2 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -301,10 +301,7 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery { return sdk.ErrInternal(errMsg.Error()).QueryResult() } - res.Proof, errMsg = buildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos) - if errMsg != nil { - return sdk.ErrInternal(errMsg.Error()).QueryResult() - } + res.Proof = buildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos) return res } diff --git a/tests/util.go b/tests/util.go index 1138bc95e9..48649eaf76 100644 --- a/tests/util.go +++ b/tests/util.go @@ -10,6 +10,7 @@ import ( tmclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" rpcclient "github.com/tendermint/tendermint/rpc/lib/client" + "strings" ) // Wait for the next tendermint block from the Tendermint RPC @@ -185,6 +186,17 @@ func WaitForRPC(laddr string) { } } +// ExtractPortFromAddress extract port from listenAddress +// The listenAddress must be some strings like tcp://0.0.0.0:12345 +func ExtractPortFromAddress(listenAddress string) string { + stringList := strings.Split(listenAddress, ":") + length := len(stringList) + if length != 3 { + panic(fmt.Errorf("expected listen address: tcp://0.0.0.0:12345, got %s", listenAddress)) + } + return stringList[2] +} + var cdc = amino.NewCodec() func init() { From 599923fb99e3b36d2c11ac35ba89f61a3396e0fd Mon Sep 17 00:00:00 2001 From: Alessio Treglia <quadrispro@ubuntu.com> Date: Fri, 31 Aug 2018 19:04:11 +0200 Subject: [PATCH 21/28] Introduce simulate mode Add a simulate only flag '--dry-run' to both CLI tx commands and RESTful endpoints to trigger the simulation of unsigned transactions. * Turning --dry-run on causes the --gas flag to be ignored. The simulation will return the estimate of the gas required to actually run the transaction. * Adjustment is no longer required. It now defaults to 1.0. * In some test cases accounts retrieved from the state do not come with a PubKey. In such cases, a fake secp256k1 key is generated and gas consumption calculated accordingly. Closes: #2110 --- PENDING.md | 2 + client/context/context.go | 2 + client/flags.go | 6 +- client/lcd/lcd_test.go | 19 +++-- client/utils/rest.go | 18 +++++ client/utils/utils.go | 101 +++++++++++++++------------ cmd/gaia/cli_test/cli_test.go | 17 ++++- docs/sdk/clients.md | 15 +++- examples/democoin/x/cool/app_test.go | 16 ++--- examples/democoin/x/pow/app_test.go | 6 +- x/auth/ante.go | 86 +++++++++++++++-------- x/auth/ante_test.go | 66 ++++++++++++++++- x/auth/client/context/context.go | 29 ++++++++ x/bank/app_test.go | 77 ++++++++++---------- x/bank/client/rest/sendtx.go | 9 ++- x/gov/client/rest/rest.go | 6 +- x/gov/client/rest/util.go | 10 ++- x/ibc/app_test.go | 8 +-- x/ibc/client/rest/transfer.go | 9 ++- x/mock/app_test.go | 6 +- x/mock/test_utils.go | 4 +- x/slashing/app_test.go | 4 +- x/slashing/client/rest/tx.go | 9 ++- x/stake/app_test.go | 10 +-- x/stake/client/rest/tx.go | 8 ++- 25 files changed, 377 insertions(+), 166 deletions(-) diff --git a/PENDING.md b/PENDING.md index 832f25e8f4..c0f250e06a 100644 --- a/PENDING.md +++ b/PENDING.md @@ -40,6 +40,7 @@ FEATURES * Gaia REST API (`gaiacli advanced rest-server`) * [lcd] Endpoints to query staking pool and params + * [lcd] \#2110 Add support for `simulate=true` requests query argument to endpoints that send txs to run simulations of transactions * Gaia CLI (`gaiacli`) * [cli] Cmds to query staking pool and params @@ -48,6 +49,7 @@ FEATURES provide desired Bech32 prefix encoding * [cli] \#2047 Setting the --gas flag value to 0 triggers a simulation of the tx before the actual execution. The gas estimate obtained via the simulation will be used as gas limit in the actual execution. * [cli] \#2047 The --gas-adjustment flag can be used to adjust the estimate obtained via the simulation triggered by --gas=0. + * [cli] \#2110 Add --dry-run flag to perform a simulation of a transaction without broadcasting it. The --gas flag is ignored as gas would be automatically estimated. * Gaia * [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address` diff --git a/client/context/context.go b/client/context/context.go index 4122cbab30..64d2375d09 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -37,6 +37,7 @@ type CLIContext struct { JSON bool PrintResponse bool Certifier tmlite.Certifier + DryRun bool } // NewCLIContext returns a new initialized CLIContext with parameters from the @@ -63,6 +64,7 @@ func NewCLIContext() CLIContext { JSON: viper.GetBool(client.FlagJson), PrintResponse: viper.GetBool(client.FlagPrintResponse), Certifier: createCertifier(), + DryRun: viper.GetBool(client.FlagDryRun), } } diff --git a/client/flags.go b/client/flags.go index 12bddb7d96..3bb4d7bc33 100644 --- a/client/flags.go +++ b/client/flags.go @@ -5,7 +5,7 @@ import "github.com/spf13/cobra" // nolint const ( DefaultGasLimit = 200000 - DefaultGasAdjustment = 1.2 + DefaultGasAdjustment = 1.0 FlagUseLedger = "ledger" FlagChainID = "chain-id" @@ -23,6 +23,7 @@ const ( FlagAsync = "async" FlagJson = "json" FlagPrintResponse = "print-response" + FlagDryRun = "dry-run" ) // LineBreak can be included in a command list to provide a blank line @@ -54,11 +55,12 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command { c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain") c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device") c.Flags().Int64(FlagGas, DefaultGasLimit, "gas limit to set per-transaction; set to 0 to calculate required gas automatically") - c.Flags().Float64(FlagGasAdjustment, DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation") + c.Flags().Float64(FlagGasAdjustment, DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ") c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously") c.Flags().Bool(FlagJson, false, "return output in json format") c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)") c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for query responses") + c.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it") } return cmds } diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index d68ba278c1..5a0694976b 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -2,6 +2,7 @@ package lcd import ( "encoding/hex" + "encoding/json" "fmt" "net/http" "regexp" @@ -265,11 +266,17 @@ func TestCoinSend(t *testing.T) { require.Equal(t, int64(1), mycoins.Amount.Int64()) // test failure with too little gas - res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 100) + res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 100, "") require.Equal(t, http.StatusInternalServerError, res.StatusCode, body) - // test success with just enough gas - res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 3000) + // run simulation and test success with estimated gas + res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 0, "?simulate=true") + require.Equal(t, http.StatusOK, res.StatusCode, body) + var responseBody struct { + GasEstimate int64 `json:"gas_estimate"` + } + require.Nil(t, json.Unmarshal([]byte(body), &responseBody)) + res, body, _ = doSendWithGas(t, port, seed, name, password, addr, responseBody.GasEstimate, "") require.Equal(t, http.StatusOK, res.StatusCode, body) } @@ -720,7 +727,7 @@ func getAccount(t *testing.T, port string, addr sdk.AccAddress) auth.Account { return acc } -func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.AccAddress, gas int64) (res *http.Response, body string, receiveAddr sdk.AccAddress) { +func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.AccAddress, gas int64, queryStr string) (res *http.Response, body string, receiveAddr sdk.AccAddress) { // create receive address kb := client.MockKeyBase() @@ -754,12 +761,12 @@ func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.Acc "chain_id":"%s" }`, gasStr, name, password, accnum, sequence, coinbz, chainID)) - res, body = Request(t, port, "POST", fmt.Sprintf("/accounts/%s/send", receiveAddr), jsonStr) + res, body = Request(t, port, "POST", fmt.Sprintf("/accounts/%s/send%v", receiveAddr, queryStr), jsonStr) return } func doSend(t *testing.T, port, seed, name, password string, addr sdk.AccAddress) (receiveAddr sdk.AccAddress, resultTx ctypes.ResultBroadcastTxCommit) { - res, body, receiveAddr := doSendWithGas(t, port, seed, name, password, addr, 0) + res, body, receiveAddr := doSendWithGas(t, port, seed, name, password, addr, 0, "") require.Equal(t, http.StatusOK, res.StatusCode, body) err := cdc.UnmarshalJSON([]byte(body), &resultTx) diff --git a/client/utils/rest.go b/client/utils/rest.go index 0e26403124..4bbc10b328 100644 --- a/client/utils/rest.go +++ b/client/utils/rest.go @@ -1,12 +1,30 @@ package utils import ( + "fmt" "net/http" ) +const ( + queryArgDryRun = "simulate" +) + // WriteErrorResponse prepares and writes a HTTP error // given a status code and an error message. func WriteErrorResponse(w *http.ResponseWriter, status int, msg string) { (*w).WriteHeader(status) (*w).Write([]byte(msg)) } + +// WriteGasEstimateResponse prepares and writes an HTTP +// response for transactions simulations. +func WriteSimulationResponse(w *http.ResponseWriter, gas int64) { + (*w).WriteHeader(http.StatusOK) + (*w).Write([]byte(fmt.Sprintf(`{"gas_estimate":%v}`, gas))) +} + +// HasDryRunArg returns true if the request's URL query contains +// the dry run argument and its value is set to "true". +func HasDryRunArg(r *http.Request) bool { + return r.URL.Query().Get(queryArgDryRun) == "true" +} diff --git a/client/utils/utils.go b/client/utils/utils.go index fb5d619887..acf90efaa0 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -15,7 +15,7 @@ import ( // DefaultGasAdjustment is applied to gas estimates to avoid tx // execution failures due to state changes that might // occur between the tx simulation and the actual run. -const DefaultGasAdjustment = 1.2 +const DefaultGasAdjustment = 1.0 // SendTx implements a auxiliary handler that facilitates sending a series of // messages in a signed transaction given a TxContext and a QueryContext. It @@ -23,35 +23,20 @@ const DefaultGasAdjustment = 1.2 // addition, it builds and signs a transaction with the supplied messages. // Finally, it broadcasts the signed transaction to a node. func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) error { - if err := cliCtx.EnsureAccountExists(); err != nil { - return err - } - - from, err := cliCtx.GetFromAddress() + txCtx, err := prepareTxContext(txCtx, cliCtx) if err != nil { return err } - - // TODO: (ref #1903) Allow for user supplied account number without - // automatically doing a manual lookup. - if txCtx.AccountNumber == 0 { - accNum, err := cliCtx.GetAccountNumber(from) + autogas := cliCtx.DryRun || (cliCtx.Gas == 0) + if autogas { + txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, msgs) if err != nil { return err } - - txCtx = txCtx.WithAccountNumber(accNum) + fmt.Fprintf(os.Stdout, "estimated gas = %v\n", txCtx.Gas) } - - // TODO: (ref #1903) Allow for user supplied account sequence without - // automatically doing a manual lookup. - if txCtx.Sequence == 0 { - accSeq, err := cliCtx.GetAccountSequence(from) - if err != nil { - return err - } - - txCtx = txCtx.WithSequence(accSeq) + if cliCtx.DryRun { + return nil } passphrase, err := keys.GetPassphrase(cliCtx.FromAddressName) @@ -59,13 +44,6 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) return err } - if cliCtx.Gas == 0 { - txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, passphrase, msgs) - if err != nil { - return err - } - } - // build and sign the transaction txBytes, err := txCtx.BuildAndSign(cliCtx.FromAddressName, passphrase, msgs) if err != nil { @@ -75,24 +53,24 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) return cliCtx.EnsureBroadcastTx(txBytes) } -// EnrichCtxWithGas calculates the gas estimate that would be consumed by the -// transaction and set the transaction's respective value accordingly. -func EnrichCtxWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name, passphrase string, msgs []sdk.Msg) (authctx.TxContext, error) { - txBytes, err := BuildAndSignTxWithZeroGas(txCtx, name, passphrase, msgs) +// SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value. +func SimulateMsgs(txCtx authctx.TxContext, cliCtx context.CLIContext, name string, msgs []sdk.Msg, gas int64) (estimated, adjusted int64, err error) { + txBytes, err := txCtx.WithGas(gas).BuildWithPubKey(name, msgs) if err != nil { - return txCtx, err + return } - estimate, adjusted, err := CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment) - if err != nil { - return txCtx, err - } - fmt.Fprintf(os.Stderr, "gas: [estimated = %v] [adjusted = %v]\n", estimate, adjusted) - return txCtx.WithGas(adjusted), nil + estimated, adjusted, err = CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment) + return } -// BuildAndSignTxWithZeroGas builds transactions with GasWanted set to 0. -func BuildAndSignTxWithZeroGas(txCtx authctx.TxContext, name, passphrase string, msgs []sdk.Msg) ([]byte, error) { - return txCtx.WithGas(0).BuildAndSign(name, passphrase, msgs) +// EnrichCtxWithGas calculates the gas estimate that would be consumed by the +// transaction and set the transaction's respective value accordingly. +func EnrichCtxWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (authctx.TxContext, error) { + _, adjusted, err := SimulateMsgs(txCtx, cliCtx, name, msgs, 0) + if err != nil { + return txCtx, err + } + return txCtx.WithGas(adjusted), nil } // CalculateGas simulates the execution of a transaction and returns @@ -109,13 +87,12 @@ func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc * return } adjusted = adjustGasEstimate(estimate, adjustment) - fmt.Fprintf(os.Stderr, "gas: [estimated = %v] [adjusted = %v]\n", estimate, adjusted) return } func adjustGasEstimate(estimate int64, adjustment float64) int64 { if adjustment == 0 { - return int64(DefaultGasAdjustment * float64(estimate)) + adjustment = DefaultGasAdjustment } return int64(adjustment * float64(estimate)) } @@ -127,3 +104,35 @@ func parseQueryResponse(cdc *amino.Codec, rawRes []byte) (int64, error) { } return simulationResult.GasUsed, nil } + +func prepareTxContext(txCtx authctx.TxContext, cliCtx context.CLIContext) (authctx.TxContext, error) { + if err := cliCtx.EnsureAccountExists(); err != nil { + return txCtx, err + } + + from, err := cliCtx.GetFromAddress() + if err != nil { + return txCtx, err + } + + // TODO: (ref #1903) Allow for user supplied account number without + // automatically doing a manual lookup. + if txCtx.AccountNumber == 0 { + accNum, err := cliCtx.GetAccountNumber(from) + if err != nil { + return txCtx, err + } + txCtx = txCtx.WithAccountNumber(accNum) + } + + // TODO: (ref #1903) Allow for user supplied account sequence without + // automatically doing a manual lookup. + if txCtx.Sequence == 0 { + accSeq, err := cliCtx.GetAccountSequence(from) + if err != nil { + return txCtx, err + } + txCtx = txCtx.WithSequence(accSeq) + } + return txCtx, nil +} diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index b91b5a45d6..696c0fc6ab 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -58,6 +58,13 @@ func TestGaiaCLISend(t *testing.T) { fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags)) require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) + // Test --dry-run + success := executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo --dry-run", flags, barAddr), app.DefaultKeyPass) + require.True(t, success) + // Check state didn't change + fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags)) + require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) + // test autosequencing executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) @@ -148,6 +155,10 @@ func TestGaiaCLICreateValidator(t *testing.T) { initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(1)) + // Test --dry-run + success := executeWrite(t, cvStr+" --dry-run", app.DefaultKeyPass) + require.True(t, success) + executeWrite(t, cvStr, app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) @@ -164,7 +175,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { unbondStr += fmt.Sprintf(" --validator=%s", sdk.ValAddress(barAddr)) unbondStr += fmt.Sprintf(" --shares-amount=%v", "1") - success := executeWrite(t, unbondStr, app.DefaultKeyPass) + success = executeWrite(t, unbondStr, app.DefaultKeyPass) require.True(t, success) tests.WaitForNextNBlocksTM(2, port) @@ -211,6 +222,10 @@ func TestGaiaCLISubmitProposal(t *testing.T) { spStr += fmt.Sprintf(" --title=%s", "Test") spStr += fmt.Sprintf(" --description=%s", "test") + // Test --dry-run + success := executeWrite(t, spStr+" --dry-run", app.DefaultKeyPass) + require.True(t, success) + executeWrite(t, spStr, app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) diff --git a/docs/sdk/clients.md b/docs/sdk/clients.md index 7a23ba28ac..62d79bbacd 100644 --- a/docs/sdk/clients.md +++ b/docs/sdk/clients.md @@ -95,6 +95,8 @@ When you query an account balance with zero tokens, you will get this error: `No ### Send Tokens +The following command could be used to send coins from one account to another: + ```bash gaiacli send \ --amount=10faucetToken \ @@ -110,7 +112,7 @@ The `--amount` flag accepts the format `--amount=<value|coin_name>`. ::: tip Note You may want to cap the maximum gas that can be consumed by the transaction via the `--gas` flag. If set to 0, the gas limit will be automatically estimated. -Gas estimate might be inaccurate as state changes could occur in between the end of the simulation and the actual execution of a transaction, thus an adjustment is applied on top of the original estimate in order to ensure the transaction is broadcasted successfully. The adjustment can be controlled via the `--gas-adjustment` flag, whose default value is 1.2. +Gas estimate might be inaccurate as state changes could occur in between the end of the simulation and the actual execution of a transaction, thus an adjustment is applied on top of the original estimate in order to ensure the transaction is broadcasted successfully. The adjustment can be controlled via the `--gas-adjustment` flag, whose default value is 1.0. ::: Now, view the updated balances of the origin and destination accounts: @@ -126,6 +128,17 @@ You can also check your balance at a given block by using the `--block` flag: gaiacli account <account_cosmos> --block=<block_height> ``` +You can simulate a transaction without actually broadcasting it by appending the `--dry-run` flag to the command line: + +```bash +gaiacli send \ + --amount=10faucetToken \ + --chain-id=<chain_id> \ + --name=<key_name> \ + --to=<destination_cosmosaccaddr> \ + --dry-run +``` + ### Staking #### Set up a Validator diff --git a/examples/democoin/x/cool/app_test.go b/examples/democoin/x/cool/app_test.go index 71b4202bc3..c0453a58ec 100644 --- a/examples/democoin/x/cool/app_test.go +++ b/examples/democoin/x/cool/app_test.go @@ -88,17 +88,17 @@ func TestMsgQuiz(t *testing.T) { require.Equal(t, acc1, res1) // Set the trend, submit a really cool quiz and check for reward - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg1}, []int64{0}, []int64{0}, true, priv1) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{1}, true, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg1}, []int64{0}, []int64{0}, true, true, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{1}, true, true, priv1) mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(69)}}) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{2}, false, priv1) // result without reward + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{2}, false, false, priv1) // result without reward mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(69)}}) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{3}, true, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{3}, true, true, priv1) mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(138)}}) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg2}, []int64{0}, []int64{4}, true, priv1) // reset the trend - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{5}, false, priv1) // the same answer will nolonger do! + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg2}, []int64{0}, []int64{4}, true, true, priv1) // reset the trend + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{5}, false, false, priv1) // the same answer will nolonger do! mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(138)}}) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{6}, true, priv1) // earlier answer now relevant again + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{6}, true, true, priv1) // earlier answer now relevant again mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"badvibesonly", sdk.NewInt(69)}, {"icecold", sdk.NewInt(138)}}) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg3}, []int64{0}, []int64{7}, false, priv1) // expect to fail to set the trend to something which is not cool + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg3}, []int64{0}, []int64{7}, false, false, priv1) // expect to fail to set the trend to something which is not cool } diff --git a/examples/democoin/x/pow/app_test.go b/examples/democoin/x/pow/app_test.go index dc53d1d998..76f062e3b0 100644 --- a/examples/democoin/x/pow/app_test.go +++ b/examples/democoin/x/pow/app_test.go @@ -74,13 +74,13 @@ func TestMsgMine(t *testing.T) { // Mine and check for reward mineMsg1 := GenerateMsgMine(addr1, 1, 2) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg1}, []int64{0}, []int64{0}, true, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg1}, []int64{0}, []int64{0}, true, true, priv1) mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(1)}}) // Mine again and check for reward mineMsg2 := GenerateMsgMine(addr1, 2, 3) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, true, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, true, true, priv1) mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(2)}}) // Mine again - should be invalid - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, false, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, false, false, priv1) mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(2)}}) } diff --git a/x/auth/ante.go b/x/auth/ante.go index c0a129be3e..94899a8726 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -65,9 +65,12 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler { return newCtx, err.Result(), true } - sigs := stdTx.GetSignatures() + sigs := stdTx.GetSignatures() // When simulating, this would just be a 0-length slice. signerAddrs := stdTx.GetSigners() msgs := tx.GetMsgs() + if simulate { + sigs = make([]StdSignature, len(signerAddrs)) + } // charge gas for the memo newCtx.GasMeter().ConsumeGas(memoCostPerByte*sdk.Gas(len(stdTx.GetMemo())), "memo") @@ -88,10 +91,7 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler { // check signature, return account with incremented nonce signBytes := StdSignBytes(newCtx.ChainID(), accNums[i], sequences[i], fee, msgs, stdTx.GetMemo()) - signerAcc, res := processSig( - newCtx, am, - signerAddr, sig, signBytes, - ) + signerAcc, res := processSig(newCtx, am, signerAddr, sig, signBytes, simulate) if !res.IsOK() { return newCtx, res, true } @@ -149,58 +149,82 @@ func validateBasic(tx StdTx) (err sdk.Error) { // if the account doesn't have a pubkey, set it. func processSig( ctx sdk.Context, am AccountMapper, - addr sdk.AccAddress, sig StdSignature, signBytes []byte) ( + addr sdk.AccAddress, sig StdSignature, signBytes []byte, simulate bool) ( acc Account, res sdk.Result) { - // Get the account. acc = am.GetAccount(ctx, addr) if acc == nil { return nil, sdk.ErrUnknownAddress(addr.String()).Result() } - // Check account number. accnum := acc.GetAccountNumber() - if accnum != sig.AccountNumber { - return nil, sdk.ErrInvalidSequence( - fmt.Sprintf("Invalid account number. Got %d, expected %d", sig.AccountNumber, accnum)).Result() - } - - // Check and increment sequence number. seq := acc.GetSequence() - if seq != sig.Sequence { - return nil, sdk.ErrInvalidSequence( - fmt.Sprintf("Invalid sequence. Got %d, expected %d", sig.Sequence, seq)).Result() + + // Perform checks that wouldn't pass successfully in simulation, i.e. sig + // would be empty as simulated transactions come with no signatures whatsoever. + if !simulate { + // Check account number. + if accnum != sig.AccountNumber { + return nil, sdk.ErrInvalidSequence( + fmt.Sprintf("Invalid account number. Got %d, expected %d", sig.AccountNumber, accnum)).Result() + } + + // Check sequence number. + if seq != sig.Sequence { + return nil, sdk.ErrInvalidSequence( + fmt.Sprintf("Invalid sequence. Got %d, expected %d", sig.Sequence, seq)).Result() + } } + // Increment sequence number err := acc.SetSequence(seq + 1) if err != nil { // Handle w/ #870 panic(err) } + // If pubkey is not known for account, + // set it from the StdSignature. + pubKey, res := processPubKey(acc, sig, simulate) + if !res.IsOK() { + return nil, res + } + err = acc.SetPubKey(pubKey) + if err != nil { + return nil, sdk.ErrInternal("setting PubKey on signer's account").Result() + } + + consumeSignatureVerificationGas(ctx.GasMeter(), pubKey) + if !simulate && !pubKey.VerifyBytes(signBytes, sig.Signature) { + return nil, sdk.ErrUnauthorized("signature verification failed").Result() + } + + return +} + +func processPubKey(acc Account, sig StdSignature, simulate bool) (crypto.PubKey, sdk.Result) { // If pubkey is not known for account, // set it from the StdSignature. pubKey := acc.GetPubKey() + if simulate { + // In simulate mode the transaction comes with no signatures, thus + // if the account's pubkey is nil, both signature verification + // and gasKVStore.Set() shall consume the largest amount, i.e. + // it takes more gas to verifiy secp256k1 keys than ed25519 ones. + if pubKey == nil { + return secp256k1.GenPrivKey().PubKey(), sdk.Result{} + } + return pubKey, sdk.Result{} + } if pubKey == nil { pubKey = sig.PubKey if pubKey == nil { return nil, sdk.ErrInvalidPubKey("PubKey not found").Result() } - if !bytes.Equal(pubKey.Address(), addr) { + if !bytes.Equal(pubKey.Address(), acc.GetAddress()) { return nil, sdk.ErrInvalidPubKey( - fmt.Sprintf("PubKey does not match Signer address %v", addr)).Result() - } - err = acc.SetPubKey(pubKey) - if err != nil { - return nil, sdk.ErrInternal("setting PubKey on signer's account").Result() + fmt.Sprintf("PubKey does not match Signer address %v", acc.GetAddress())).Result() } } - - // Check sig. - consumeSignatureVerificationGas(ctx.GasMeter(), pubKey) - if !pubKey.VerifyBytes(signBytes, sig.Signature) { - return nil, sdk.ErrUnauthorized("signature verification failed").Result() - } - - return + return pubKey, sdk.Result{} } func consumeSignatureVerificationGas(meter sdk.GasMeter, pubkey crypto.PubKey) { diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index a841bc7760..e137845122 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -4,14 +4,14 @@ import ( "fmt" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" + wire "github.com/cosmos/cosmos-sdk/wire" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/tendermint/tendermint/libs/log" - - sdk "github.com/cosmos/cosmos-sdk/types" - wire "github.com/cosmos/cosmos-sdk/wire" ) func newTestMsg(addrs ...sdk.AccAddress) *sdk.TestMsg { @@ -567,3 +567,63 @@ func TestAnteHandlerSetPubKey(t *testing.T) { acc2 = mapper.GetAccount(ctx, addr2) require.Nil(t, acc2.GetPubKey()) } + +func TestProcessPubKey(t *testing.T) { + ms, capKey, _ := setupMultiStore() + cdc := wire.NewCodec() + RegisterBaseAccount(cdc) + mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) + ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) + // keys + _, addr1 := privAndAddr() + priv2, _ := privAndAddr() + acc1 := mapper.NewAccountWithAddress(ctx, addr1) + type args struct { + acc Account + sig StdSignature + simulate bool + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"no sigs, simulate off", args{acc1, StdSignature{}, false}, true}, + {"no sigs, simulate on", args{acc1, StdSignature{}, true}, false}, + {"pubkey doesn't match addr, simulate off", args{acc1, StdSignature{PubKey: priv2.PubKey()}, false}, true}, + {"pubkey doesn't match addr, simulate on", args{acc1, StdSignature{PubKey: priv2.PubKey()}, true}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := processPubKey(tt.args.acc, tt.args.sig, tt.args.simulate) + require.Equal(t, tt.wantErr, !err.IsOK()) + }) + } +} + +func TestConsumeSignatureVerificationGas(t *testing.T) { + type args struct { + meter sdk.GasMeter + pubkey crypto.PubKey + } + tests := []struct { + name string + args args + gasConsumed int64 + wantPanic bool + }{ + {"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), ed25519.GenPrivKey().PubKey()}, ed25519VerifyCost, false}, + {"PubKeySecp256k1", args{sdk.NewInfiniteGasMeter(), secp256k1.GenPrivKey().PubKey()}, secp256k1VerifyCost, false}, + {"unknown key", args{sdk.NewInfiniteGasMeter(), nil}, 0, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.wantPanic { + require.Panics(t, func() { consumeSignatureVerificationGas(tt.args.meter, tt.args.pubkey) }) + } else { + consumeSignatureVerificationGas(tt.args.meter, tt.args.pubkey) + require.Equal(t, tt.args.meter.GasConsumed(), tt.gasConsumed) + } + }) + } +} diff --git a/x/auth/client/context/context.go b/x/auth/client/context/context.go index 8d0a94136d..5e55696b83 100644 --- a/x/auth/client/context/context.go +++ b/x/auth/client/context/context.go @@ -148,3 +148,32 @@ func (ctx TxContext) BuildAndSign(name, passphrase string, msgs []sdk.Msg) ([]by return ctx.Sign(name, passphrase, msg) } + +// BuildWithPubKey builds a single message to be signed from a TxContext given a set of +// messages and attach the public key associated to the given name. +// It returns an error if a fee is supplied but cannot be parsed or the key cannot be +// retrieved. +func (ctx TxContext) BuildWithPubKey(name string, msgs []sdk.Msg) ([]byte, error) { + msg, err := ctx.Build(msgs) + if err != nil { + return nil, err + } + + keybase, err := keys.GetKeyBase() + if err != nil { + return nil, err + } + + info, err := keybase.Get(name) + if err != nil { + return nil, err + } + + sigs := []auth.StdSignature{{ + AccountNumber: msg.AccountNumber, + Sequence: msg.Sequence, + PubKey: info.GetPubKey(), + }} + + return ctx.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo)) +} diff --git a/x/bank/app_test.go b/x/bank/app_test.go index c8d0a417dc..7ef344ffcd 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -21,6 +21,7 @@ type ( } appTestCase struct { + expSimPass bool expPass bool msgs []sdk.Msg accNums []int64 @@ -107,27 +108,29 @@ func TestMsgSendWithAccounts(t *testing.T) { testCases := []appTestCase{ { - msgs: []sdk.Msg{sendMsg1}, - accNums: []int64{0}, - accSeqs: []int64{0}, - expPass: true, - privKeys: []crypto.PrivKey{priv1}, + msgs: []sdk.Msg{sendMsg1}, + accNums: []int64{0}, + accSeqs: []int64{0}, + expSimPass: true, + expPass: true, + privKeys: []crypto.PrivKey{priv1}, expectedBalances: []expectedBalance{ {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 57)}}, {addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}}, }, }, { - msgs: []sdk.Msg{sendMsg1, sendMsg2}, - accNums: []int64{0}, - accSeqs: []int64{0}, - expPass: false, - privKeys: []crypto.PrivKey{priv1}, + msgs: []sdk.Msg{sendMsg1, sendMsg2}, + accNums: []int64{0}, + accSeqs: []int64{0}, + expSimPass: true, + expPass: false, + privKeys: []crypto.PrivKey{priv1}, }, } for _, tc := range testCases { - mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...) + mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) for _, eb := range tc.expectedBalances { mock.CheckBalance(t, mapp, eb.addr, eb.coins) @@ -144,7 +147,7 @@ func TestMsgSendWithAccounts(t *testing.T) { require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) // resigning the tx with the bumped sequence should work - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg1, sendMsg2}, []int64{0}, []int64{1}, true, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg1, sendMsg2}, []int64{0}, []int64{1}, true, true, priv1) } func TestMsgSendMultipleOut(t *testing.T) { @@ -163,11 +166,12 @@ func TestMsgSendMultipleOut(t *testing.T) { testCases := []appTestCase{ { - msgs: []sdk.Msg{sendMsg2}, - accNums: []int64{0}, - accSeqs: []int64{0}, - expPass: true, - privKeys: []crypto.PrivKey{priv1}, + msgs: []sdk.Msg{sendMsg2}, + accNums: []int64{0}, + accSeqs: []int64{0}, + expSimPass: true, + expPass: true, + privKeys: []crypto.PrivKey{priv1}, expectedBalances: []expectedBalance{ {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, {addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 47)}}, @@ -177,7 +181,7 @@ func TestMsgSendMultipleOut(t *testing.T) { } for _, tc := range testCases { - mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...) + mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) for _, eb := range tc.expectedBalances { mock.CheckBalance(t, mapp, eb.addr, eb.coins) @@ -205,11 +209,12 @@ func TestSengMsgMultipleInOut(t *testing.T) { testCases := []appTestCase{ { - msgs: []sdk.Msg{sendMsg3}, - accNums: []int64{0, 2}, - accSeqs: []int64{0, 0}, - expPass: true, - privKeys: []crypto.PrivKey{priv1, priv4}, + msgs: []sdk.Msg{sendMsg3}, + accNums: []int64{0, 2}, + accSeqs: []int64{0, 0}, + expSimPass: true, + expPass: true, + privKeys: []crypto.PrivKey{priv1, priv4}, expectedBalances: []expectedBalance{ {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, {addr4, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, @@ -220,7 +225,7 @@ func TestSengMsgMultipleInOut(t *testing.T) { } for _, tc := range testCases { - mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...) + mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) for _, eb := range tc.expectedBalances { mock.CheckBalance(t, mapp, eb.addr, eb.coins) @@ -240,22 +245,24 @@ func TestMsgSendDependent(t *testing.T) { testCases := []appTestCase{ { - msgs: []sdk.Msg{sendMsg1}, - accNums: []int64{0}, - accSeqs: []int64{0}, - expPass: true, - privKeys: []crypto.PrivKey{priv1}, + msgs: []sdk.Msg{sendMsg1}, + accNums: []int64{0}, + accSeqs: []int64{0}, + expSimPass: true, + expPass: true, + privKeys: []crypto.PrivKey{priv1}, expectedBalances: []expectedBalance{ {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}}, {addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}}, }, }, { - msgs: []sdk.Msg{sendMsg4}, - accNums: []int64{1}, - accSeqs: []int64{0}, - expPass: true, - privKeys: []crypto.PrivKey{priv2}, + msgs: []sdk.Msg{sendMsg4}, + accNums: []int64{1}, + accSeqs: []int64{0}, + expSimPass: true, + expPass: true, + privKeys: []crypto.PrivKey{priv2}, expectedBalances: []expectedBalance{ {addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}}, }, @@ -263,7 +270,7 @@ func TestMsgSendDependent(t *testing.T) { } for _, tc := range testCases { - mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...) + mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...) for _, eb := range tc.expectedBalances { mock.CheckBalance(t, mapp, eb.addr, eb.coins) diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index c7baa96910..07b0b87862 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -40,6 +40,7 @@ func init() { } // SendRequestHandlerFn - http request handler to send coins to a address +// nolint: gocyclo func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // collect data @@ -85,12 +86,16 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo Sequence: m.Sequence, } - if m.Gas == 0 { - newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg}) + if utils.HasDryRunArg(r) || m.Gas == 0 { + newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) return } + if utils.HasDryRunArg(r) { + utils.WriteSimulationResponse(&w, txCtx.Gas) + return + } txCtx = newCtx } diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 4e6a5c1b37..5241a39141 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -81,7 +81,7 @@ func postProposalHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.Hand return } - signAndBuild(w, cliCtx, req.BaseReq, msg, cdc) + signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc) } } @@ -118,7 +118,7 @@ func depositHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFu return } - signAndBuild(w, cliCtx, req.BaseReq, msg, cdc) + signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc) } } @@ -155,7 +155,7 @@ func voteHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc return } - signAndBuild(w, cliCtx, req.BaseReq, msg, cdc) + signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc) } } diff --git a/x/gov/client/rest/util.go b/x/gov/client/rest/util.go index f98f7bfa59..d664be5ad0 100644 --- a/x/gov/client/rest/util.go +++ b/x/gov/client/rest/util.go @@ -66,7 +66,7 @@ func (req baseReq) baseReqValidate(w http.ResponseWriter) bool { // TODO: Build this function out into a more generic base-request // (probably should live in client/lcd). -func signAndBuild(w http.ResponseWriter, cliCtx context.CLIContext, baseReq baseReq, msg sdk.Msg, cdc *wire.Codec) { +func signAndBuild(w http.ResponseWriter, r *http.Request, cliCtx context.CLIContext, baseReq baseReq, msg sdk.Msg, cdc *wire.Codec) { var err error txCtx := authctx.TxContext{ Codec: cdc, @@ -76,12 +76,16 @@ func signAndBuild(w http.ResponseWriter, cliCtx context.CLIContext, baseReq base Gas: baseReq.Gas, } - if baseReq.Gas == 0 { - newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, baseReq.Name, baseReq.Password, []sdk.Msg{msg}) + if utils.HasDryRunArg(r) || baseReq.Gas == 0 { + newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, baseReq.Name, []sdk.Msg{msg}) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) return } + if utils.HasDryRunArg(r) { + utils.WriteSimulationResponse(&w, txCtx.Gas) + return + } txCtx = newCtx } txBytes, err := txCtx.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg}) diff --git a/x/ibc/app_test.go b/x/ibc/app_test.go index 5c3a0df78e..f761f861d6 100644 --- a/x/ibc/app_test.go +++ b/x/ibc/app_test.go @@ -70,10 +70,10 @@ func TestIBCMsgs(t *testing.T) { Sequence: 0, } - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{0}, true, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{0}, true, true, priv1) mock.CheckBalance(t, mapp, addr1, emptyCoins) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{1}, false, priv1) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, true, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{1}, false, false, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, true, true, priv1) mock.CheckBalance(t, mapp, addr1, coins) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, false, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, false, false, priv1) } diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go index 765208b056..ba0a845c29 100644 --- a/x/ibc/client/rest/transfer.go +++ b/x/ibc/client/rest/transfer.go @@ -33,6 +33,7 @@ type transferBody struct { // TransferRequestHandler - http request handler to transfer coins to a address // on a different chain via IBC +// nolint: gocyclo func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -76,12 +77,16 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C Gas: m.Gas, } - if m.Gas == 0 { - newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg}) + if utils.HasDryRunArg(r) || m.Gas == 0 { + newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) return } + if utils.HasDryRunArg(r) { + utils.WriteSimulationResponse(&w, txCtx.Gas) + return + } txCtx = newCtx } diff --git a/x/mock/app_test.go b/x/mock/app_test.go index 7477e12044..460757a043 100644 --- a/x/mock/app_test.go +++ b/x/mock/app_test.go @@ -61,14 +61,14 @@ func TestCheckAndDeliverGenTx(t *testing.T) { SignCheckDeliver( t, mApp.BaseApp, []sdk.Msg{msg}, []int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence()}, - true, privKeys[0], + true, true, privKeys[0], ) // Signing a tx with the wrong privKey should result in an auth error res := SignCheckDeliver( t, mApp.BaseApp, []sdk.Msg{msg}, []int64{accs[1].GetAccountNumber()}, []int64{accs[1].GetSequence() + 1}, - false, privKeys[1], + true, false, privKeys[1], ) require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) @@ -76,7 +76,7 @@ func TestCheckAndDeliverGenTx(t *testing.T) { SignCheckDeliver( t, mApp.BaseApp, []sdk.Msg{msg}, []int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence() + 1}, - true, privKeys[0], + true, true, privKeys[0], ) } diff --git a/x/mock/test_utils.go b/x/mock/test_utils.go index c97f1c0c85..caaca6c9a5 100644 --- a/x/mock/test_utils.go +++ b/x/mock/test_utils.go @@ -71,13 +71,13 @@ func CheckGenTx( // returned. func SignCheckDeliver( t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accNums []int64, - seq []int64, expPass bool, priv ...crypto.PrivKey, + seq []int64, expSimPass, expPass bool, priv ...crypto.PrivKey, ) sdk.Result { tx := GenTx(msgs, accNums, seq, priv...) // Must simulate now as CheckTx doesn't run Msgs anymore res := app.Simulate(tx) - if expPass { + if expSimPass { require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) } else { require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index f9ec0833fa..671c2241e8 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -102,7 +102,7 @@ func TestSlashingMsgs(t *testing.T) { createValidatorMsg := stake.NewMsgCreateValidator( sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description, ) - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1) + mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, true, priv1) mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin.Minus(bondCoin)}) mapp.BeginBlock(abci.RequestBeginBlock{}) @@ -116,6 +116,6 @@ func TestSlashingMsgs(t *testing.T) { checkValidatorSigningInfo(t, mapp, keeper, sdk.ValAddress(addr1), false) // unjail should fail with unknown validator - res := mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{unjailMsg}, []int64{0}, []int64{1}, false, priv1) + res := mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{unjailMsg}, []int64{0}, []int64{1}, false, false, priv1) require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotJailed), res.Code) } diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index c7efdc97e9..3728558839 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -36,6 +36,7 @@ type UnjailBody struct { ValidatorAddr string `json:"validator_addr"` } +// nolint: gocyclo func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var m UnjailBody @@ -77,12 +78,16 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI msg := slashing.NewMsgUnjail(valAddr) - if m.Gas == 0 { - newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg}) + if utils.HasDryRunArg(r) || m.Gas == 0 { + newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) return } + if utils.HasDryRunArg(r) { + utils.WriteSimulationResponse(&w, txCtx.Gas) + return + } txCtx = newCtx } diff --git a/x/stake/app_test.go b/x/stake/app_test.go index 587e90b465..bfeff5df76 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -131,7 +131,7 @@ func TestStakeMsgs(t *testing.T) { sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description, ) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1) + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, true, priv1) mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin)}) mApp.BeginBlock(abci.RequestBeginBlock{}) @@ -145,7 +145,7 @@ func TestStakeMsgs(t *testing.T) { addr1, sdk.ValAddress(addr2), priv2.PubKey(), bondCoin, description, ) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []int64{0, 1}, []int64{1, 0}, true, priv1, priv2) + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []int64{0, 1}, []int64{1, 0}, true, true, priv1, priv2) mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin).Minus(bondCoin)}) mApp.BeginBlock(abci.RequestBeginBlock{}) @@ -161,7 +161,7 @@ func TestStakeMsgs(t *testing.T) { description = NewDescription("bar_moniker", "", "", "") editValidatorMsg := NewMsgEditValidator(sdk.ValAddress(addr1), description) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{2}, true, priv1) + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{2}, true, true, priv1) validator = checkValidator(t, mApp, keeper, sdk.ValAddress(addr1), true) require.Equal(t, description, validator.Description) @@ -169,13 +169,13 @@ func TestStakeMsgs(t *testing.T) { mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin}) delegateMsg := NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, priv2) + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, true, priv2) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), true, sdk.NewDec(10)) // begin unbonding beginUnbondingMsg := NewMsgBeginUnbonding(addr2, sdk.ValAddress(addr1), sdk.NewDec(10)) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, priv2) + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, true, priv2) // delegation should exist anymore checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), false, sdk.Dec{}) diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 24a8c38752..320205dd71 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -276,12 +276,16 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex m.Sequence++ - if m.Gas == 0 { - newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg}) + if utils.HasDryRunArg(r) || m.Gas == 0 { + newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) return } + if utils.HasDryRunArg(r) { + utils.WriteSimulationResponse(&w, txCtx.Gas) + return + } txCtx = newCtx } From 1370ca611b6077f798d40487d490dcb07f1b58c7 Mon Sep 17 00:00:00 2001 From: Alessio Treglia <quadrispro@ubuntu.com> Date: Fri, 31 Aug 2018 19:04:42 +0200 Subject: [PATCH 22/28] Set GasAdjustment in CLIContext when handling HTTP requests This is to address @alexanderbez's comments --- client/context/context.go | 4 ++++ client/flags.go | 5 ++++- client/lcd/lcd_test.go | 24 +++++++++++++++++------- client/utils/rest.go | 15 +++++++++++++++ client/utils/utils.go | 8 -------- x/bank/client/rest/sendtx.go | 8 ++++++++ x/gov/client/rest/util.go | 8 ++++++++ x/ibc/client/rest/transfer.go | 8 ++++++++ x/slashing/client/rest/tx.go | 8 ++++++++ x/stake/client/rest/tx.go | 8 ++++++++ 10 files changed, 80 insertions(+), 16 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index 64d2375d09..2444c56d13 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -159,5 +159,9 @@ func (ctx CLIContext) WithUseLedger(useLedger bool) CLIContext { // WithCertifier - return a copy of the context with an updated Certifier func (ctx CLIContext) WithCertifier(certifier tmlite.Certifier) CLIContext { ctx.Certifier = certifier + +// WithGasAdjustment returns a copy of the context with an updated GasAdjustment flag. +func (ctx CLIContext) WithGasAdjustment(adjustment float64) CLIContext { + ctx.GasAdjustment = adjustment return ctx } diff --git a/client/flags.go b/client/flags.go index 3bb4d7bc33..a1d3c6e178 100644 --- a/client/flags.go +++ b/client/flags.go @@ -4,8 +4,11 @@ import "github.com/spf13/cobra" // nolint const ( - DefaultGasLimit = 200000 + // DefaultGasAdjustment is applied to gas estimates to avoid tx + // execution failures due to state changes that might + // occur between the tx simulation and the actual run. DefaultGasAdjustment = 1.0 + DefaultGasLimit = 200000 FlagUseLedger = "ledger" FlagChainID = "chain-id" diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 5a0694976b..707cc21f7a 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -266,17 +266,21 @@ func TestCoinSend(t *testing.T) { require.Equal(t, int64(1), mycoins.Amount.Int64()) // test failure with too little gas - res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 100, "") + res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 100, 0, "") + require.Equal(t, http.StatusInternalServerError, res.StatusCode, body) + + // test failure with wrong adjustment + res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 0, 0.1, "") require.Equal(t, http.StatusInternalServerError, res.StatusCode, body) // run simulation and test success with estimated gas - res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 0, "?simulate=true") + res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 0, 0, "?simulate=true") require.Equal(t, http.StatusOK, res.StatusCode, body) var responseBody struct { GasEstimate int64 `json:"gas_estimate"` } require.Nil(t, json.Unmarshal([]byte(body), &responseBody)) - res, body, _ = doSendWithGas(t, port, seed, name, password, addr, responseBody.GasEstimate, "") + res, body, _ = doSendWithGas(t, port, seed, name, password, addr, responseBody.GasEstimate, 0, "") require.Equal(t, http.StatusOK, res.StatusCode, body) } @@ -727,7 +731,7 @@ func getAccount(t *testing.T, port string, addr sdk.AccAddress) auth.Account { return acc } -func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.AccAddress, gas int64, queryStr string) (res *http.Response, body string, receiveAddr sdk.AccAddress) { +func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.AccAddress, gas int64, gasAdjustment float64, queryStr string) (res *http.Response, body string, receiveAddr sdk.AccAddress) { // create receive address kb := client.MockKeyBase() @@ -751,22 +755,28 @@ func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.Acc "gas":"%v", `, gas) } + gasAdjustmentStr := "" + if gasAdjustment > 0 { + gasStr = fmt.Sprintf(` + "gas_adjustment":"%v", + `, gasAdjustment) + } jsonStr := []byte(fmt.Sprintf(`{ - %v + %v%v "name":"%s", "password":"%s", "account_number":"%d", "sequence":"%d", "amount":[%s], "chain_id":"%s" - }`, gasStr, name, password, accnum, sequence, coinbz, chainID)) + }`, gasStr, gasAdjustmentStr, name, password, accnum, sequence, coinbz, chainID)) res, body = Request(t, port, "POST", fmt.Sprintf("/accounts/%s/send%v", receiveAddr, queryStr), jsonStr) return } func doSend(t *testing.T, port, seed, name, password string, addr sdk.AccAddress) (receiveAddr sdk.AccAddress, resultTx ctypes.ResultBroadcastTxCommit) { - res, body, receiveAddr := doSendWithGas(t, port, seed, name, password, addr, 0, "") + res, body, receiveAddr := doSendWithGas(t, port, seed, name, password, addr, 0, 0, "") require.Equal(t, http.StatusOK, res.StatusCode, body) err := cdc.UnmarshalJSON([]byte(body), &resultTx) diff --git a/client/utils/rest.go b/client/utils/rest.go index 4bbc10b328..b369a81274 100644 --- a/client/utils/rest.go +++ b/client/utils/rest.go @@ -3,6 +3,7 @@ package utils import ( "fmt" "net/http" + "strconv" ) const ( @@ -28,3 +29,17 @@ func WriteSimulationResponse(w *http.ResponseWriter, gas int64) { func HasDryRunArg(r *http.Request) bool { return r.URL.Query().Get(queryArgDryRun) == "true" } + +// ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a default +// value if the string is empty. Write +func ParseFloat64OrReturnBadRequest(w *http.ResponseWriter, s string, defaultIfEmpty float64) (n float64, ok bool) { + if len(s) == 0 { + return defaultIfEmpty, true + } + n, err := strconv.ParseFloat(s, 64) + if err != nil { + WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return n, false + } + return n, true +} diff --git a/client/utils/utils.go b/client/utils/utils.go index acf90efaa0..20b1c6bc54 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -12,11 +12,6 @@ import ( "github.com/tendermint/tendermint/libs/common" ) -// DefaultGasAdjustment is applied to gas estimates to avoid tx -// execution failures due to state changes that might -// occur between the tx simulation and the actual run. -const DefaultGasAdjustment = 1.0 - // SendTx implements a auxiliary handler that facilitates sending a series of // messages in a signed transaction given a TxContext and a QueryContext. It // ensures that the account exists, has a proper number and sequence set. In @@ -91,9 +86,6 @@ func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc * } func adjustGasEstimate(estimate int64, adjustment float64) int64 { - if adjustment == 0 { - adjustment = DefaultGasAdjustment - } return int64(adjustment * float64(estimate)) } diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index 07b0b87862..41635d28a8 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "net/http" + cliclient "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/utils" "github.com/cosmos/cosmos-sdk/crypto/keys" @@ -31,6 +32,7 @@ type sendBody struct { AccountNumber int64 `json:"account_number"` Sequence int64 `json:"sequence"` Gas int64 `json:"gas"` + GasAdjustment string `json:"gas_adjustment"` } var msgCdc = wire.NewCodec() @@ -86,6 +88,12 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo Sequence: m.Sequence, } + adjustment, ok := utils.ParseFloat64OrReturnBadRequest(&w, m.GasAdjustment, cliclient.DefaultGasAdjustment) + if !ok { + return + } + cliCtx = cliCtx.WithGasAdjustment(adjustment) + if utils.HasDryRunArg(r) || m.Gas == 0 { newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { diff --git a/x/gov/client/rest/util.go b/x/gov/client/rest/util.go index d664be5ad0..f563b4ec20 100644 --- a/x/gov/client/rest/util.go +++ b/x/gov/client/rest/util.go @@ -6,6 +6,7 @@ import ( "net/http" "strconv" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/utils" sdk "github.com/cosmos/cosmos-sdk/types" @@ -20,6 +21,7 @@ type baseReq struct { AccountNumber int64 `json:"account_number"` Sequence int64 `json:"sequence"` Gas int64 `json:"gas"` + GasAdjustment string `json:"gas_adjustment"` } func buildReq(w http.ResponseWriter, r *http.Request, cdc *wire.Codec, req interface{}) error { @@ -76,6 +78,12 @@ func signAndBuild(w http.ResponseWriter, r *http.Request, cliCtx context.CLICont Gas: baseReq.Gas, } + adjustment, ok := utils.ParseFloat64OrReturnBadRequest(&w, baseReq.GasAdjustment, client.DefaultGasAdjustment) + if !ok { + return + } + cliCtx = cliCtx.WithGasAdjustment(adjustment) + if utils.HasDryRunArg(r) || baseReq.Gas == 0 { newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, baseReq.Name, []sdk.Msg{msg}) if err != nil { diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go index ba0a845c29..111f9086d0 100644 --- a/x/ibc/client/rest/transfer.go +++ b/x/ibc/client/rest/transfer.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "net/http" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/utils" "github.com/cosmos/cosmos-sdk/crypto/keys" @@ -29,6 +30,7 @@ type transferBody struct { AccountNumber int64 `json:"account_number"` Sequence int64 `json:"sequence"` Gas int64 `json:"gas"` + GasAdjustment string `json:"gas_adjustment"` } // TransferRequestHandler - http request handler to transfer coins to a address @@ -77,6 +79,12 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C Gas: m.Gas, } + adjustment, ok := utils.ParseFloat64OrReturnBadRequest(&w, m.GasAdjustment, client.DefaultGasAdjustment) + if !ok { + return + } + cliCtx = cliCtx.WithGasAdjustment(adjustment) + if utils.HasDryRunArg(r) || m.Gas == 0 { newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index 3728558839..322a4aa083 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "net/http" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/utils" "github.com/cosmos/cosmos-sdk/crypto/keys" @@ -33,6 +34,7 @@ type UnjailBody struct { AccountNumber int64 `json:"account_number"` Sequence int64 `json:"sequence"` Gas int64 `json:"gas"` + GasAdjustment string `json:"gas_adjustment"` ValidatorAddr string `json:"validator_addr"` } @@ -78,6 +80,12 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI msg := slashing.NewMsgUnjail(valAddr) + adjustment, ok := utils.ParseFloat64OrReturnBadRequest(&w, m.GasAdjustment, client.DefaultGasAdjustment) + if !ok { + return + } + cliCtx = cliCtx.WithGasAdjustment(adjustment) + if utils.HasDryRunArg(r) || m.Gas == 0 { newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 320205dd71..5e6226dcc7 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "net/http" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/utils" "github.com/cosmos/cosmos-sdk/crypto/keys" @@ -60,6 +61,7 @@ type EditDelegationsBody struct { AccountNumber int64 `json:"account_number"` Sequence int64 `json:"sequence"` Gas int64 `json:"gas"` + GasAdjustment string `json:"gas_adjustment"` Delegations []msgDelegationsInput `json:"delegations"` BeginUnbondings []msgBeginUnbondingInput `json:"begin_unbondings"` CompleteUnbondings []msgCompleteUnbondingInput `json:"complete_unbondings"` @@ -276,6 +278,12 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex m.Sequence++ + adjustment, ok := utils.ParseFloat64OrReturnBadRequest(&w, m.GasAdjustment, client.DefaultGasAdjustment) + if !ok { + return + } + cliCtx = cliCtx.WithGasAdjustment(adjustment) + if utils.HasDryRunArg(r) || m.Gas == 0 { newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { From 122ed3a900d41dcb7200bbf28e528bc3b35153f7 Mon Sep 17 00:00:00 2001 From: Alessio Treglia <quadrispro@ubuntu.com> Date: Fri, 31 Aug 2018 17:10:09 +0200 Subject: [PATCH 23/28] Don't use pointers when you need them not! --- client/utils/rest.go | 14 ++++---- x/auth/client/rest/query.go | 8 ++--- x/bank/client/rest/sendtx.go | 22 ++++++------- x/gov/client/rest/rest.go | 62 +++++++++++++++++------------------ x/gov/client/rest/util.go | 26 +++++++-------- x/ibc/client/rest/transfer.go | 20 +++++------ x/slashing/client/rest/tx.go | 22 ++++++------- x/stake/client/rest/tx.go | 50 ++++++++++++++-------------- 8 files changed, 112 insertions(+), 112 deletions(-) diff --git a/client/utils/rest.go b/client/utils/rest.go index b369a81274..25e1c23d85 100644 --- a/client/utils/rest.go +++ b/client/utils/rest.go @@ -12,16 +12,16 @@ const ( // WriteErrorResponse prepares and writes a HTTP error // given a status code and an error message. -func WriteErrorResponse(w *http.ResponseWriter, status int, msg string) { - (*w).WriteHeader(status) - (*w).Write([]byte(msg)) +func WriteErrorResponse(w http.ResponseWriter, status int, msg string) { + w.WriteHeader(status) + w.Write([]byte(msg)) } // WriteGasEstimateResponse prepares and writes an HTTP // response for transactions simulations. -func WriteSimulationResponse(w *http.ResponseWriter, gas int64) { - (*w).WriteHeader(http.StatusOK) - (*w).Write([]byte(fmt.Sprintf(`{"gas_estimate":%v}`, gas))) +func WriteSimulationResponse(w http.ResponseWriter, gas int64) { + w.WriteHeader(http.StatusOK) + w.Write([]byte(fmt.Sprintf(`{"gas_estimate":%v}`, gas))) } // HasDryRunArg returns true if the request's URL query contains @@ -32,7 +32,7 @@ func HasDryRunArg(r *http.Request) bool { // ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a default // value if the string is empty. Write -func ParseFloat64OrReturnBadRequest(w *http.ResponseWriter, s string, defaultIfEmpty float64) (n float64, ok bool) { +func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEmpty float64) (n float64, ok bool) { if len(s) == 0 { return defaultIfEmpty, true } diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 07b109d403..6ad50a14dd 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -33,13 +33,13 @@ func QueryAccountRequestHandlerFn( addr, err := sdk.AccAddressFromBech32(bech32addr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } res, err := cliCtx.QueryStore(auth.AddressStoreKey(addr), storeName) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("couldn't query account. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("couldn't query account. Error: %s", err.Error())) return } @@ -52,14 +52,14 @@ func QueryAccountRequestHandlerFn( // decode the value account, err := decoder(res) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("couldn't parse query result. Result: %s. Error: %s", res, err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("couldn't parse query result. Result: %s. Error: %s", res, err.Error())) return } // print out whole account output, err := cdc.MarshalJSON(account) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("couldn't marshall query result. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("couldn't marshall query result. Error: %s", err.Error())) return } diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index 41635d28a8..23506e0fec 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -51,32 +51,32 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo to, err := sdk.AccAddressFromBech32(bech32addr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } var m sendBody body, err := ioutil.ReadAll(r.Body) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } err = msgCdc.UnmarshalJSON(body, &m) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } info, err := kb.Get(m.LocalAccountName) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) return } // build message msg := client.BuildMsg(sdk.AccAddress(info.GetPubKey().Address()), to, m.Amount) if err != nil { // XXX rechecking same error ? - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } @@ -88,7 +88,7 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo Sequence: m.Sequence, } - adjustment, ok := utils.ParseFloat64OrReturnBadRequest(&w, m.GasAdjustment, cliclient.DefaultGasAdjustment) + adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, cliclient.DefaultGasAdjustment) if !ok { return } @@ -97,11 +97,11 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo if utils.HasDryRunArg(r) || m.Gas == 0 { newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } if utils.HasDryRunArg(r) { - utils.WriteSimulationResponse(&w, txCtx.Gas) + utils.WriteSimulationResponse(w, txCtx.Gas) return } txCtx = newCtx @@ -109,19 +109,19 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) return } res, err := cliCtx.BroadcastTx(txBytes) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } output, err := wire.MarshalJSONIndent(cdc, res) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index 5241a39141..8bf675b025 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -77,7 +77,7 @@ func postProposalHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.Hand msg := gov.NewMsgSubmitProposal(req.Title, req.Description, req.ProposalType, req.Proposer, req.InitialDeposit) err = msg.ValidateBasic() if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -92,7 +92,7 @@ func depositHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFu if len(strProposalID) == 0 { err := errors.New("proposalId required but not specified") - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -114,7 +114,7 @@ func depositHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFu msg := gov.NewMsgDeposit(req.Depositer, proposalID, req.Amount) err = msg.ValidateBasic() if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -129,7 +129,7 @@ func voteHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc if len(strProposalID) == 0 { err := errors.New("proposalId required but not specified") - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -151,7 +151,7 @@ func voteHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc msg := gov.NewMsgVote(req.Voter, proposalID, req.Option) err = msg.ValidateBasic() if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -166,7 +166,7 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { if len(strProposalID) == 0 { err := errors.New("proposalId required but not specified") - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -183,13 +183,13 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { bz, err := cdc.MarshalJSON(params) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } res, err := cliCtx.QueryWithData("custom/gov/proposal", bz) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } @@ -205,7 +205,7 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { if len(strProposalID) == 0 { err := errors.New("proposalId required but not specified") - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -216,14 +216,14 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { if len(bechDepositerAddr) == 0 { err := errors.New("depositer address required but not specified") - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } depositerAddr, err := sdk.AccAddressFromBech32(bechDepositerAddr) if err != nil { err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer) - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -236,13 +236,13 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { bz, err := cdc.MarshalJSON(params) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } res, err := cliCtx.QueryWithData("custom/gov/deposit", bz) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } @@ -252,11 +252,11 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc { res, err := cliCtx.QueryWithData("custom/gov/proposal", cdc.MustMarshalBinary(gov.QueryProposalParams{params.ProposalID})) if err != nil || len(res) == 0 { err := errors.Errorf("proposalID [%d] does not exist", proposalID) - utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error()) + utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) return } err = errors.Errorf("depositer [%s] did not deposit on proposalID [%d]", bechDepositerAddr, proposalID) - utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error()) + utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) return } @@ -272,7 +272,7 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { if len(strProposalID) == 0 { err := errors.New("proposalId required but not specified") - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -283,14 +283,14 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { if len(bechVoterAddr) == 0 { err := errors.New("voter address required but not specified") - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } voterAddr, err := sdk.AccAddressFromBech32(bechVoterAddr) if err != nil { err := errors.Errorf("'%s' needs to be bech32 encoded", RestVoter) - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -302,13 +302,13 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { } bz, err := cdc.MarshalJSON(params) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } res, err := cliCtx.QueryWithData("custom/gov/vote", bz) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } @@ -317,17 +317,17 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { if vote.Empty() { bz, err := cdc.MarshalJSON(gov.QueryProposalParams{params.ProposalID}) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } res, err := cliCtx.QueryWithData("custom/gov/proposal", bz) if err != nil || len(res) == 0 { err := errors.Errorf("proposalID [%d] does not exist", proposalID) - utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error()) + utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) return } err = errors.Errorf("voter [%s] did not deposit on proposalID [%d]", bechVoterAddr, proposalID) - utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error()) + utils.WriteErrorResponse(w, http.StatusNotFound, err.Error()) return } w.Write(res) @@ -343,7 +343,7 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { if len(strProposalID) == 0 { err := errors.New("proposalId required but not specified") - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -359,13 +359,13 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { } bz, err := cdc.MarshalJSON(params) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } res, err := cliCtx.QueryWithData("custom/gov/votes", bz) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } @@ -388,7 +388,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { voterAddr, err := sdk.AccAddressFromBech32(bechVoterAddr) if err != nil { err := errors.Errorf("'%s' needs to be bech32 encoded", RestVoter) - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } params.Voter = voterAddr @@ -398,7 +398,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { depositerAddr, err := sdk.AccAddressFromBech32(bechDepositerAddr) if err != nil { err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer) - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } params.Depositer = depositerAddr @@ -408,7 +408,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { proposalStatus, err := gov.ProposalStatusFromString(strProposalStatus) if err != nil { err := errors.Errorf("'%s' is not a valid Proposal Status", strProposalStatus) - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } params.ProposalStatus = proposalStatus @@ -423,7 +423,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { bz, err := cdc.MarshalJSON(params) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } @@ -431,7 +431,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { res, err := cliCtx.QueryWithData("custom/gov/proposals", bz) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } diff --git a/x/gov/client/rest/util.go b/x/gov/client/rest/util.go index f563b4ec20..a5fae3c3fa 100644 --- a/x/gov/client/rest/util.go +++ b/x/gov/client/rest/util.go @@ -27,12 +27,12 @@ type baseReq struct { func buildReq(w http.ResponseWriter, r *http.Request, cdc *wire.Codec, req interface{}) error { body, err := ioutil.ReadAll(r.Body) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return err } err = cdc.UnmarshalJSON(body, req) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return err } return nil @@ -40,27 +40,27 @@ func buildReq(w http.ResponseWriter, r *http.Request, cdc *wire.Codec, req inter func (req baseReq) baseReqValidate(w http.ResponseWriter) bool { if len(req.Name) == 0 { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Name required but not specified") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Name required but not specified") return false } if len(req.Password) == 0 { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Password required but not specified") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Password required but not specified") return false } if len(req.ChainID) == 0 { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "ChainID required but not specified") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "ChainID required but not specified") return false } if req.AccountNumber < 0 { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Account Number required but not specified") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Account Number required but not specified") return false } if req.Sequence < 0 { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Sequence required but not specified") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Sequence required but not specified") return false } return true @@ -78,7 +78,7 @@ func signAndBuild(w http.ResponseWriter, r *http.Request, cliCtx context.CLICont Gas: baseReq.Gas, } - adjustment, ok := utils.ParseFloat64OrReturnBadRequest(&w, baseReq.GasAdjustment, client.DefaultGasAdjustment) + adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment) if !ok { return } @@ -87,30 +87,30 @@ func signAndBuild(w http.ResponseWriter, r *http.Request, cliCtx context.CLICont if utils.HasDryRunArg(r) || baseReq.Gas == 0 { newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, baseReq.Name, []sdk.Msg{msg}) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } if utils.HasDryRunArg(r) { - utils.WriteSimulationResponse(&w, txCtx.Gas) + utils.WriteSimulationResponse(w, txCtx.Gas) return } txCtx = newCtx } txBytes, err := txCtx.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg}) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) return } res, err := cliCtx.BroadcastTx(txBytes) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } output, err := wire.MarshalJSONIndent(cdc, res) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go index 111f9086d0..0580ff4062 100644 --- a/x/ibc/client/rest/transfer.go +++ b/x/ibc/client/rest/transfer.go @@ -44,26 +44,26 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C to, err := sdk.AccAddressFromBech32(bech32addr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } var m transferBody body, err := ioutil.ReadAll(r.Body) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } err = cdc.UnmarshalJSON(body, &m) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } info, err := kb.Get(m.LocalAccountName) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) return } @@ -79,7 +79,7 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C Gas: m.Gas, } - adjustment, ok := utils.ParseFloat64OrReturnBadRequest(&w, m.GasAdjustment, client.DefaultGasAdjustment) + adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment) if !ok { return } @@ -88,11 +88,11 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C if utils.HasDryRunArg(r) || m.Gas == 0 { newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } if utils.HasDryRunArg(r) { - utils.WriteSimulationResponse(&w, txCtx.Gas) + utils.WriteSimulationResponse(w, txCtx.Gas) return } txCtx = newCtx @@ -100,19 +100,19 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) return } res, err := cliCtx.BroadcastTx(txBytes) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } output, err := cdc.MarshalJSON(res) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index 322a4aa083..faf0341ce5 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -44,29 +44,29 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI var m UnjailBody body, err := ioutil.ReadAll(r.Body) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } err = json.Unmarshal(body, &m) if err != nil { - utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error()) + utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } info, err := kb.Get(m.LocalAccountName) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) return } valAddr, err := sdk.ValAddressFromBech32(m.ValidatorAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } if !bytes.Equal(info.GetPubKey().Address(), valAddr) { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own validator address") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own validator address") return } @@ -80,7 +80,7 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI msg := slashing.NewMsgUnjail(valAddr) - adjustment, ok := utils.ParseFloat64OrReturnBadRequest(&w, m.GasAdjustment, client.DefaultGasAdjustment) + adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment) if !ok { return } @@ -89,11 +89,11 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI if utils.HasDryRunArg(r) || m.Gas == 0 { newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } if utils.HasDryRunArg(r) { - utils.WriteSimulationResponse(&w, txCtx.Gas) + utils.WriteSimulationResponse(w, txCtx.Gas) return } txCtx = newCtx @@ -101,19 +101,19 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own validator address") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own validator address") return } res, err := cliCtx.BroadcastTx(txBytes) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } output, err := json.MarshalIndent(res, "", " ") if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index 5e6226dcc7..9925b6b1ce 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -108,18 +108,18 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex for _, msg := range m.Delegations { delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) return } valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } if !bytes.Equal(info.GetPubKey().Address(), delAddr) { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") return } @@ -135,29 +135,29 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex for _, msg := range m.BeginRedelegates { delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } if !bytes.Equal(info.GetPubKey().Address(), delAddr) { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") return } valSrcAddr, err := sdk.ValAddressFromBech32(msg.ValidatorSrcAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } valDstAddr, err := sdk.ValAddressFromBech32(msg.ValidatorDstAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } shares, err := sdk.NewDecFromStr(msg.SharesAmount) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error())) return } @@ -174,24 +174,24 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex for _, msg := range m.CompleteRedelegates { delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) return } valSrcAddr, err := sdk.ValAddressFromBech32(msg.ValidatorSrcAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } valDstAddr, err := sdk.ValAddressFromBech32(msg.ValidatorDstAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } if !bytes.Equal(info.GetPubKey().Address(), delAddr) { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") return } @@ -207,24 +207,24 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex for _, msg := range m.BeginUnbondings { delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) return } if !bytes.Equal(info.GetPubKey().Address(), delAddr) { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") return } valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } shares, err := sdk.NewDecFromStr(msg.SharesAmount) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error())) return } @@ -240,18 +240,18 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex for _, msg := range m.CompleteUnbondings { delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())) return } valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) + utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())) return } if !bytes.Equal(info.GetPubKey().Address(), delAddr) { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address") + utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address") return } @@ -278,7 +278,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex m.Sequence++ - adjustment, ok := utils.ParseFloat64OrReturnBadRequest(&w, m.GasAdjustment, client.DefaultGasAdjustment) + adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment) if !ok { return } @@ -287,11 +287,11 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex if utils.HasDryRunArg(r) || m.Gas == 0 { newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg}) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } if utils.HasDryRunArg(r) { - utils.WriteSimulationResponse(&w, txCtx.Gas) + utils.WriteSimulationResponse(w, txCtx.Gas) return } txCtx = newCtx @@ -299,7 +299,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error()) return } @@ -313,7 +313,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex for i, txBytes := range signedTxs { res, err := cliCtx.BroadcastTx(txBytes) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } @@ -322,7 +322,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex output, err := wire.MarshalJSONIndent(cdc, results[:]) if err != nil { - utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error()) + utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } From 1ed76565f2d1e1667011de6f6453836ea13383d0 Mon Sep 17 00:00:00 2001 From: Alessio Treglia <quadrispro@ubuntu.com> Date: Fri, 31 Aug 2018 17:13:24 +0200 Subject: [PATCH 24/28] Remove obsolete comments --- x/auth/ante.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/x/auth/ante.go b/x/auth/ante.go index 94899a8726..51440e2ece 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -175,14 +175,11 @@ func processSig( fmt.Sprintf("Invalid sequence. Got %d, expected %d", sig.Sequence, seq)).Result() } } - // Increment sequence number err := acc.SetSequence(seq + 1) if err != nil { // Handle w/ #870 panic(err) } - // If pubkey is not known for account, - // set it from the StdSignature. pubKey, res := processPubKey(acc, sig, simulate) if !res.IsOK() { return nil, res From d84885ca49e557fac2964fb7eae6d6a049656e51 Mon Sep 17 00:00:00 2001 From: Alessio Treglia <quadrispro@ubuntu.com> Date: Fri, 31 Aug 2018 17:47:20 +0200 Subject: [PATCH 25/28] No need to create a fake slice of signatures nor skip account no./sequence check --- client/context/context.go | 2 ++ x/auth/ante.go | 25 +++++++++---------------- x/bank/app_test.go | 2 +- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index 2444c56d13..8e56cfa1ae 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -159,6 +159,8 @@ func (ctx CLIContext) WithUseLedger(useLedger bool) CLIContext { // WithCertifier - return a copy of the context with an updated Certifier func (ctx CLIContext) WithCertifier(certifier tmlite.Certifier) CLIContext { ctx.Certifier = certifier + return ctx +} // WithGasAdjustment returns a copy of the context with an updated GasAdjustment flag. func (ctx CLIContext) WithGasAdjustment(adjustment float64) CLIContext { diff --git a/x/auth/ante.go b/x/auth/ante.go index 51440e2ece..65071e69a7 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -68,9 +68,6 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler { sigs := stdTx.GetSignatures() // When simulating, this would just be a 0-length slice. signerAddrs := stdTx.GetSigners() msgs := tx.GetMsgs() - if simulate { - sigs = make([]StdSignature, len(signerAddrs)) - } // charge gas for the memo newCtx.GasMeter().ConsumeGas(memoCostPerByte*sdk.Gas(len(stdTx.GetMemo())), "memo") @@ -160,20 +157,16 @@ func processSig( accnum := acc.GetAccountNumber() seq := acc.GetSequence() - // Perform checks that wouldn't pass successfully in simulation, i.e. sig - // would be empty as simulated transactions come with no signatures whatsoever. - if !simulate { - // Check account number. - if accnum != sig.AccountNumber { - return nil, sdk.ErrInvalidSequence( - fmt.Sprintf("Invalid account number. Got %d, expected %d", sig.AccountNumber, accnum)).Result() - } + // Check account number. + if accnum != sig.AccountNumber { + return nil, sdk.ErrInvalidSequence( + fmt.Sprintf("Invalid account number. Got %d, expected %d", sig.AccountNumber, accnum)).Result() + } - // Check sequence number. - if seq != sig.Sequence { - return nil, sdk.ErrInvalidSequence( - fmt.Sprintf("Invalid sequence. Got %d, expected %d", sig.Sequence, seq)).Result() - } + // Check sequence number. + if seq != sig.Sequence { + return nil, sdk.ErrInvalidSequence( + fmt.Sprintf("Invalid sequence. Got %d, expected %d", sig.Sequence, seq)).Result() } err := acc.SetSequence(seq + 1) if err != nil { diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 7ef344ffcd..77991f94b7 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -123,7 +123,7 @@ func TestMsgSendWithAccounts(t *testing.T) { msgs: []sdk.Msg{sendMsg1, sendMsg2}, accNums: []int64{0}, accSeqs: []int64{0}, - expSimPass: true, + expSimPass: false, expPass: false, privKeys: []crypto.PrivKey{priv1}, }, From b92ac313acce45c0c60cfe319f774a4a50f05b02 Mon Sep 17 00:00:00 2001 From: Rigel <rigel.rozanski@gmail.com> Date: Fri, 31 Aug 2018 15:21:12 -0400 Subject: [PATCH 26/28] Merg PR #2198: Ensure Legacy Validator Delegation Invariants * Test and allow jailed validator to self-bond * Implement TestJailedValidatorDelegations * Restructure TestJailedValidatorDelegations * Add Delegation to Validator type and update handleMsgUnjail accordingly * Update ErrMissingSelfDelegation error message * Update democoin mock validator set impl * Update pending log * Add comment to ValidatorSet * Fix conflicts/errors due to develop merge --- PENDING.md | 1 + examples/democoin/mock/validator.go | 5 ++ types/stake.go | 4 ++ x/slashing/errors.go | 14 ++++- x/slashing/handler.go | 15 +++-- x/slashing/handler_test.go | 60 +++++++++++++++++++ x/slashing/test_common.go | 11 +++- x/stake/handler.go | 8 ++- x/stake/handler_test.go | 91 +++++++++++++++++++++++++++++ x/stake/keeper/delegation.go | 3 +- x/stake/keeper/sdk_types.go | 1 + 11 files changed, 200 insertions(+), 13 deletions(-) diff --git a/PENDING.md b/PENDING.md index 832f25e8f4..3843be5fd5 100644 --- a/PENDING.md +++ b/PENDING.md @@ -73,6 +73,7 @@ IMPROVEMENTS * Gaia * [x/stake] [#2023](https://github.com/cosmos/cosmos-sdk/pull/2023) Terminate iteration loop in `UpdateBondedValidators` and `UpdateBondedValidatorsFull` when the first revoked validator is encountered and perform a sanity check. * [x/auth] Signature verification's gas cost now accounts for pubkey type. [#2046](https://github.com/tendermint/tendermint/pull/2046) + * [x/stake] [x/slashing] Ensure delegation invariants to jailed validators [#1883](https://github.com/cosmos/cosmos-sdk/issues/1883). * SDK * [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present. diff --git a/examples/democoin/mock/validator.go b/examples/democoin/mock/validator.go index f937e45dcc..9f84786adf 100644 --- a/examples/democoin/mock/validator.go +++ b/examples/democoin/mock/validator.go @@ -135,3 +135,8 @@ func (vs *ValidatorSet) Jail(ctx sdk.Context, pubkey crypto.PubKey) { func (vs *ValidatorSet) Unjail(ctx sdk.Context, pubkey crypto.PubKey) { panic("not implemented") } + +// Implements sdk.ValidatorSet +func (vs *ValidatorSet) Delegation(ctx sdk.Context, addrDel sdk.AccAddress, addrVal sdk.ValAddress) sdk.Delegation { + panic("not implemented") +} diff --git a/types/stake.go b/types/stake.go index f411251775..978398fa51 100644 --- a/types/stake.go +++ b/types/stake.go @@ -75,6 +75,10 @@ type ValidatorSet interface { Slash(Context, crypto.PubKey, int64, int64, Dec) Jail(Context, crypto.PubKey) // jail a validator Unjail(Context, crypto.PubKey) // unjail a validator + + // Delegation allows for getting a particular delegation for a given validator + // and delegator outside the scope of the staking module. + Delegation(Context, AccAddress, ValAddress) Delegation } //_______________________________________________________________________________ diff --git a/x/slashing/errors.go b/x/slashing/errors.go index 4573d5e145..77cb2d28e3 100644 --- a/x/slashing/errors.go +++ b/x/slashing/errors.go @@ -12,20 +12,28 @@ const ( // Default slashing codespace DefaultCodespace sdk.CodespaceType = 10 - CodeInvalidValidator CodeType = 101 - CodeValidatorJailed CodeType = 102 - CodeValidatorNotJailed CodeType = 103 + CodeInvalidValidator CodeType = 101 + CodeValidatorJailed CodeType = 102 + CodeValidatorNotJailed CodeType = 103 + CodeMissingSelfDelegation CodeType = 104 ) func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "that address is not associated with any known validator") } + func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address") } + func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeValidatorJailed, "validator still jailed, cannot yet be unjailed") } + func ErrValidatorNotJailed(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeValidatorNotJailed, "validator not jailed, cannot be unjailed") } + +func ErrMissingSelfDelegation(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeMissingSelfDelegation, "validator has no self-delegation; cannot be unjailed") +} diff --git a/x/slashing/handler.go b/x/slashing/handler.go index d79ea73c2d..c18587955b 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -19,35 +19,38 @@ func NewHandler(k Keeper) sdk.Handler { // Validators must submit a transaction to unjail itself after // having been jailed (and thus unbonded) for downtime func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result { - - // Validator must exist validator := k.validatorSet.Validator(ctx, msg.ValidatorAddr) if validator == nil { return ErrNoValidatorForAddress(k.codespace).Result() } + // cannot be unjailed if no self-delegation exists + selfDel := k.validatorSet.Delegation(ctx, sdk.AccAddress(msg.ValidatorAddr), msg.ValidatorAddr) + if selfDel == nil { + return ErrMissingSelfDelegation(k.codespace).Result() + } + if !validator.GetJailed() { return ErrValidatorNotJailed(k.codespace).Result() } addr := sdk.ValAddress(validator.GetPubKey().Address()) - // Signing info must exist info, found := k.getValidatorSigningInfo(ctx, addr) if !found { return ErrNoValidatorForAddress(k.codespace).Result() } - // Cannot be unjailed until out of jail + // cannot be unjailed until out of jail if ctx.BlockHeader().Time.Before(info.JailedUntil) { return ErrValidatorJailed(k.codespace).Result() } - // Update the starting height (so the validator can't be immediately jailed again) + // update the starting height so the validator can't be immediately jailed + // again info.StartHeight = ctx.BlockHeight() k.setValidatorSigningInfo(ctx, addr, info) - // Unjail the validator k.validatorSet.Unjail(ctx, validator.GetPubKey()) tags := sdk.NewTags("action", []byte("unjail"), "validator", []byte(msg.ValidatorAddr.String())) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 8e3b719f49..8c522215a2 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -2,6 +2,7 @@ package slashing import ( "testing" + "time" "github.com/stretchr/testify/require" @@ -27,3 +28,62 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { require.False(t, got.IsOK(), "allowed unjail of non-jailed validator") require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotJailed), got.Code) } + +func TestJailedValidatorDelegations(t *testing.T) { + ctx, _, stakeKeeper, _, slashingKeeper := createTestInput(t) + + stakeParams := stakeKeeper.GetParams(ctx) + stakeParams.UnbondingTime = 0 + stakeKeeper.SetParams(ctx, stakeParams) + + // create a validator + amount := int64(10) + valAddr, valPubKey, bondAmount := sdk.ValAddress(addrs[0]), pks[0], sdk.NewInt(amount) + msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount) + got := stake.NewHandler(stakeKeeper)(ctx, msgCreateVal) + require.True(t, got.IsOK(), "expected create validator msg to be ok, got: %v", got) + + // set dummy signing info + newInfo := ValidatorSigningInfo{ + StartHeight: int64(0), + IndexOffset: int64(0), + JailedUntil: time.Unix(0, 0), + SignedBlocksCounter: int64(0), + } + slashingKeeper.setValidatorSigningInfo(ctx, valAddr, newInfo) + + // delegate tokens to the validator + delAddr := addrs[1] + msgDelegate := newTestMsgDelegate(delAddr, valAddr, bondAmount) + got = stake.NewHandler(stakeKeeper)(ctx, msgDelegate) + require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + + unbondShares := sdk.NewDec(10) + + // unbond validator total self-delegations (which should jail the validator) + msgBeginUnbonding := stake.NewMsgBeginUnbonding(sdk.AccAddress(valAddr), valAddr, unbondShares) + got = stake.NewHandler(stakeKeeper)(ctx, msgBeginUnbonding) + require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got: %v", got) + + msgCompleteUnbonding := stake.NewMsgCompleteUnbonding(sdk.AccAddress(valAddr), valAddr) + got = stake.NewHandler(stakeKeeper)(ctx, msgCompleteUnbonding) + require.True(t, got.IsOK(), "expected complete unbonding validator msg to be ok, got: %v", got) + + // verify validator still exists and is jailed + validator, found := stakeKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.True(t, validator.GetJailed()) + + // verify the validator cannot unjail itself + got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) + require.False(t, got.IsOK(), "expected jailed validator to not be able to unjail, got: %v", got) + + // self-delegate to validator + msgSelfDelegate := newTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) + got = stake.NewHandler(stakeKeeper)(ctx, msgSelfDelegate) + require.True(t, got.IsOK(), "expected delegation to not be ok, got %v", got) + + // verify the validator can now unjail itself + got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) + require.True(t, got.IsOK(), "expected jailed validator to be able to unjail, got: %v", got) +} diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 1053823786..6974113100 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "os" "testing" + "time" "github.com/stretchr/testify/require" @@ -61,7 +62,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) err := ms.LoadLatestVersion() require.Nil(t, err) - ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewTMLogger(os.Stdout)) + ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout)) cdc := createTestCodec() accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount) ck := bank.NewKeeper(accountMapper) @@ -108,3 +109,11 @@ func newTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt Delegation: sdk.Coin{"steak", amt}, } } + +func newTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, delAmount sdk.Int) stake.MsgDelegate { + return stake.MsgDelegate{ + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, + Delegation: sdk.Coin{"steak", delAmount}, + } +} diff --git a/x/stake/handler.go b/x/stake/handler.go index c8be6a835a..4b478fffd7 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -1,6 +1,7 @@ package stake import ( + "bytes" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -128,17 +129,19 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe } func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) sdk.Result { - validator, found := k.GetValidator(ctx, msg.ValidatorAddr) if !found { return ErrNoValidatorFound(k.Codespace()).Result() } + if msg.Delegation.Denom != k.GetParams(ctx).BondDenom { return ErrBadDenom(k.Codespace()).Result() } - if validator.Jailed { + + if validator.Jailed && !bytes.Equal(validator.Operator, msg.DelegatorAddr) { return ErrValidatorJailed(k.Codespace()).Result() } + _, err := k.Delegate(ctx, msg.DelegatorAddr, msg.Delegation, validator, true) if err != nil { return err.Result() @@ -149,6 +152,7 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) tags.Delegator, []byte(msg.DelegatorAddr.String()), tags.DstValidator, []byte(msg.ValidatorAddr.String()), ) + return sdk.Result{ Tags: tags, } diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index f7d01bcfc7..2006745d89 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -193,6 +193,97 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { require.False(t, got.IsOK(), "%v", got) } +func TestLegacyValidatorDelegations(t *testing.T) { + ctx, _, keeper := keep.CreateTestInput(t, false, int64(1000)) + setInstantUnbondPeriod(keeper, ctx) + + bondAmount := int64(10) + valAddr, valPubKey := sdk.ValAddress(keep.Addrs[0]), keep.PKs[0] + delAddr := keep.Addrs[1] + + // create validator + msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount) + got := handleMsgCreateValidator(ctx, msgCreateVal, keeper) + require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) + + // verify the validator exists and has the correct attributes + validator, found := keeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, sdk.Bonded, validator.Status) + require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt64()) + require.Equal(t, bondAmount, validator.BondedTokens().RoundInt64()) + + // delegate tokens to the validator + msgDelegate := newTestMsgDelegate(delAddr, valAddr, bondAmount) + got = handleMsgDelegate(ctx, msgDelegate, keeper) + require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + + // verify validator bonded shares + validator, found = keeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, bondAmount*2, validator.DelegatorShares.RoundInt64()) + require.Equal(t, bondAmount*2, validator.BondedTokens().RoundInt64()) + + // unbond validator total self-delegations (which should jail the validator) + unbondShares := sdk.NewDec(10) + msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(valAddr), valAddr, unbondShares) + msgCompleteUnbonding := NewMsgCompleteUnbonding(sdk.AccAddress(valAddr), valAddr) + + got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) + require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got %v", got) + + got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper) + require.True(t, got.IsOK(), "expected complete unbonding validator msg to be ok, got %v", got) + + // verify the validator record still exists, is jailed, and has correct tokens + validator, found = keeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.True(t, validator.Jailed) + require.Equal(t, sdk.NewDec(10), validator.Tokens) + + // verify delegation still exists + bond, found := keeper.GetDelegation(ctx, delAddr, valAddr) + require.True(t, found) + require.Equal(t, bondAmount, bond.Shares.RoundInt64()) + require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt64()) + + // verify a delegator cannot create a new delegation to the now jailed validator + msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount) + got = handleMsgDelegate(ctx, msgDelegate, keeper) + require.False(t, got.IsOK(), "expected delegation to not be ok, got %v", got) + + // verify the validator can still self-delegate + msgSelfDelegate := newTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) + got = handleMsgDelegate(ctx, msgSelfDelegate, keeper) + require.True(t, got.IsOK(), "expected delegation to not be ok, got %v", got) + + // verify validator bonded shares + validator, found = keeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, bondAmount*2, validator.DelegatorShares.RoundInt64()) + require.Equal(t, bondAmount*2, validator.Tokens.RoundInt64()) + + // unjail the validator now that is has non-zero self-delegated shares + keeper.Unjail(ctx, valPubKey) + + // verify the validator can now accept delegations + msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount) + got = handleMsgDelegate(ctx, msgDelegate, keeper) + require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + + // verify validator bonded shares + validator, found = keeper.GetValidator(ctx, valAddr) + require.True(t, found) + require.Equal(t, bondAmount*3, validator.DelegatorShares.RoundInt64()) + require.Equal(t, bondAmount*3, validator.Tokens.RoundInt64()) + + // verify new delegation + bond, found = keeper.GetDelegation(ctx, delAddr, valAddr) + require.True(t, found) + require.Equal(t, bondAmount*2, bond.Shares.RoundInt64()) + require.Equal(t, bondAmount*3, validator.DelegatorShares.RoundInt64()) +} + func TestIncrementsMsgDelegate(t *testing.T) { initBond := int64(1000) ctx, accMapper, keeper := keep.CreateTestInput(t, false, initBond) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 9f7a402fc2..2c997b4633 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -288,6 +288,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA if bytes.Equal(delegation.DelegatorAddr, validator.Operator) && validator.Jailed == false { validator.Jailed = true } + k.RemoveDelegation(ctx, delegation) } else { // Update height @@ -307,7 +308,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA k.RemoveValidator(ctx, validator.Operator) } - return + return amount, nil } //______________________________________________________________________________________________________ diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index 480df701b1..e4c7a1c193 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -91,6 +91,7 @@ func (k Keeper) Delegation(ctx sdk.Context, addrDel sdk.AccAddress, addrVal sdk. if !ok { return nil } + return bond } From 12048576940ae9f9273650b463655c11f0f54528 Mon Sep 17 00:00:00 2001 From: Christopher Goes <cwgoes@pluranimity.org> Date: Sat, 1 Sep 2018 02:01:23 +0200 Subject: [PATCH 27/28] Merge PR #2122: Implement slashing period * Update PENDING.md * SlashingPeriod struct * Seperate keys.go, constant prefixes * Make linter happy * Update Gopkg.lock * Seek slashing period by infraction height * Slashing period hooks * Slashing period unit tests; bugfix * Add simple hook tests * Add sdk.ValidatorHooks interface * No-op hooks * Real hooks * Fix iteration direction & duplicate key, update Gaia * Correctly simulate past validator set signatures * Tiny rename * Update dep; 'make format' * Add quick slashing period functionality test * Additional unit tests * Use current validators when selected * Panic in the right place * Address @rigelrozanski comments * Fix linter errors * Address @melekes suggestion * Rename hook * Update for new bech32 types * 'make format' --- PENDING.md | 1 + cmd/gaia/app/app.go | 3 +- server/tm_cmds.go | 2 +- types/decimal.go | 8 ++ types/stake.go | 10 ++ x/mock/simulation/random_simulate_blocks.go | 54 +++++----- x/slashing/app_test.go | 4 +- x/slashing/client/cli/query.go | 2 +- x/slashing/client/rest/query.go | 2 +- x/slashing/handler.go | 2 +- x/slashing/handler_test.go | 2 +- x/slashing/hooks.go | 46 +++++++++ x/slashing/hooks_test.go | 26 +++++ x/slashing/keeper.go | 16 +-- x/slashing/keeper_test.go | 75 ++++++++++++-- x/slashing/keys.go | 43 ++++++++ x/slashing/signing_info.go | 21 +--- x/slashing/signing_info_test.go | 12 +-- x/slashing/slashing_period.go | 107 ++++++++++++++++++++ x/slashing/slashing_period_test.go | 86 ++++++++++++++++ x/slashing/test_common.go | 10 +- x/slashing/tick_test.go | 4 +- x/stake/keeper/keeper.go | 25 +++-- x/stake/keeper/validator.go | 13 +++ x/stake/types/validator.go | 5 + 25 files changed, 494 insertions(+), 85 deletions(-) create mode 100644 x/slashing/hooks.go create mode 100644 x/slashing/hooks_test.go create mode 100644 x/slashing/keys.go create mode 100644 x/slashing/slashing_period.go create mode 100644 x/slashing/slashing_period_test.go diff --git a/PENDING.md b/PENDING.md index 32f1face82..17f9b2a458 100644 --- a/PENDING.md +++ b/PENDING.md @@ -30,6 +30,7 @@ BREAKING CHANGES * SDK * [core] \#1807 Switch from use of rational to decimal * [types] \#1901 Validator interface's GetOwner() renamed to GetOperator() + * [x/slashing] [#2122](https://github.com/cosmos/cosmos-sdk/pull/2122) - Implement slashing period * [types] \#2119 Parsed error messages and ABCI log errors to make them more human readable. * [simulation] Rename TestAndRunTx to Operation [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 4ce6b2806d..f1ca2a7b66 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -93,9 +93,10 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace)) app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams) 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.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace)) + app.stakeKeeper = app.stakeKeeper.WithValidatorHooks(app.slashingKeeper.ValidatorHooks()) app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper.Setter(), app.coinKeeper, app.stakeKeeper, app.RegisterCodespace(gov.DefaultCodespace)) app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(app.cdc, app.keyFeeCollection) - app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace)) // register message routes app.Router(). diff --git a/server/tm_cmds.go b/server/tm_cmds.go index b6daf07753..bf208a5bec 100644 --- a/server/tm_cmds.go +++ b/server/tm_cmds.go @@ -7,11 +7,11 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" "github.com/tendermint/tendermint/p2p" pvm "github.com/tendermint/tendermint/privval" - "github.com/cosmos/cosmos-sdk/client" ) // ShowNodeIDCmd - ported from Tendermint, dump node ID to stdout diff --git a/types/decimal.go b/types/decimal.go index baf2d9573d..8e7db1340b 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -415,6 +415,14 @@ func MinDec(d1, d2 Dec) Dec { return d2 } +// maximum decimal between two +func MaxDec(d1, d2 Dec) Dec { + if d1.LT(d2) { + return d2 + } + return d1 +} + // intended to be used with require/assert: require.True(DecEq(...)) func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) { return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got diff --git a/types/stake.go b/types/stake.go index 978398fa51..ba11cd5f86 100644 --- a/types/stake.go +++ b/types/stake.go @@ -99,3 +99,13 @@ type DelegationSet interface { IterateDelegations(ctx Context, delegator AccAddress, fn func(index int64, delegation Delegation) (stop bool)) } + +// validator event hooks +// These can be utilized to communicate between a staking keeper +// and another keeper which must take particular actions when +// validators are bonded and unbonded. The second keeper must implement +// this interface, which then the staking keeper can call. +type ValidatorHooks interface { + OnValidatorBonded(ctx Context, address ConsAddress) // Must be called when a validator is bonded + OnValidatorBeginUnbonding(ctx Context, address ConsAddress) // Must be called when a validator begins unbonding +} diff --git a/x/mock/simulation/random_simulate_blocks.go b/x/mock/simulation/random_simulate_blocks.go index 995013ef8f..a99b3a4c97 100644 --- a/x/mock/simulation/random_simulate_blocks.go +++ b/x/mock/simulation/random_simulate_blocks.go @@ -67,9 +67,10 @@ func SimulateFromSeed( header := abci.Header{Height: 0, Time: timestamp} opCount := 0 - request := abci.RequestBeginBlock{Header: header} - var pastTimes []time.Time + var pastSigningValidators [][]abci.SigningValidator + + request := RandomRequestBeginBlock(t, r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header, log) // These are operations which have been queued by previous operations operationQueue := make(map[int][]Operation) @@ -77,6 +78,7 @@ func SimulateFromSeed( // Log the header time for future lookup pastTimes = append(pastTimes, header.Time) + pastSigningValidators = append(pastSigningValidators, request.LastCommitInfo.Validators) // Run the BeginBlock handler app.BeginBlock(request) @@ -131,7 +133,7 @@ func SimulateFromSeed( } // Generate a random RequestBeginBlock with the current validator set for the next block - request = RandomRequestBeginBlock(t, r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, event, header, log) + request = RandomRequestBeginBlock(t, r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header, log) // Update the validator set validators = updateValidators(t, r, validators, res.ValidatorUpdates, event) @@ -187,13 +189,12 @@ func getKeys(validators map[string]mockValidator) []string { // RandomRequestBeginBlock generates a list of signing validators according to the provided list of validators, signing fraction, and evidence fraction func RandomRequestBeginBlock(t *testing.T, r *rand.Rand, validators map[string]mockValidator, livenessTransitions TransitionMatrix, evidenceFraction float64, - pastTimes []time.Time, event func(string), header abci.Header, log string) abci.RequestBeginBlock { + pastTimes []time.Time, pastSigningValidators [][]abci.SigningValidator, event func(string), header abci.Header, log string) abci.RequestBeginBlock { if len(validators) == 0 { return abci.RequestBeginBlock{Header: header} } signingValidators := make([]abci.SigningValidator, len(validators)) i := 0 - for _, key := range getKeys(validators) { mVal := validators[key] mVal.livenessState = livenessTransitions.NextState(r, mVal.livenessState) @@ -220,26 +221,31 @@ func RandomRequestBeginBlock(t *testing.T, r *rand.Rand, validators map[string]m i++ } evidence := make([]abci.Evidence, 0) - for r.Float64() < evidenceFraction { - height := header.Height - time := header.Time - if r.Float64() < pastEvidenceFraction { - height = int64(r.Intn(int(header.Height))) - time = pastTimes[height] + // Anything but the first block + if len(pastTimes) > 0 { + for r.Float64() < evidenceFraction { + height := header.Height + time := header.Time + vals := signingValidators + if r.Float64() < pastEvidenceFraction { + height = int64(r.Intn(int(header.Height))) + time = pastTimes[height] + vals = pastSigningValidators[height] + } + validator := vals[r.Intn(len(vals))].Validator + var totalVotingPower int64 + for _, val := range vals { + totalVotingPower += val.Validator.Power + } + evidence = append(evidence, abci.Evidence{ + Type: tmtypes.ABCIEvidenceTypeDuplicateVote, + Validator: validator, + Height: height, + Time: time, + TotalVotingPower: totalVotingPower, + }) + event("beginblock/evidence") } - validator := signingValidators[r.Intn(len(signingValidators))].Validator - var currentTotalVotingPower int64 - for _, mVal := range validators { - currentTotalVotingPower += mVal.val.Power - } - evidence = append(evidence, abci.Evidence{ - Type: tmtypes.ABCIEvidenceTypeDuplicateVote, - Validator: validator, - Height: height, - Time: time, - TotalVotingPower: currentTotalVotingPower, - }) - event("beginblock/evidence") } return abci.RequestBeginBlock{ Header: header, diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 671c2241e8..96dd1ff871 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -79,7 +79,7 @@ func checkValidator(t *testing.T, mapp *mock.App, keeper stake.Keeper, } func checkValidatorSigningInfo(t *testing.T, mapp *mock.App, keeper Keeper, - addr sdk.ValAddress, expFound bool) ValidatorSigningInfo { + addr sdk.ConsAddress, expFound bool) ValidatorSigningInfo { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) signingInfo, found := keeper.getValidatorSigningInfo(ctxCheck, addr) require.Equal(t, expFound, found) @@ -113,7 +113,7 @@ func TestSlashingMsgs(t *testing.T) { unjailMsg := MsgUnjail{ValidatorAddr: sdk.ValAddress(validator.PubKey.Address())} // no signing info yet - checkValidatorSigningInfo(t, mapp, keeper, sdk.ValAddress(addr1), false) + checkValidatorSigningInfo(t, mapp, keeper, sdk.ConsAddress(addr1), false) // unjail should fail with unknown validator res := mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{unjailMsg}, []int64{0}, []int64{1}, false, false, priv1) diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 9f6d834dda..87d0ad41d3 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -25,7 +25,7 @@ func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command { return err } - key := slashing.GetValidatorSigningInfoKey(sdk.ValAddress(pk.Address())) + key := slashing.GetValidatorSigningInfoKey(sdk.ConsAddress(pk.Address())) cliCtx := context.NewCLIContext().WithCodec(cdc) res, err := cliCtx.QueryStore(key, storeName) diff --git a/x/slashing/client/rest/query.go b/x/slashing/client/rest/query.go index 291679375b..78c4a2d2f8 100644 --- a/x/slashing/client/rest/query.go +++ b/x/slashing/client/rest/query.go @@ -30,7 +30,7 @@ func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *wire return } - key := slashing.GetValidatorSigningInfoKey(sdk.ValAddress(pk.Address())) + key := slashing.GetValidatorSigningInfoKey(sdk.ConsAddress(pk.Address())) res, err := cliCtx.QueryStore(key, storeName) if err != nil { diff --git a/x/slashing/handler.go b/x/slashing/handler.go index c18587955b..c43ed6be61 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -34,7 +34,7 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result { return ErrValidatorNotJailed(k.codespace).Result() } - addr := sdk.ValAddress(validator.GetPubKey().Address()) + addr := sdk.ConsAddress(validator.GetPubKey().Address()) info, found := k.getValidatorSigningInfo(ctx, addr) if !found { diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 8c522215a2..2ba8dcc4db 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -20,7 +20,7 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { got := stake.NewHandler(sk)(ctx, msg) require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) - require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) + require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower())) // assert non-jailed validator can't be unjailed diff --git a/x/slashing/hooks.go b/x/slashing/hooks.go new file mode 100644 index 0000000000..f5f3cc48c3 --- /dev/null +++ b/x/slashing/hooks.go @@ -0,0 +1,46 @@ +package slashing + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Create a new slashing period when a validator is bonded +func (k Keeper) onValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) { + slashingPeriod := ValidatorSlashingPeriod{ + ValidatorAddr: address, + StartHeight: ctx.BlockHeight(), + EndHeight: 0, + SlashedSoFar: sdk.ZeroDec(), + } + k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) +} + +// Mark the slashing period as having ended when a validator begins unbonding +func (k Keeper) onValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) { + slashingPeriod := k.getValidatorSlashingPeriodForHeight(ctx, address, ctx.BlockHeight()) + slashingPeriod.EndHeight = ctx.BlockHeight() + k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) +} + +// Wrapper struct for sdk.ValidatorHooks +type ValidatorHooks struct { + k Keeper +} + +// Assert implementation +var _ sdk.ValidatorHooks = ValidatorHooks{} + +// Return a sdk.ValidatorHooks interface over the wrapper struct +func (k Keeper) ValidatorHooks() sdk.ValidatorHooks { + return ValidatorHooks{k} +} + +// Implements sdk.ValidatorHooks +func (v ValidatorHooks) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) { + v.k.onValidatorBonded(ctx, address) +} + +// Implements sdk.ValidatorHooks +func (v ValidatorHooks) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) { + v.k.onValidatorBeginUnbonding(ctx, address) +} diff --git a/x/slashing/hooks_test.go b/x/slashing/hooks_test.go new file mode 100644 index 0000000000..0731fd8f26 --- /dev/null +++ b/x/slashing/hooks_test.go @@ -0,0 +1,26 @@ +package slashing + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestHookOnValidatorBonded(t *testing.T) { + ctx, _, _, _, keeper := createTestInput(t) + addr := sdk.ConsAddress(addrs[0]) + keeper.onValidatorBonded(ctx, addr) + period := keeper.getValidatorSlashingPeriodForHeight(ctx, addr, ctx.BlockHeight()) + require.Equal(t, ValidatorSlashingPeriod{addr, ctx.BlockHeight(), 0, sdk.ZeroDec()}, period) +} + +func TestHookOnValidatorBeginUnbonding(t *testing.T) { + ctx, _, _, _, keeper := createTestInput(t) + addr := sdk.ConsAddress(addrs[0]) + keeper.onValidatorBonded(ctx, addr) + keeper.onValidatorBeginUnbonding(ctx, addr) + period := keeper.getValidatorSlashingPeriodForHeight(ctx, addr, ctx.BlockHeight()) + require.Equal(t, ValidatorSlashingPeriod{addr, ctx.BlockHeight(), ctx.BlockHeight(), sdk.ZeroDec()}, period) +} diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 6d8e47cbe2..2725165857 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -40,7 +40,7 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio logger := ctx.Logger().With("module", "x/slashing") time := ctx.BlockHeader().Time age := time.Sub(timestamp) - address := sdk.ValAddress(addr) + address := sdk.ConsAddress(addr) pubkey, err := k.getPubkey(ctx, addr) if err != nil { panic(fmt.Sprintf("Validator address %v not found", addr)) @@ -56,8 +56,14 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio // 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(), infractionHeight, age, maxEvidenceAge)) + // Cap the amount slashed to the penalty for the worst infraction + // within the slashing period when this infraction was committed + fraction := k.SlashFractionDoubleSign(ctx) + revisedFraction := k.capBySlashingPeriod(ctx, address, fraction, infractionHeight) + logger.Info(fmt.Sprintf("Fraction slashed capped by slashing period from %v to %v", fraction, revisedFraction)) + // Slash validator - k.validatorSet.Slash(ctx, pubkey, infractionHeight, power, k.SlashFractionDoubleSign(ctx)) + k.validatorSet.Slash(ctx, pubkey, infractionHeight, power, revisedFraction) // Jail validator k.validatorSet.Jail(ctx, pubkey) @@ -76,7 +82,7 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, power int64, signed bool) { logger := ctx.Logger().With("module", "x/slashing") height := ctx.BlockHeight() - address := sdk.ValAddress(addr) + address := sdk.ConsAddress(addr) pubkey, err := k.getPubkey(ctx, addr) if err != nil { panic(fmt.Sprintf("Validator address %v not found", addr)) @@ -169,7 +175,3 @@ func (k Keeper) deleteAddrPubkeyRelation(ctx sdk.Context, addr crypto.Address) { store := ctx.KVStore(k.storeKey) store.Delete(getAddrPubkeyRelationKey(addr)) } - -func getAddrPubkeyRelationKey(address []byte) []byte { - return append([]byte{0x03}, address...) -} diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 3bdb043a82..af15bc2b28 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -24,13 +24,14 @@ func TestHandleDoubleSign(t *testing.T) { // initial setup ctx, ck, sk, _, keeper := createTestInput(t) + sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt)) require.True(t, got.IsOK()) validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) - require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) + require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower())) // handle a signature to set signing info @@ -58,12 +59,68 @@ func TestHandleDoubleSign(t *testing.T) { ) } +// Test that the amount a validator is slashed for multiple double signs +// is correctly capped by the slashing period in which they were committed +func TestSlashingPeriodCap(t *testing.T) { + + // initial setup + ctx, ck, sk, _, keeper := createTestInput(t) + sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) + amtInt := int64(100) + addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) + got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) + require.True(t, got.IsOK()) + validatorUpdates := stake.EndBlocker(ctx, sk) + keeper.AddValidators(ctx, validatorUpdates) + require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) + require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower())) + + // handle a signature to set signing info + keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true) + + // double sign less than max age + keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt) + + // should be jailed + require.True(t, sk.Validator(ctx, addr).GetJailed()) + // update block height + ctx = ctx.WithBlockHeight(int64(1)) + // unjail to measure power + sk.Unjail(ctx, val) + // power should be reduced + expectedPower := sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))) + require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower()) + + // double sign again, same slashing period + keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt) + // should be jailed + require.True(t, sk.Validator(ctx, addr).GetJailed()) + // update block height + ctx = ctx.WithBlockHeight(int64(2)) + // unjail to measure power + sk.Unjail(ctx, val) + // power should be equal, no more should have been slashed + expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))) + require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower()) + + // double sign again, new slashing period + keeper.handleDoubleSign(ctx, val.Address(), 2, time.Unix(0, 0), amtInt) + // should be jailed + require.True(t, sk.Validator(ctx, addr).GetJailed()) + // unjail to measure power + sk.Unjail(ctx, val) + // power should be reduced + expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(18).Quo(sdk.NewDec(20))) + require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower()) +} + // Test a validator through uptime, downtime, revocation, // unrevocation, starting height reset, and revocation again func TestHandleAbsentValidator(t *testing.T) { // initial setup ctx, ck, sk, _, keeper := createTestInput(t) + sk = sk.WithValidatorHooks(keeper.ValidatorHooks()) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) sh := stake.NewHandler(sk) @@ -72,9 +129,9 @@ func TestHandleAbsentValidator(t *testing.T) { require.True(t, got.IsOK()) validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) - require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) + require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower())) - info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) + info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) require.False(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, int64(0), info.IndexOffset) @@ -89,7 +146,7 @@ func TestHandleAbsentValidator(t *testing.T) { ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true) } - info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) + info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) require.True(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, keeper.SignedBlocksWindow(ctx), info.SignedBlocksCounter) @@ -99,7 +156,7 @@ func TestHandleAbsentValidator(t *testing.T) { ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) } - info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) + info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) require.True(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.SignedBlocksCounter) @@ -113,7 +170,7 @@ func TestHandleAbsentValidator(t *testing.T) { // 501st block missed ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) - info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) + info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) require.True(t, found) require.Equal(t, int64(0), info.StartHeight) require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter) @@ -141,7 +198,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, int64(amtInt)-slashAmt, pool.BondedTokens.RoundInt64()) // validator start height should have been changed - info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) + info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) require.True(t, found) require.Equal(t, height, info.StartHeight) require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter) @@ -182,7 +239,7 @@ func TestHandleNewValidator(t *testing.T) { require.True(t, got.IsOK()) validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) - require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}}) + require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}}) require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, sdk.ValAddress(addr)).GetPower()) // 1000 first blocks not a validator @@ -193,7 +250,7 @@ func TestHandleNewValidator(t *testing.T) { ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 2) keeper.handleValidatorSignature(ctx, val.Address(), 100, false) - info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) + info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address())) require.True(t, found) require.Equal(t, int64(keeper.SignedBlocksWindow(ctx)+1), info.StartHeight) require.Equal(t, int64(2), info.IndexOffset) diff --git a/x/slashing/keys.go b/x/slashing/keys.go new file mode 100644 index 0000000000..2af9e069a1 --- /dev/null +++ b/x/slashing/keys.go @@ -0,0 +1,43 @@ +package slashing + +import ( + "encoding/binary" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// key prefix bytes +var ( + ValidatorSigningInfoKey = []byte{0x01} // Prefix for signing info + ValidatorSigningBitArrayKey = []byte{0x02} // Prefix for signature bit array + ValidatorSlashingPeriodKey = []byte{0x03} // Prefix for slashing period + AddrPubkeyRelationKey = []byte{0x04} // Prefix for address-pubkey relation +) + +// stored by *Tendermint* address (not owner address) +func GetValidatorSigningInfoKey(v sdk.ConsAddress) []byte { + return append(ValidatorSigningInfoKey, v.Bytes()...) +} + +// stored by *Tendermint* address (not owner address) +func GetValidatorSigningBitArrayKey(v sdk.ConsAddress, i int64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, uint64(i)) + return append(ValidatorSigningBitArrayKey, append(v.Bytes(), b...)...) +} + +// stored by *Tendermint* address (not owner address) +func GetValidatorSlashingPeriodPrefix(v sdk.ConsAddress) []byte { + return append(ValidatorSlashingPeriodKey, v.Bytes()...) +} + +// stored by *Tendermint* address (not owner address) followed by start height +func GetValidatorSlashingPeriodKey(v sdk.ConsAddress, startHeight int64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, uint64(startHeight)) + return append(GetValidatorSlashingPeriodPrefix(v), b...) +} + +func getAddrPubkeyRelationKey(address []byte) []byte { + return append(AddrPubkeyRelationKey, address...) +} diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index 25a83e833d..e76fea53f2 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -1,7 +1,6 @@ package slashing import ( - "encoding/binary" "fmt" "time" @@ -9,7 +8,7 @@ import ( ) // Stored by *validator* address (not owner address) -func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.ValAddress) (info ValidatorSigningInfo, found bool) { +func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress) (info ValidatorSigningInfo, found bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(GetValidatorSigningInfoKey(address)) if bz == nil { @@ -22,14 +21,14 @@ func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.ValAddress) } // Stored by *validator* address (not owner address) -func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.ValAddress, info ValidatorSigningInfo) { +func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress, info ValidatorSigningInfo) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(info) store.Set(GetValidatorSigningInfoKey(address), bz) } // Stored by *validator* address (not owner address) -func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.ValAddress, index int64) (signed bool) { +func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64) (signed bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(GetValidatorSigningBitArrayKey(address, index)) if bz == nil { @@ -42,7 +41,7 @@ func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.ValAddr } // Stored by *validator* address (not owner address) -func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.ValAddress, index int64, signed bool) { +func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64, signed bool) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(signed) store.Set(GetValidatorSigningBitArrayKey(address, index), bz) @@ -71,15 +70,3 @@ func (i ValidatorSigningInfo) HumanReadableString() string { return fmt.Sprintf("Start height: %d, index offset: %d, jailed until: %v, signed blocks counter: %d", i.StartHeight, i.IndexOffset, i.JailedUntil, i.SignedBlocksCounter) } - -// Stored by *validator* address (not owner address) -func GetValidatorSigningInfoKey(v sdk.ValAddress) []byte { - return append([]byte{0x01}, v.Bytes()...) -} - -// Stored by *validator* address (not owner address) -func GetValidatorSigningBitArrayKey(v sdk.ValAddress, 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 f92c43581b..7aff0da95f 100644 --- a/x/slashing/signing_info_test.go +++ b/x/slashing/signing_info_test.go @@ -11,7 +11,7 @@ import ( func TestGetSetValidatorSigningInfo(t *testing.T) { ctx, _, _, _, keeper := createTestInput(t) - info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(addrs[0])) + info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(addrs[0])) require.False(t, found) newInfo := ValidatorSigningInfo{ StartHeight: int64(4), @@ -19,8 +19,8 @@ func TestGetSetValidatorSigningInfo(t *testing.T) { JailedUntil: time.Unix(2, 0), SignedBlocksCounter: int64(10), } - keeper.setValidatorSigningInfo(ctx, sdk.ValAddress(addrs[0]), newInfo) - info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(addrs[0])) + keeper.setValidatorSigningInfo(ctx, sdk.ConsAddress(addrs[0]), newInfo) + info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(addrs[0])) require.True(t, found) require.Equal(t, info.StartHeight, int64(4)) require.Equal(t, info.IndexOffset, int64(3)) @@ -30,9 +30,9 @@ func TestGetSetValidatorSigningInfo(t *testing.T) { func TestGetSetValidatorSigningBitArray(t *testing.T) { ctx, _, _, _, keeper := createTestInput(t) - signed := keeper.getValidatorSigningBitArray(ctx, sdk.ValAddress(addrs[0]), 0) + signed := keeper.getValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0) require.False(t, signed) // treat empty key as unsigned - keeper.setValidatorSigningBitArray(ctx, sdk.ValAddress(addrs[0]), 0, true) - signed = keeper.getValidatorSigningBitArray(ctx, sdk.ValAddress(addrs[0]), 0) + keeper.setValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0, true) + signed = keeper.getValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0) require.True(t, signed) // now should be signed } diff --git a/x/slashing/slashing_period.go b/x/slashing/slashing_period.go new file mode 100644 index 0000000000..61d25071eb --- /dev/null +++ b/x/slashing/slashing_period.go @@ -0,0 +1,107 @@ +package slashing + +import ( + "encoding/binary" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Cap an infraction's slash amount by the slashing period in which it was committed +func (k Keeper) capBySlashingPeriod(ctx sdk.Context, address sdk.ConsAddress, fraction sdk.Dec, infractionHeight int64) (revisedFraction sdk.Dec) { + + // Fetch the newest slashing period starting before this infraction was committed + slashingPeriod := k.getValidatorSlashingPeriodForHeight(ctx, address, infractionHeight) + + // Sanity check + if slashingPeriod.EndHeight > 0 && slashingPeriod.EndHeight < infractionHeight { + panic(fmt.Sprintf("slashing period ended before infraction: infraction height %d, slashing period ended at %d", infractionHeight, slashingPeriod.EndHeight)) + } + + // Calculate the updated total slash amount + // This is capped at the slashing fraction for the worst infraction within this slashing period + totalToSlash := sdk.MaxDec(slashingPeriod.SlashedSoFar, fraction) + + // Calculate the remainder which we now must slash + revisedFraction = totalToSlash.Sub(slashingPeriod.SlashedSoFar) + + // Update the slashing period struct + slashingPeriod.SlashedSoFar = totalToSlash + k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod) + + return +} + +// Stored by validator Tendermint address (not owner address) +// This function retrieves the most recent slashing period starting +// before a particular height - so the slashing period that was "in effect" +// at the time of an infraction committed at that height. +func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk.ConsAddress, height int64) (slashingPeriod ValidatorSlashingPeriod) { + store := ctx.KVStore(k.storeKey) + // Get the most recent slashing period at or before the infraction height + start := GetValidatorSlashingPeriodPrefix(address) + end := sdk.PrefixEndBytes(GetValidatorSlashingPeriodKey(address, height)) + iterator := store.ReverseIterator(start, end) + if !iterator.Valid() { + panic("expected to find slashing period, but none was found") + } + slashingPeriod = k.unmarshalSlashingPeriodKeyValue(iterator.Key(), iterator.Value()) + return +} + +// Stored by validator Tendermint address (not owner address) +// This function sets a validator slashing period for a particular validator, +// start height, end height, and current slashed-so-far total, or updates +// an existing slashing period for the same validator and start height. +func (k Keeper) addOrUpdateValidatorSlashingPeriod(ctx sdk.Context, slashingPeriod ValidatorSlashingPeriod) { + slashingPeriodValue := ValidatorSlashingPeriodValue{ + EndHeight: slashingPeriod.EndHeight, + SlashedSoFar: slashingPeriod.SlashedSoFar, + } + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshalBinary(slashingPeriodValue) + store.Set(GetValidatorSlashingPeriodKey(slashingPeriod.ValidatorAddr, slashingPeriod.StartHeight), bz) +} + +// Unmarshal key/value into a ValidatorSlashingPeriod +func (k Keeper) unmarshalSlashingPeriodKeyValue(key []byte, value []byte) ValidatorSlashingPeriod { + var slashingPeriodValue ValidatorSlashingPeriodValue + k.cdc.MustUnmarshalBinary(value, &slashingPeriodValue) + address := sdk.ConsAddress(key[1 : 1+sdk.AddrLen]) + startHeight := int64(binary.LittleEndian.Uint64(key[1+sdk.AddrLen : 1+sdk.AddrLen+8])) + return ValidatorSlashingPeriod{ + ValidatorAddr: address, + StartHeight: startHeight, + EndHeight: slashingPeriodValue.EndHeight, + SlashedSoFar: slashingPeriodValue.SlashedSoFar, + } +} + +// Construct a new `ValidatorSlashingPeriod` struct +func NewValidatorSlashingPeriod(startHeight int64, endHeight int64, slashedSoFar sdk.Dec) ValidatorSlashingPeriod { + return ValidatorSlashingPeriod{ + StartHeight: startHeight, + EndHeight: endHeight, + SlashedSoFar: slashedSoFar, + } +} + +// Slashing period for a validator +type ValidatorSlashingPeriod struct { + ValidatorAddr sdk.ConsAddress `json:"validator_addr"` // validator which this slashing period is for + StartHeight int64 `json:"start_height"` // starting height of the slashing period + EndHeight int64 `json:"end_height"` // ending height of the slashing period, or sentinel value of 0 for in-progress + SlashedSoFar sdk.Dec `json:"slashed_so_far"` // fraction of validator stake slashed so far in this slashing period +} + +// Value part of slashing period (validator address & start height are stored in the key) +type ValidatorSlashingPeriodValue struct { + EndHeight int64 `json:"end_height"` + SlashedSoFar sdk.Dec `json:"slashed_so_far"` +} + +// Return human readable slashing period +func (p ValidatorSlashingPeriod) HumanReadableString() string { + return fmt.Sprintf("Start height: %d, end height: %d, slashed so far: %v", + p.StartHeight, p.EndHeight, p.SlashedSoFar) +} diff --git a/x/slashing/slashing_period_test.go b/x/slashing/slashing_period_test.go new file mode 100644 index 0000000000..54157bb9cc --- /dev/null +++ b/x/slashing/slashing_period_test.go @@ -0,0 +1,86 @@ +package slashing + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestGetSetValidatorSlashingPeriod(t *testing.T) { + ctx, _, _, _, keeper := createTestInput(t) + addr := sdk.ConsAddress(addrs[0]) + height := int64(5) + require.Panics(t, func() { keeper.getValidatorSlashingPeriodForHeight(ctx, addr, height) }) + newPeriod := ValidatorSlashingPeriod{ + ValidatorAddr: addr, + StartHeight: height, + EndHeight: height + 10, + SlashedSoFar: sdk.ZeroDec(), + } + keeper.addOrUpdateValidatorSlashingPeriod(ctx, newPeriod) + + // Get at start height + retrieved := keeper.getValidatorSlashingPeriodForHeight(ctx, addr, height) + require.Equal(t, newPeriod, retrieved) + + // Get after start height (works) + retrieved = keeper.getValidatorSlashingPeriodForHeight(ctx, addr, int64(6)) + require.Equal(t, newPeriod, retrieved) + + // Get before start height (panic) + require.Panics(t, func() { keeper.getValidatorSlashingPeriodForHeight(ctx, addr, int64(0)) }) + + // Get after end height (panic) + newPeriod.EndHeight = int64(4) + keeper.addOrUpdateValidatorSlashingPeriod(ctx, newPeriod) + require.Panics(t, func() { keeper.capBySlashingPeriod(ctx, addr, sdk.ZeroDec(), height) }) + + // Back to old end height + newPeriod.EndHeight = height + 10 + keeper.addOrUpdateValidatorSlashingPeriod(ctx, newPeriod) + + // Set a new, later period + anotherPeriod := ValidatorSlashingPeriod{ + ValidatorAddr: addr, + StartHeight: height + 1, + EndHeight: height + 11, + SlashedSoFar: sdk.ZeroDec(), + } + keeper.addOrUpdateValidatorSlashingPeriod(ctx, anotherPeriod) + + // Old period retrieved for prior height + retrieved = keeper.getValidatorSlashingPeriodForHeight(ctx, addr, height) + require.Equal(t, newPeriod, retrieved) + + // New period retrieved at new height + retrieved = keeper.getValidatorSlashingPeriodForHeight(ctx, addr, height+1) + require.Equal(t, anotherPeriod, retrieved) +} + +func TestValidatorSlashingPeriodCap(t *testing.T) { + ctx, _, _, _, keeper := createTestInput(t) + addr := sdk.ConsAddress(addrs[0]) + height := int64(5) + newPeriod := ValidatorSlashingPeriod{ + ValidatorAddr: addr, + StartHeight: height, + EndHeight: height + 10, + SlashedSoFar: sdk.ZeroDec(), + } + keeper.addOrUpdateValidatorSlashingPeriod(ctx, newPeriod) + half := sdk.NewDec(1).Quo(sdk.NewDec(2)) + + // First slash should be full + fractionA := keeper.capBySlashingPeriod(ctx, addr, half, height) + require.True(t, fractionA.Equal(half)) + + // Second slash should be capped + fractionB := keeper.capBySlashingPeriod(ctx, addr, half, height) + require.True(t, fractionB.Equal(sdk.ZeroDec())) + + // Third slash should be capped to difference + fractionC := keeper.capBySlashingPeriod(ctx, addr, sdk.OneDec(), height) + require.True(t, fractionC.Equal(half)) +} diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 6974113100..afbe47d553 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -31,10 +31,10 @@ var ( newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"), } - addrs = []sdk.AccAddress{ - sdk.AccAddress(pks[0].Address()), - sdk.AccAddress(pks[1].Address()), - sdk.AccAddress(pks[2].Address()), + addrs = []sdk.ValAddress{ + sdk.ValAddress(pks[0].Address()), + sdk.ValAddress(pks[1].Address()), + sdk.ValAddress(pks[2].Address()), } initCoins = sdk.NewInt(200) ) @@ -76,7 +76,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para require.Nil(t, err) for _, addr := range addrs { - _, _, err = ck.AddCoins(ctx, addr, sdk.Coins{ + _, _, err = ck.AddCoins(ctx, sdk.AccAddress(addr), sdk.Coins{ {sk.GetParams(ctx).BondDenom, initCoins}, }) } diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index 9eb956e671..40705cf515 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -21,7 +21,7 @@ func TestBeginBlocker(t *testing.T) { require.True(t, got.IsOK()) validatorUpdates := stake.EndBlocker(ctx, sk) keeper.AddValidators(ctx, validatorUpdates) - require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) + require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower())) val := abci.Validator{ @@ -40,7 +40,7 @@ func TestBeginBlocker(t *testing.T) { } BeginBlocker(ctx, req, keeper) - info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(pk.Address())) + info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(pk.Address())) require.True(t, found) require.Equal(t, ctx.BlockHeight(), info.StartHeight) require.Equal(t, int64(1), info.IndexOffset) diff --git a/x/stake/keeper/keeper.go b/x/stake/keeper/keeper.go index 187649c5f7..14c8343878 100644 --- a/x/stake/keeper/keeper.go +++ b/x/stake/keeper/keeper.go @@ -10,9 +10,10 @@ import ( // keeper of the stake store type Keeper struct { - storeKey sdk.StoreKey - cdc *wire.Codec - coinKeeper bank.Keeper + storeKey sdk.StoreKey + cdc *wire.Codec + coinKeeper bank.Keeper + validatorHooks sdk.ValidatorHooks // codespace codespace sdk.CodespaceType @@ -20,14 +21,24 @@ type Keeper struct { func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.Keeper, codespace sdk.CodespaceType) Keeper { keeper := Keeper{ - storeKey: key, - cdc: cdc, - coinKeeper: ck, - codespace: codespace, + storeKey: key, + cdc: cdc, + coinKeeper: ck, + validatorHooks: nil, + codespace: codespace, } return keeper } +// Set the validator hooks +func (k Keeper) WithValidatorHooks(v sdk.ValidatorHooks) Keeper { + if k.validatorHooks != nil { + panic("cannot set validator hooks twice") + } + k.validatorHooks = v + return k +} + //_________________________________________________________________________ // return the codespace diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index cb225df6cc..0ea24e6396 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -591,6 +591,13 @@ func (k Keeper) unbondValidator(ctx sdk.Context, validator types.Validator) type // also remove from the Bonded types.Validators Store store.Delete(GetValidatorsBondedIndexKey(validator.Operator)) + + // call the unbond hook if present + if k.validatorHooks != nil { + k.validatorHooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) + } + + // return updated validator return validator } @@ -617,6 +624,12 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator()) store.Set(GetTendermintUpdatesKey(validator.Operator), bzABCI) + // call the bond hook if present + if k.validatorHooks != nil { + k.validatorHooks.OnValidatorBonded(ctx, validator.ConsAddress()) + } + + // return updated validator return validator } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 2cb952db28..6a53965ca8 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -246,6 +246,11 @@ func (v Validator) Equal(c2 Validator) bool { v.LastBondedTokens.Equal(c2.LastBondedTokens) } +// return the TM validator address +func (v Validator) ConsAddress() sdk.ConsAddress { + return sdk.ConsAddress(v.PubKey.Address()) +} + // constant used in flags to indicate that description field should not be updated const DoNotModifyDesc = "[do-not-modify]" From b29620953604bf2ce611ec39ca8c76013bd9c71b Mon Sep 17 00:00:00 2001 From: Rigel <rigel.rozanski@gmail.com> Date: Fri, 31 Aug 2018 21:23:30 -0400 Subject: [PATCH 28/28] Merge PR #2205: minor develop fix * minor corrections * ... * ... --- x/slashing/handler_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 2ba8dcc4db..c5afb87389 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -38,7 +38,9 @@ func TestJailedValidatorDelegations(t *testing.T) { // create a validator amount := int64(10) - valAddr, valPubKey, bondAmount := sdk.ValAddress(addrs[0]), pks[0], sdk.NewInt(amount) + valPubKey, bondAmount := pks[0], sdk.NewInt(amount) + valAddr, consAddr := sdk.ValAddress(addrs[1]), sdk.ConsAddress(addrs[0]) + msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount) got := stake.NewHandler(stakeKeeper)(ctx, msgCreateVal) require.True(t, got.IsOK(), "expected create validator msg to be ok, got: %v", got) @@ -50,10 +52,10 @@ func TestJailedValidatorDelegations(t *testing.T) { JailedUntil: time.Unix(0, 0), SignedBlocksCounter: int64(0), } - slashingKeeper.setValidatorSigningInfo(ctx, valAddr, newInfo) + slashingKeeper.setValidatorSigningInfo(ctx, consAddr, newInfo) // delegate tokens to the validator - delAddr := addrs[1] + delAddr := sdk.AccAddress(addrs[2]) msgDelegate := newTestMsgDelegate(delAddr, valAddr, bondAmount) got = stake.NewHandler(stakeKeeper)(ctx, msgDelegate) require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got)