From cf1d6846a67894a05abc762a06ba47512d285d40 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Thu, 31 Jan 2019 03:25:18 +0100 Subject: [PATCH 01/21] Improve coverage --- crypto/keys/hd/hdpath.go | 37 +++++++++--------- crypto/keys/hd/hdpath_test.go | 70 +++++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 24 deletions(-) diff --git a/crypto/keys/hd/hdpath.go b/crypto/keys/hd/hdpath.go index 112abe0b662a..301982c37bca 100644 --- a/crypto/keys/hd/hdpath.go +++ b/crypto/keys/hd/hdpath.go @@ -62,19 +62,7 @@ func NewParamsFromPath(path string) (*BIP44Params, error) { return nil, fmt.Errorf("path length is wrong. Expected 5, got %d", len(spl)) } - if spl[0] != "44'" { - return nil, fmt.Errorf("first field in path must be 44', got %v", spl[0]) - } - - if !isHardened(spl[1]) || !isHardened(spl[2]) { - return nil, - fmt.Errorf("second and third field in path must be hardened (ie. contain the suffix ', got %v and %v", spl[1], spl[2]) - } - if isHardened(spl[3]) || isHardened(spl[4]) { - return nil, - fmt.Errorf("fourth and fifth field in path must not be hardened (ie. not contain the suffix ', got %v and %v", spl[3], spl[4]) - } - + // Check items can be parsed purpose, err := hardenedInt(spl[0]) if err != nil { return nil, err @@ -91,15 +79,30 @@ func NewParamsFromPath(path string) (*BIP44Params, error) { if err != nil { return nil, err } - if !(change == 0 || change == 1) { - return nil, fmt.Errorf("change field can only be 0 or 1") - } addressIdx, err := hardenedInt(spl[4]) if err != nil { return nil, err } + // Confirm valid values + if spl[0] != "44'" { + return nil, fmt.Errorf("first field in path must be 44', got %v", spl[0]) + } + + if !isHardened(spl[1]) || !isHardened(spl[2]) { + return nil, + fmt.Errorf("second and third field in path must be hardened (ie. contain the suffix ', got %v and %v", spl[1], spl[2]) + } + if isHardened(spl[3]) || isHardened(spl[4]) { + return nil, + fmt.Errorf("fourth and fifth field in path must not be hardened (ie. not contain the suffix ', got %v and %v", spl[3], spl[4]) + } + + if !(change == 0 || change == 1) { + return nil, fmt.Errorf("change field can only be 0 or 1") + } + return &BIP44Params{ purpose: purpose, coinType: coinType, @@ -132,7 +135,7 @@ func NewFundraiserParams(account uint32, addressIdx uint32) *BIP44Params { return NewParams(44, 118, account, false, addressIdx) } -// Return the BIP44 fields as an array. +// DerivationPath returns the BIP44 fields as an array. func (p BIP44Params) DerivationPath() []uint32 { change := uint32(0) if p.change { diff --git a/crypto/keys/hd/hdpath_test.go b/crypto/keys/hd/hdpath_test.go index f310fc3555cb..2781bc01ecb5 100644 --- a/crypto/keys/hd/hdpath_test.go +++ b/crypto/keys/hd/hdpath_test.go @@ -21,7 +21,31 @@ func mnemonicToSeed(mnemonic string) []byte { func ExampleStringifyPathParams() { path := NewParams(44, 0, 0, false, 0) fmt.Println(path.String()) - // Output: 44'/0'/0'/0/0 + path = NewParams(44, 33, 7, true, 9) + fmt.Println(path.String()) + // Output: + // 44'/0'/0'/0/0 + // 44'/33'/7'/1/9 +} + +func ExampleStringifyFundraiserPathParams() { + path := NewFundraiserParams(4, 22) + fmt.Println(path.String()) + path = NewFundraiserParams(4, 57) + fmt.Println(path.String()) + // Output: + // 44'/118'/4'/0/22 + // 44'/118'/4'/0/57 +} + +func ExamplePathToArray() { + path := NewParams(44, 118, 1, false, 4) + fmt.Println(path.DerivationPath()) + path = NewParams(44, 118, 2, true, 15) + fmt.Println(path.DerivationPath()) + // Output: + // [44 118 1 0 4] + // [44 118 2 1 15] } func TestParamsFromPath(t *testing.T) { @@ -60,6 +84,11 @@ func TestParamsFromPath(t *testing.T) { {"44'/0'/0'/0/0'"}, // fifth field must not have ' {"44'/-1'/0'/0/0"}, // no negatives {"44'/0'/0'/-1/0"}, // no negatives + {"a'/0'/0'/-1/0"}, // valid values + {"0/X/0'/-1/0"}, // valid values + {"44'/0'/X/-1/0"}, // valid values + {"44'/0'/0'/%/0"}, // valid values + {"44'/0'/0'/0/%"}, // valid values } for i, c := range badCases { @@ -80,14 +109,39 @@ func ExampleSomeBIP32TestVecs() { fmt.Println("keys from fundraiser test-vector (cosmos, bitcoin, ether)") fmt.Println() // cosmos - priv, _ := DerivePrivateKeyForPath(master, ch, FullFundraiserPath) - fmt.Println(hex.EncodeToString(priv[:])) + priv, err := DerivePrivateKeyForPath(master, ch, FullFundraiserPath) + if err != nil { + fmt.Println("INVALID") + } else { + fmt.Println(hex.EncodeToString(priv[:])) + } // bitcoin - priv, _ = DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/0") - fmt.Println(hex.EncodeToString(priv[:])) + priv, err = DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/0") + if err != nil { + fmt.Println("INVALID") + } else { + fmt.Println(hex.EncodeToString(priv[:])) + } // ether - priv, _ = DerivePrivateKeyForPath(master, ch, "44'/60'/0'/0/0") - fmt.Println(hex.EncodeToString(priv[:])) + priv, err = DerivePrivateKeyForPath(master, ch, "44'/60'/0'/0/0") + if err != nil { + fmt.Println("INVALID") + } else { + fmt.Println(hex.EncodeToString(priv[:])) + } + // INVALID + priv, err = DerivePrivateKeyForPath(master, ch, "X/0'/0'/0/0") + if err != nil { + fmt.Println("INVALID") + } else { + fmt.Println(hex.EncodeToString(priv[:])) + } + priv, err = DerivePrivateKeyForPath(master, ch, "-44/0'/0'/0/0") + if err != nil { + fmt.Println("INVALID") + } else { + fmt.Println(hex.EncodeToString(priv[:])) + } fmt.Println() fmt.Println("keys generated via https://coinomi.com/recovery-phrase-tool.html") @@ -121,6 +175,8 @@ func ExampleSomeBIP32TestVecs() { // bfcb217c058d8bbafd5e186eae936106ca3e943889b0b4a093ae13822fd3170c // e77c3de76965ad89997451de97b95bb65ede23a6bf185a55d80363d92ee37c3d // 7fc4d8a8146dea344ba04c593517d3f377fa6cded36cd55aee0a0bb968e651bc + // INVALID + // INVALID // // keys generated via https://coinomi.com/recovery-phrase-tool.html // From d0548e9dfbbf9925ef1999ce9c9333c039993d91 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Thu, 31 Jan 2019 03:25:45 +0100 Subject: [PATCH 02/21] remove bip44 option in gaiacli --- client/keys/add.go | 49 +++++++------------------------------- crypto/keys/keybase.go | 7 ++++-- crypto/keys/types.go | 21 +++++++--------- crypto/ledger_secp256k1.go | 12 ++++------ crypto/ledger_test.go | 9 +++---- 5 files changed, 32 insertions(+), 66 deletions(-) diff --git a/client/keys/add.go b/client/keys/add.go index b3af588dc8b4..77df60cd244e 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -20,7 +20,6 @@ import ( "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client" - ccrypto "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" sdk "github.com/cosmos/cosmos-sdk/types" @@ -28,7 +27,6 @@ import ( const ( flagInteractive = "interactive" - flagBIP44Path = "bip44-path" flagRecover = "recover" flagNoBackup = "no-backup" flagDryRun = "dry-run" @@ -68,7 +66,6 @@ the flag --nosort is set. cmd.Flags().String(FlagPublicKey, "", "Parse a public key in bech32 format and save it to disk") cmd.Flags().BoolP(flagInteractive, "i", false, "Interactively prompt user for BIP39 passphrase and mnemonic") cmd.Flags().Bool(client.FlagUseLedger, false, "Store a local reference to a private key on a Ledger device") - cmd.Flags().String(flagBIP44Path, "44'/118'/0'/0/0", "BIP44 path from which to derive a private key") cmd.Flags().Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating") cmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)") cmd.Flags().Bool(flagDryRun, false, "Perform action, but don't add key to local keystore") @@ -168,19 +165,13 @@ func runAddCmd(cmd *cobra.Command, args []string) error { return nil } - bipFlag := cmd.Flags().Lookup(flagBIP44Path) - bip44Params, err := getBIP44ParamsAndPath(bipFlag.Value.String(), bipFlag.Changed || !interactive) - if err != nil { - return err - } + account := uint32(viper.GetInt(flagAccount)) + index := uint32(viper.GetInt(flagIndex)) + bip44path := hd.NewParams(44, 118, account, false, index) - // If we're using ledger, only thing we need is the path. So generate key and - // we're done. + // If we're using ledger, only thing we need is the path. So generate key and we're done. if viper.GetBool(client.FlagUseLedger) { - account := uint32(viper.GetInt(flagAccount)) - index := uint32(viper.GetInt(flagIndex)) - path := ccrypto.DerivationPath{44, 118, account, 0, index} - info, err := kb.CreateLedger(name, path, keys.Secp256k1) + info, err := kb.CreateLedger(name, *bip44path, keys.Secp256k1) if err != nil { return err } @@ -196,6 +187,8 @@ func runAddCmd(cmd *cobra.Command, args []string) error { if err != nil { return err } + + // TODO: THIS IS INCORRECT! info, err := kb.CreateKey(name, seed, encryptPassword) if err != nil { return err @@ -250,7 +243,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error { } } - info, err := kb.Derive(name, mnemonic, bip39Passphrase, encryptPassword, *bip44Params) + info, err := kb.Derive(name, mnemonic, bip39Passphrase, encryptPassword, *bip44path) if err != nil { return err } @@ -258,32 +251,6 @@ func runAddCmd(cmd *cobra.Command, args []string) error { return nil } -func getBIP44ParamsAndPath(path string, flagSet bool) (*hd.BIP44Params, error) { - buf := client.BufferStdin() - bip44Path := path - - // if it wasn't set in the flag, give it a chance to overide interactively - if !flagSet { - var err error - - bip44Path, err = client.GetString(fmt.Sprintf("Enter your bip44 path. Default is %s\n", path), buf) - if err != nil { - return nil, err - } - - if len(bip44Path) == 0 { - bip44Path = path - } - } - - bip44params, err := hd.NewParamsFromPath(bip44Path) - if err != nil { - return nil, err - } - - return bip44params, nil -} - func printCreate(info keys.Info, seed string) { output := viper.Get(cli.OutputFlag) switch output { diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index e202cd6d816f..c165f920b16e 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -30,6 +30,7 @@ var _ Keybase = dbKeybase{} // Find a list of all supported languages in the BIP 39 spec (word lists). type Language int +//noinspection ALL const ( // English is the default language to create a mnemonic. // It is the only supported language by this package. @@ -158,15 +159,17 @@ func (kb dbKeybase) Derive(name, mnemonic, bip39Passphrase, encryptPasswd string // CreateLedger creates a new locally-stored reference to a Ledger keypair // It returns the created key info and an error if the Ledger could not be queried -func (kb dbKeybase) CreateLedger(name string, path crypto.DerivationPath, algo SigningAlgo) (Info, error) { +func (kb dbKeybase) CreateLedger(name string, path hd.BIP44Params, algo SigningAlgo) (Info, error) { if algo != Secp256k1 { return nil, ErrUnsupportedSigningAlgo } + priv, err := crypto.NewPrivKeyLedgerSecp256k1(path) if err != nil { return nil, err } pub := priv.PubKey() + return kb.writeLedgerKey(pub, path, name), nil } @@ -432,7 +435,7 @@ func (kb dbKeybase) writeLocalKey(priv tmcrypto.PrivKey, name, passphrase string return info } -func (kb dbKeybase) writeLedgerKey(pub tmcrypto.PubKey, path crypto.DerivationPath, name string) Info { +func (kb dbKeybase) writeLedgerKey(pub tmcrypto.PubKey, path hd.BIP44Params, name string) Info { info := newLedgerInfo(name, pub, path) kb.writeInfo(info, name) return info diff --git a/crypto/keys/types.go b/crypto/keys/types.go index 14d050961135..998120df6f7d 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -3,8 +3,6 @@ package keys import ( "github.com/tendermint/tendermint/crypto" - ccrypto "github.com/cosmos/cosmos-sdk/crypto" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "github.com/cosmos/cosmos-sdk/types" ) @@ -27,16 +25,15 @@ type Keybase interface { CreateKey(name, mnemonic, passwd string) (info Info, err error) // CreateFundraiserKey takes a mnemonic and derives, a password CreateFundraiserKey(name, mnemonic, passwd string) (info Info, err error) - // Compute a BIP39 seed from th mnemonic and bip39Passwd. + // Derive computes a BIP39 seed from th mnemonic and bip39Passwd. // Derive private key from the seed using the BIP44 params. // Encrypt the key to disk using encryptPasswd. // See https://github.com/cosmos/cosmos-sdk/issues/2095 - Derive(name, mnemonic, bip39Passwd, - encryptPasswd string, params hd.BIP44Params) (Info, error) - // Create, store, and return a new Ledger key reference - CreateLedger(name string, path ccrypto.DerivationPath, algo SigningAlgo) (info Info, err error) + Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error) + // CreateLedger creates, stores, and returns a new Ledger key reference + CreateLedger(name string, path hd.BIP44Params, algo SigningAlgo) (info Info, err error) - // Create, store, and return a new offline key reference + // CreateOffline creates, stores, and returns a new offline key reference CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error) // The following operations will *only* work on locally-stored keys @@ -46,10 +43,10 @@ type Keybase interface { Export(name string) (armor string, err error) ExportPubKey(name string) (armor string, err error) - // *only* works on locally-stored keys. Temporary method until we redo the exporting API + // ExportPrivateKeyObject *only* works on locally-stored keys. Temporary method until we redo the exporting API ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error) - // Close closes the database. + // CloseDB closes the database. CloseDB() } @@ -125,10 +122,10 @@ func (i localInfo) GetAddress() types.AccAddress { type ledgerInfo struct { Name string `json:"name"` PubKey crypto.PubKey `json:"pubkey"` - Path ccrypto.DerivationPath `json:"path"` + Path hd.BIP44Params `json:"path"` } -func newLedgerInfo(name string, pub crypto.PubKey, path ccrypto.DerivationPath) Info { +func newLedgerInfo(name string, pub crypto.PubKey, path hd.BIP44Params) Info { return &ledgerInfo{ Name: name, PubKey: pub, diff --git a/crypto/ledger_secp256k1.go b/crypto/ledger_secp256k1.go index ff05d31bae66..8f5c9ab8138b 100644 --- a/crypto/ledger_secp256k1.go +++ b/crypto/ledger_secp256k1.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" secp256k1 "github.com/btcsuite/btcd/btcec" + "github.com/cosmos/cosmos-sdk/crypto/keys/hd" tmcrypto "github.com/tendermint/tendermint/crypto" tmsecp256k1 "github.com/tendermint/tendermint/crypto/secp256k1" ) @@ -22,9 +23,6 @@ type ( // dependencies when Ledger support is potentially not enabled. discoverLedgerFn func() (LedgerSECP256K1, error) - // DerivationPath represents a Ledger derivation path. - DerivationPath []uint32 - // LedgerSECP256K1 reflects an interface a Ledger API must implement for // the SECP256K1 scheme. LedgerSECP256K1 interface { @@ -39,7 +37,7 @@ type ( // go-amino so we can view the address later, even without having the // ledger attached. CachedPubKey tmcrypto.PubKey - Path DerivationPath + Path hd.BIP44Params ledger LedgerSECP256K1 } ) @@ -49,7 +47,7 @@ type ( // // CONTRACT: The ledger device, ledgerDevice, must be loaded and set prior to // any creation of a PrivKeyLedgerSecp256k1. -func NewPrivKeyLedgerSecp256k1(path DerivationPath) (tmcrypto.PrivKey, error) { +func NewPrivKeyLedgerSecp256k1(path hd.BIP44Params) (tmcrypto.PrivKey, error) { if discoverLedger == nil { return nil, errors.New("no Ledger discovery function defined") } @@ -138,11 +136,11 @@ func (pkl PrivKeyLedgerSecp256k1) getPubKey() (key tmcrypto.PubKey, err error) { } func (pkl PrivKeyLedgerSecp256k1) signLedgerSecp256k1(msg []byte) ([]byte, error) { - return pkl.ledger.SignSECP256K1(pkl.Path, msg) + return pkl.ledger.SignSECP256K1(pkl.Path.DerivationPath(), msg) } func (pkl PrivKeyLedgerSecp256k1) pubkeyLedgerSecp256k1() (pub tmcrypto.PubKey, err error) { - key, err := pkl.ledger.GetPublicKeySECP256K1(pkl.Path) + key, err := pkl.ledger.GetPublicKeySECP256K1(pkl.Path.DerivationPath()) if err != nil { return nil, fmt.Errorf("error fetching public key: %v", err) } diff --git a/crypto/ledger_test.go b/crypto/ledger_test.go index 1aae158eff95..db49fb73eac2 100644 --- a/crypto/ledger_test.go +++ b/crypto/ledger_test.go @@ -2,6 +2,7 @@ package crypto import ( "fmt" + "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "os" "testing" @@ -16,9 +17,9 @@ func TestRealLedgerSecp256k1(t *testing.T) { t.Skip(fmt.Sprintf("Set '%s' to run code on a real ledger", ledgerEnabledEnv)) } msg := []byte("{\"account_number\":\"3\",\"chain_id\":\"1234\",\"fee\":{\"amount\":[{\"amount\":\"150\",\"denom\":\"atom\"}],\"gas\":\"5000\"},\"memo\":\"memo\",\"msgs\":[[\"%s\"]],\"sequence\":\"6\"}") - path := DerivationPath{44, 60, 0, 0, 0} + path := hd.NewParams(44, 60, 0, false, 0) - priv, err := NewPrivKeyLedgerSecp256k1(path) + priv, err := NewPrivKeyLedgerSecp256k1(*path) require.Nil(t, err, "%s", err) pub := priv.PubKey() @@ -58,7 +59,7 @@ func TestRealLedgerErrorHandling(t *testing.T) { // first, try to generate a key, must return an error // (no panic) - path := DerivationPath{44, 60, 0, 0, 0} - _, err := NewPrivKeyLedgerSecp256k1(path) + path := hd.NewParams(44, 60, 0, false, 0) + _, err := NewPrivKeyLedgerSecp256k1(*path) require.Error(t, err) } From 8db1c3dc7a6916fb41ba280a1d7655f915caf9e5 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Thu, 31 Jan 2019 13:22:02 +0100 Subject: [PATCH 03/21] Adding support for account, index in REST Removing obsolete methods Clarifying mnemonic vs seed --- client/input.go | 6 - client/keys/add.go | 289 +++++++++++++++++++++++----------------- client/keys/errors.go | 18 ++- client/keys/mnemonic.go | 2 +- client/keys/utils.go | 10 +- crypto/keys/keybase.go | 34 +---- crypto/keys/types.go | 4 - 7 files changed, 186 insertions(+), 177 deletions(-) diff --git a/client/input.go b/client/input.go index 46c838e2e4e4..631e13c69320 100644 --- a/client/input.go +++ b/client/input.go @@ -42,12 +42,6 @@ func GetPassword(prompt string, buf *bufio.Reader) (pass string, err error) { return pass, nil } -// GetSeed will request a seed phrase from stdin and trims off -// leading/trailing spaces -func GetSeed(prompt string, buf *bufio.Reader) (string, error) { - return GetString(prompt, buf) -} - // GetCheckPassword will prompt for a password twice to verify they // match (for creating a new password). // It enforces the password length. Only parses password once if diff --git a/client/keys/add.go b/client/keys/add.go index 77df60cd244e..ad33b88b478d 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -4,13 +4,13 @@ import ( "bytes" "encoding/json" "fmt" + "github.com/tendermint/tendermint/crypto/multisig" "io/ioutil" + "log" "net/http" "os" "sort" - "github.com/tendermint/tendermint/crypto/multisig" - "github.com/cosmos/go-bip39" "github.com/gorilla/mux" "github.com/pkg/errors" @@ -36,6 +36,21 @@ const ( flagNoSort = "nosort" ) +const ( + defaultBIP39Passphrase = "" + throwAwayPassword = "throwing-this-key-away" + maxValidAccountValue = int(0x80000000 - 1) + maxValidIndexalue = int(0x80000000 - 1) +) + +var ( + logger *log.Logger +) + +func Init() { + logger = log.New(os.Stderr, "", 0) +} + func addKeyCommand() *cobra.Command { cmd := &cobra.Command{ Use: "add ", @@ -92,12 +107,13 @@ func runAddCmd(cmd *cobra.Command, args []string) error { name := args[0] interactive := viper.GetBool(flagInteractive) + showMnemonic := viper.GetBool(flagNoBackup) if viper.GetBool(flagDryRun) { // we throw this away, so don't enforce args, // we want to get a new random seed phrase quickly kb = client.MockKeyBase() - encryptPassword = "throwing-this-key-away" + encryptPassword = throwAwayPassword } else { kb, err = GetKeyBaseWithWritePerm() if err != nil { @@ -141,7 +157,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error { if _, err := kb.CreateOffline(name, pk); err != nil { return err } - fmt.Fprintf(os.Stderr, "Key %q saved to disk.", name) + logger.Printf("Key %q saved to disk.", name) return nil } @@ -176,32 +192,24 @@ func runAddCmd(cmd *cobra.Command, args []string) error { return err } - printCreate(info, "") + printCreate(info, false, "") return nil } - // Recover key from seed passphrase - if viper.GetBool(flagRecover) { - seed, err := client.GetSeed( - "Enter your recovery seed phrase:", buf) - if err != nil { - return err - } + ////////////////////////////// + ////////////////////////////// - // TODO: THIS IS INCORRECT! - info, err := kb.CreateKey(name, seed, encryptPassword) - if err != nil { - return err + // Get bip39 mnemonic + var mnemonic string + bip39Passphrase := defaultBIP39Passphrase + + if interactive || viper.GetBool(flagRecover) { + bip39Message := "Enter your bip39 mnemonic" + if !viper.GetBool(flagRecover) { + bip39Message = "Enter your bip39 mnemonic, or hit enter to generate one." } - // print out results without the seed phrase - viper.Set(flagNoBackup, true) - printCreate(info, "") - return nil - } - var mnemonic string - if interactive { - mnemonic, err = client.GetString("Enter your bip39 mnemonic, or hit enter to generate one.", buf) + mnemonic, err = client.GetString(bip39Message, buf) if err != nil { return err } @@ -220,8 +228,12 @@ func runAddCmd(cmd *cobra.Command, args []string) error { } } - // get bip39 passphrase - var bip39Passphrase string + if !bip39.IsMnemonicValid(mnemonic) { + logger.Printf("Error: Mnemonic is not valid") + return nil + } + + // override bip39 passphrase if interactive { bip39Passphrase, err = client.GetString( "Enter your bip39 passphrase. This is combined with the mnemonic to derive the seed. "+ @@ -243,68 +255,66 @@ func runAddCmd(cmd *cobra.Command, args []string) error { } } - info, err := kb.Derive(name, mnemonic, bip39Passphrase, encryptPassword, *bip44path) + ////////////////////////////// + ////////////////////////////// + + info, err := kb.Derive(name, mnemonic, defaultBIP39Passphrase, encryptPassword, *bip44path) if err != nil { return err } - printCreate(info, mnemonic) + + // Recover key from seed passphrase + if viper.GetBool(flagRecover) { + // Hide mnemonic from output + showMnemonic = false + mnemonic = "" + } + + printCreate(info, showMnemonic, mnemonic) return nil } -func printCreate(info keys.Info, seed string) { +func printCreate(info keys.Info, showMnemonic bool, mnemonic string) { output := viper.Get(cli.OutputFlag) + switch output { case "text": - fmt.Fprintln(os.Stderr, "") + logger.Println() printKeyInfo(info, Bech32KeyOutput) - // print seed unless requested not to. - if !viper.GetBool(client.FlagUseLedger) && !viper.GetBool(flagNoBackup) { - fmt.Fprintln(os.Stderr, "\n**Important** write this seed phrase in a safe place.") - fmt.Fprintln(os.Stderr, "It is the only way to recover your account if you ever forget your password.") - fmt.Fprintln(os.Stderr) - fmt.Fprintln(os.Stderr, seed) + // print mnemonic unless requested not to. + if showMnemonic { + logger.Printf("\n**Important** write this mnemonic phrase in a safe place.") + logger.Printf("It is the only way to recover your account if you ever forget your password.") + logger.Println() + logger.Println(mnemonic) } case "json": out, err := Bech32KeyOutput(info) if err != nil { panic(err) } - if !viper.GetBool(flagNoBackup) { - out.Seed = seed + + if showMnemonic { + out.Mnemonic = mnemonic } + var jsonString []byte if viper.GetBool(client.FlagIndentResponse) { jsonString, err = cdc.MarshalJSONIndent(out, "", " ") } else { jsonString, err = cdc.MarshalJSON(out) } + if err != nil { panic(err) // really shouldn't happen... } - fmt.Fprintln(os.Stderr, string(jsonString)) + logger.Printf(string(jsonString)) default: panic(fmt.Sprintf("I can't speak: %s", output)) } } -// function to just a new seed to display in the UI before actually persisting it in the keybase -func getSeed(algo keys.SigningAlgo) string { - kb := client.MockKeyBase() - pass := "throwing-this-key-away" - name := "inmemorykey" - _, seed, _ := kb.CreateMnemonic(name, keys.English, pass, algo) - return seed -} - -func printPrefixed(msg string) { - fmt.Fprintln(os.Stderr, msg) -} - -func printStep() { - printPrefixed("-------------------------------------") -} - ///////////////////////////// // REST @@ -312,7 +322,35 @@ func printStep() { type NewKeyBody struct { Name string `json:"name"` Password string `json:"password"` - Seed string `json:"seed"` + Mnemonic string `json:"mnemonic"` + Account int `json:"account"` + Index int `json:"index"` +} + +// RecoverKeyBody is recover key request REST body +type RecoverKeyBody struct { + Password string `json:"password"` + Mnemonic string `json:"mnemonic"` + Account int `json:"account"` + Index int `json:"index"` +} + +// function to just create a new seed to display in the UI before actually persisting it in the keybase +func generateMnemonic(algo keys.SigningAlgo) string { + kb := client.MockKeyBase() + pass := throwAwayPassword + name := "inmemorykey" + _, seed, _ := kb.CreateMnemonic(name, keys.English, pass, algo) + return seed +} + +func checkErrorREST(w http.ResponseWriter, httpErr int, err error) bool { + if err != nil { + w.WriteHeader(httpErr) + _, _ = w.Write([]byte(err.Error())) + return true + } + return false } // add new key REST handler @@ -322,34 +360,46 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { var m NewKeyBody kb, err := GetKeyBaseWithWritePerm() - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + if checkErrorREST(w, http.StatusInternalServerError, err) { return } body, err := ioutil.ReadAll(r.Body) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) + if checkErrorREST(w, http.StatusBadRequest, err) { return } + err = json.Unmarshal(body, &m) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) + if checkErrorREST(w, http.StatusBadRequest, err) { return } + + // Check parameters if m.Name == "" { - w.WriteHeader(http.StatusBadRequest) - err = errMissingName() - w.Write([]byte(err.Error())) + checkErrorREST(w, http.StatusBadRequest, errMissingName()) return } if m.Password == "" { - w.WriteHeader(http.StatusBadRequest) - err = errMissingPassword() - w.Write([]byte(err.Error())) + checkErrorREST(w, http.StatusBadRequest, errMissingPassword()) + return + } + + mnemonic := m.Mnemonic + // if mnemonic is empty, generate one + if mnemonic == "" { + mnemonic = generateMnemonic(keys.Secp256k1) + } + if !bip39.IsMnemonicValid(mnemonic) { + checkErrorREST(w, http.StatusBadRequest, errInvalidMnemonic()) + } + + if m.Account < 0 || m.Account > maxValidAccountValue { + checkErrorREST(w, http.StatusBadRequest, errInvalidAccountNumber()) + return + } + + if m.Index < 0 || m.Index > maxValidIndexalue { + checkErrorREST(w, http.StatusBadRequest, errInvalidIndexNumber()) return } @@ -357,33 +407,26 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { infos, err := kb.List() for _, info := range infos { if info.GetName() == m.Name { - w.WriteHeader(http.StatusConflict) - err = errKeyNameConflict(m.Name) - w.Write([]byte(err.Error())) + checkErrorREST(w, http.StatusConflict, errKeyNameConflict(m.Name)) return } } // create account - seed := m.Seed - if seed == "" { - seed = getSeed(keys.Secp256k1) - } - info, err := kb.CreateKey(m.Name, seed, m.Password) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + account := uint32(m.Account) + index := uint32(m.Index) + bip44path := hd.NewParams(44, 118, account, false, index) + info, err := kb.Derive(m.Name, mnemonic, defaultBIP39Passphrase, m.Password, *bip44path) + if checkErrorREST(w, http.StatusInternalServerError, err) { return } keyOutput, err := Bech32KeyOutput(info) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + if checkErrorREST(w, http.StatusInternalServerError, err) { return } - keyOutput.Seed = seed + keyOutput.Mnemonic = mnemonic PostProcessResponse(w, cdc, keyOutput, indent) } @@ -399,16 +442,10 @@ func SeedRequestHandler(w http.ResponseWriter, r *http.Request) { } algo := keys.SigningAlgo(algoType) - seed := getSeed(algo) + seed := generateMnemonic(algo) w.Header().Set("Content-Type", "application/json") - w.Write([]byte(seed)) -} - -// RecoverKeyBody is recover key request REST body -type RecoverKeyBody struct { - Password string `json:"password"` - Seed string `json:"seed"` + _, _ = w.Write([]byte(seed)) } // RecoverRequestHandler performs key recover request @@ -417,66 +454,68 @@ func RecoverRequestHandler(indent bool) http.HandlerFunc { vars := mux.Vars(r) name := vars["name"] var m RecoverKeyBody + body, err := ioutil.ReadAll(r.Body) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) + if checkErrorREST(w, http.StatusBadRequest, err) { return } + err = cdc.UnmarshalJSON(body, &m) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) + if checkErrorREST(w, http.StatusBadRequest, err) { return } + kb, err := GetKeyBaseWithWritePerm() + checkErrorREST(w, http.StatusInternalServerError, err) + if name == "" { - w.WriteHeader(http.StatusBadRequest) - err = errMissingName() - w.Write([]byte(err.Error())) + checkErrorREST(w, http.StatusBadRequest, errMissingName()) return } if m.Password == "" { - w.WriteHeader(http.StatusBadRequest) - err = errMissingPassword() - w.Write([]byte(err.Error())) + checkErrorREST(w, http.StatusBadRequest, errMissingPassword()) return } - if m.Seed == "" { - w.WriteHeader(http.StatusBadRequest) - err = errMissingSeed() - w.Write([]byte(err.Error())) + + mnemonic := m.Mnemonic + if !bip39.IsMnemonicValid(mnemonic) { + checkErrorREST(w, http.StatusBadRequest, errInvalidMnemonic()) + } + + if m.Mnemonic == "" { + checkErrorREST(w, http.StatusBadRequest, errMissingMnemonic()) return } - kb, err := GetKeyBaseWithWritePerm() - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + if m.Account < 0 || m.Account > maxValidAccountValue { + checkErrorREST(w, http.StatusBadRequest, errInvalidAccountNumber()) return } + + if m.Index < 0 || m.Index > maxValidIndexalue { + checkErrorREST(w, http.StatusBadRequest, errInvalidIndexNumber()) + return + } + // check if already exists infos, err := kb.List() for _, info := range infos { if info.GetName() == name { - w.WriteHeader(http.StatusConflict) - err = errKeyNameConflict(name) - w.Write([]byte(err.Error())) + checkErrorREST(w, http.StatusConflict, errKeyNameConflict(name)) return } } - info, err := kb.CreateKey(name, m.Seed, m.Password) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + account := uint32(m.Account) + index := uint32(m.Index) + bip44path := hd.NewParams(44, 118, account, false, index) + info, err := kb.Derive(name, mnemonic, defaultBIP39Passphrase, m.Password, *bip44path) + if checkErrorREST(w, http.StatusInternalServerError, err) { return } keyOutput, err := Bech32KeyOutput(info) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + if checkErrorREST(w, http.StatusInternalServerError, err) { return } diff --git a/client/keys/errors.go b/client/keys/errors.go index 9c6139d7a753..a603b1d1a65b 100644 --- a/client/keys/errors.go +++ b/client/keys/errors.go @@ -3,7 +3,7 @@ package keys import "fmt" func errKeyNameConflict(name string) error { - return fmt.Errorf("acount with name %s already exists", name) + return fmt.Errorf("account with name %s already exists", name) } func errMissingName() error { @@ -14,6 +14,18 @@ func errMissingPassword() error { return fmt.Errorf("you have to specify a password for the locally stored account") } -func errMissingSeed() error { - return fmt.Errorf("you have to specify seed for key recover") +func errMissingMnemonic() error { + return fmt.Errorf("you have to specify a mnemonic for key recovery") +} + +func errInvalidMnemonic() error { + return fmt.Errorf("the mnemonic is invalid") +} + +func errInvalidAccountNumber() error { + return fmt.Errorf("the account number is invalid") +} + +func errInvalidIndexNumber() error { + return fmt.Errorf("the index number is invalid") } diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index 32a6856bbdea..a85ab8de6f33 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -58,7 +58,7 @@ func runMnemonicCmd(cmd *cobra.Command, args []string) error { // hash input entropy to get entropy seed hashedEntropy := sha256.Sum256([]byte(inputEntropy)) entropySeed = hashedEntropy[:] - printStep() + logger.Printf("-------------------------------------") } else { // read entropy seed straight from crypto.Rand var err error diff --git a/client/keys/utils.go b/client/keys/utils.go index 78899f5f8af4..04aff72823d0 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -120,11 +120,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 string `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"` + Mnemonic string `json:"mnemonic,omitempty"` } // create a list of KeyOutput in bech32 format diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index c165f920b16e..f82abd861d94 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -115,45 +115,13 @@ func (kb dbKeybase) CreateMnemonic(name string, language Language, passwd string return } -// TEMPORARY METHOD UNTIL WE FIGURE OUT USER FACING HD DERIVATION API -func (kb dbKeybase) CreateKey(name, mnemonic, passwd string) (info Info, err error) { - words := strings.Split(mnemonic, " ") - if len(words) != 12 && len(words) != 24 { - err = fmt.Errorf("recovering only works with 12 word (fundraiser) or 24 word mnemonics, got: %v words", len(words)) - return - } - seed, err := bip39.NewSeedWithErrorChecking(mnemonic, defaultBIP39Passphrase) - if err != nil { - return - } - info, err = kb.persistDerivedKey(seed, passwd, name, hd.FullFundraiserPath) - return -} - -// CreateFundraiserKey converts a mnemonic to a private key and persists it, -// encrypted with the given password. -// TODO(ismail) -func (kb dbKeybase) CreateFundraiserKey(name, mnemonic, passwd string) (info Info, err error) { - words := strings.Split(mnemonic, " ") - if len(words) != 12 { - err = fmt.Errorf("recovering only works with 12 word (fundraiser), got: %v words", len(words)) - return - } - seed, err := bip39.NewSeedWithErrorChecking(mnemonic, defaultBIP39Passphrase) - if err != nil { - return - } - info, err = kb.persistDerivedKey(seed, passwd, name, hd.FullFundraiserPath) - return -} - func (kb dbKeybase) Derive(name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params) (info Info, err error) { seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase) if err != nil { return } - info, err = kb.persistDerivedKey(seed, encryptPasswd, name, params.String()) + info, err = kb.persistDerivedKey(seed, encryptPasswd, name, params.String()) return } diff --git a/crypto/keys/types.go b/crypto/keys/types.go index 998120df6f7d..d81ecbabe91f 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -21,10 +21,6 @@ type Keybase interface { // CreateMnemonic creates a new mnemonic, and derives a hierarchical deterministic // key from that. CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) - // CreateKey takes a mnemonic and derives, a password. This method is temporary - CreateKey(name, mnemonic, passwd string) (info Info, err error) - // CreateFundraiserKey takes a mnemonic and derives, a password - CreateFundraiserKey(name, mnemonic, passwd string) (info Info, err error) // Derive computes a BIP39 seed from th mnemonic and bip39Passwd. // Derive private key from the seed using the BIP44 params. // Encrypt the key to disk using encryptPasswd. From bf7bb3159a98dc99471a77b6489bdf68f25e4831 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Thu, 31 Jan 2019 16:58:46 +0100 Subject: [PATCH 04/21] Improving tests --- client/keys/add.go | 67 +++++++++++++------------- client/keys/add_test.go | 76 +++++++++++++++++++++++++++++ client/keys/mnemonic.go | 2 +- client/lcd/lcd_test.go | 97 ++++++++++++++++++++++++++++++-------- client/lcd/test_helpers.go | 37 ++++++++++----- crypto/keys/keybase.go | 12 +++-- crypto/keys/types.go | 7 ++- 7 files changed, 229 insertions(+), 69 deletions(-) create mode 100644 client/keys/add_test.go diff --git a/client/keys/add.go b/client/keys/add.go index ad33b88b478d..28a96417ac14 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -21,7 +21,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/crypto/keys" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -44,11 +43,11 @@ const ( ) var ( - logger *log.Logger + logSErr *log.Logger ) -func Init() { - logger = log.New(os.Stderr, "", 0) +func init() { + logSErr = log.New(os.Stderr, "", 0) } func addKeyCommand() *cobra.Command { @@ -157,7 +156,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error { if _, err := kb.CreateOffline(name, pk); err != nil { return err } - logger.Printf("Key %q saved to disk.", name) + logSErr.Printf("Key %q saved to disk.", name) return nil } @@ -177,23 +176,24 @@ func runAddCmd(cmd *cobra.Command, args []string) error { if err != nil { return err } - kb.CreateOffline(name, pk) + _, err = kb.CreateOffline(name, pk) + if err != nil { + return err + } return nil } account := uint32(viper.GetInt(flagAccount)) index := uint32(viper.GetInt(flagIndex)) - bip44path := hd.NewParams(44, 118, account, false, index) // If we're using ledger, only thing we need is the path. So generate key and we're done. if viper.GetBool(client.FlagUseLedger) { - info, err := kb.CreateLedger(name, *bip44path, keys.Secp256k1) + info, err := kb.CreateLedger(name, keys.Secp256k1, account, index) if err != nil { return err } - printCreate(info, false, "") - return nil + return printCreate(info, false, "") } ////////////////////////////// @@ -229,7 +229,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error { } if !bip39.IsMnemonicValid(mnemonic) { - logger.Printf("Error: Mnemonic is not valid") + logSErr.Printf("Error: Mnemonic is not valid") return nil } @@ -258,7 +258,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error { ////////////////////////////// ////////////////////////////// - info, err := kb.Derive(name, mnemonic, defaultBIP39Passphrase, encryptPassword, *bip44path) + info, err := kb.CreateAccount(name, mnemonic, defaultBIP39Passphrase, encryptPassword, account, index) if err != nil { return err } @@ -270,29 +270,28 @@ func runAddCmd(cmd *cobra.Command, args []string) error { mnemonic = "" } - printCreate(info, showMnemonic, mnemonic) - return nil + return printCreate(info, showMnemonic, mnemonic) } -func printCreate(info keys.Info, showMnemonic bool, mnemonic string) { +func printCreate(info keys.Info, showMnemonic bool, mnemonic string) error { output := viper.Get(cli.OutputFlag) switch output { case "text": - logger.Println() + fmt.Println() printKeyInfo(info, Bech32KeyOutput) // print mnemonic unless requested not to. if showMnemonic { - logger.Printf("\n**Important** write this mnemonic phrase in a safe place.") - logger.Printf("It is the only way to recover your account if you ever forget your password.") - logger.Println() - logger.Println(mnemonic) + fmt.Printf("\n**Important** write this mnemonic phrase in a safe place.") + fmt.Printf("It is the only way to recover your account if you ever forget your password.") + fmt.Println() + fmt.Println(mnemonic) } case "json": out, err := Bech32KeyOutput(info) if err != nil { - panic(err) + return err } if showMnemonic { @@ -307,12 +306,14 @@ func printCreate(info keys.Info, showMnemonic bool, mnemonic string) { } if err != nil { - panic(err) // really shouldn't happen... + return err } - logger.Printf(string(jsonString)) + fmt.Printf(string(jsonString)) default: - panic(fmt.Sprintf("I can't speak: %s", output)) + return errors.Errorf("I can't speak: %s", output) } + + return nil } ///////////////////////////// @@ -323,16 +324,16 @@ type NewKeyBody struct { Name string `json:"name"` Password string `json:"password"` Mnemonic string `json:"mnemonic"` - Account int `json:"account"` - Index int `json:"index"` + Account int `json:"account,string,omitempty"` + Index int `json:"index,string,omitempty"` } // RecoverKeyBody is recover key request REST body type RecoverKeyBody struct { Password string `json:"password"` Mnemonic string `json:"mnemonic"` - Account int `json:"account"` - Index int `json:"index"` + Account int `json:"account,string,omitempty"` + Index int `json:"index,string,omitempty"` } // function to just create a new seed to display in the UI before actually persisting it in the keybase @@ -415,8 +416,7 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { // create account account := uint32(m.Account) index := uint32(m.Index) - bip44path := hd.NewParams(44, 118, account, false, index) - info, err := kb.Derive(m.Name, mnemonic, defaultBIP39Passphrase, m.Password, *bip44path) + info, err := kb.CreateAccount(m.Name, mnemonic, defaultBIP39Passphrase, m.Password, account, index) if checkErrorREST(w, http.StatusInternalServerError, err) { return } @@ -436,12 +436,13 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { func SeedRequestHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) algoType := vars["type"] + // algo type defaults to secp256k1 if algoType == "" { algoType = "secp256k1" } - algo := keys.SigningAlgo(algoType) + algo := keys.SigningAlgo(algoType) seed := generateMnemonic(algo) w.Header().Set("Content-Type", "application/json") @@ -508,8 +509,8 @@ func RecoverRequestHandler(indent bool) http.HandlerFunc { account := uint32(m.Account) index := uint32(m.Index) - bip44path := hd.NewParams(44, 118, account, false, index) - info, err := kb.Derive(name, mnemonic, defaultBIP39Passphrase, m.Password, *bip44path) + + info, err := kb.CreateAccount(name, mnemonic, defaultBIP39Passphrase, m.Password, account, index) if checkErrorREST(w, http.StatusInternalServerError, err) { return } diff --git a/client/keys/add_test.go b/client/keys/add_test.go new file mode 100644 index 000000000000..c6e9765265a8 --- /dev/null +++ b/client/keys/add_test.go @@ -0,0 +1,76 @@ +package keys + +import ( + "fmt" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/tendermint/tendermint/libs/cli" + "testing" +) + +const ( + testMnemonic1 = "snake island check kitten mobile member toe asthma betray symptom adjust maximum" +) + +func TestPrintCreateEmpty(t *testing.T) { + err := printCreate(nil, false, "") + assert.NotNil(t, err) +} + +func ExamplePrintNewAddressText() { + var kb keys.Keybase + kb = client.MockKeyBase() + + info, err := kb.CreateAccount("some_name", testMnemonic1, defaultBIP39Passphrase, "", 0, 0) + + if err != nil { + fmt.Println("ERROR") + } + + viper.Set(cli.OutputFlag, "text") + err = printCreate(info, true, "") + + // Output: + //NAME: TYPE: ADDRESS: PUBKEY: + //some_name offline cosmos143cm6xgtpwjm2s0dmmh5538cse478gn4eafsu8 cosmospub1addwnpepq0n89mkx74tykj8kwk443v6jjwqqylgnx0xnwdwgk34uakw7666nqmj8a8j + // + //**Important** write this mnemonic phrase in a safe place.It is the only way to recover your account if you ever forget your password. +} + +func ExamplePrintNewAddressJson() { + var kb keys.Keybase + kb = client.MockKeyBase() + + info, err := kb.CreateAccount("some_name", testMnemonic1, defaultBIP39Passphrase, "", 0, 0) + + if err != nil { + fmt.Println("ERROR") + } + + viper.Set(cli.OutputFlag, "json") + err = printCreate(info, true, "") + + // Output: + // {"name":"some_name","type":"offline","address":"cosmos143cm6xgtpwjm2s0dmmh5538cse478gn4eafsu8","pub_key":"cosmospub1addwnpepq0n89mkx74tykj8kwk443v6jjwqqylgnx0xnwdwgk34uakw7666nqmj8a8j"} +} + +func ExampleCLIAddNewAddress() { + cmd := cobra.Command{} + args := []string{"test1"} + + viper.Set(flagDryRun, true) + viper.Set(cli.OutputFlag, "text") + viper.Set(flagRecover, true) + + err := runAddCmd(&cmd, args) + if err != nil { + fmt.Printf(err.Error()) + } + + // TODO: Enable mocking + // Output: + // EOF +} diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index a85ab8de6f33..c2230a4c0c7c 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -58,7 +58,7 @@ func runMnemonicCmd(cmd *cobra.Command, args []string) error { // hash input entropy to get entropy seed hashedEntropy := sha256.Sum256([]byte(inputEntropy)) entropySeed = hashedEntropy[:] - logger.Printf("-------------------------------------") + logSErr.Printf("-------------------------------------") } else { // read entropy seed straight from crypto.Rand var err error diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 5e13cf474e8f..6d472c768887 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -14,13 +14,13 @@ import ( ctypes "github.com/tendermint/tendermint/rpc/core/types" - client "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/client/utils" "github.com/cosmos/cosmos-sdk/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" - tests "github.com/cosmos/cosmos-sdk/tests" + "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" @@ -48,41 +48,100 @@ func init() { version.Version = os.Getenv("VERSION") } -func TestKeys(t *testing.T) { +func TestSeedsAreDifferent(t *testing.T) { addr, _ := CreateAddr(t, name1, pw, GetKeyBase(t)) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}) defer cleanup() - // get new seed - seed := getKeysSeed(t, port) + mnemonic1 := getKeysSeed(t, port) + mnemonic2 := getKeysSeed(t, port) + + require.NotEqual(t, mnemonic1, mnemonic2) +} + +func TestKeyRecover(t *testing.T) { + cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}) + defer cleanup() + + myName1 := "TestKeyRecover_1" + myName2 := "TestKeyRecover_2" + + mnemonic := getKeysSeed(t, port) + expectedInfo, _ := GetKeyBase(t).CreateAccount(myName1, mnemonic, "", pw, 0, 0, ) + expectedAddress := expectedInfo.GetAddress().String() + expectedPubKey := sdk.MustBech32ifyAccPub(expectedInfo.GetPubKey()) // recover key - doRecoverKey(t, port, name2, pw, seed) + doRecoverKey(t, port, myName2, pw, mnemonic, 0, 0) + + keys := getKeys(t, port) + + require.Equal(t, expectedAddress, keys[0].Address) + require.Equal(t, expectedPubKey, keys[0].PubKey) +} + +func TestKeyRecoverHDPath(t *testing.T) { + cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}) + defer cleanup() + + mnemonic := getKeysSeed(t, port) + + for account := uint32(0); account < 50; account += 13 { + for index := uint32(0); index < 50; index += 15 { + name1Idx := fmt.Sprintf("name1_%d_%d", account, index) + name2Idx := fmt.Sprintf("name2_%d_%d", account, index) + + expectedInfo, _ := GetKeyBase(t).CreateAccount(name1Idx, mnemonic, "", pw, account, index) + expectedAddress := expectedInfo.GetAddress().String() + expectedPubKey := sdk.MustBech32ifyAccPub(expectedInfo.GetPubKey()) + + // recover key + doRecoverKey(t, port, name2Idx, pw, mnemonic, account, index) + + keysName2Idx := getKey(t, port, name2Idx) + + require.Equal(t, expectedAddress, keysName2Idx.Address) + require.Equal(t, expectedPubKey, keysName2Idx.PubKey) + } + } +} + +func TestKeys(t *testing.T) { + addr1, _ := CreateAddr(t, name1, pw, GetKeyBase(t)) + addr1Bech32 := addr1.String() + + cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr1}) + defer cleanup() + + // get new seed & recover key + mnemonic2 := getKeysSeed(t, port) + doRecoverKey(t, port, name2, pw, mnemonic2, 0, 0) // add key - resp := doKeysPost(t, port, name3, pw, seed) + mnemonic3 := mnemonic2 + resp := doKeysPost(t, port, name3, pw, mnemonic3, 0, 0) - addrBech32 := addr.String() - addr2Bech32 := resp.Address - _, err := sdk.AccAddressFromBech32(addr2Bech32) + addr3Bech32 := resp.Address + _, err := sdk.AccAddressFromBech32(addr3Bech32) require.NoError(t, err, "Failed to return a correct bech32 address") // test if created account is the correct account - expectedInfo, _ := GetKeyBase(t).CreateKey(name3, seed, pw) - expectedAccount := sdk.AccAddress(expectedInfo.GetPubKey().Address().Bytes()) - require.Equal(t, expectedAccount.String(), addr2Bech32) + expectedInfo3, _ := GetKeyBase(t).CreateAccount(name3, mnemonic3, "", pw, 0, 0, ) + expectedAddress3 := sdk.AccAddress(expectedInfo3.GetPubKey().Address()).String() + require.Equal(t, expectedAddress3, addr3Bech32) // existing keys - keys := getKeys(t, port) - require.Equal(t, name1, keys[0].Name, "Did not serve keys name correctly") - require.Equal(t, addrBech32, keys[0].Address, "Did not serve keys Address correctly") - require.Equal(t, name2, keys[1].Name, "Did not serve keys name correctly") - require.Equal(t, addr2Bech32, keys[1].Address, "Did not serve keys Address correctly") + require.Equal(t, name1, getKey(t, port, name1).Name, "Did not serve keys name correctly") + require.Equal(t, addr1Bech32, getKey(t, port, name1).Address, "Did not serve keys Address correctly") + require.Equal(t, name2, getKey(t, port, name2).Name, "Did not serve keys name correctly") + require.Equal(t, addr3Bech32, getKey(t, port, name2).Address, "Did not serve keys Address correctly") + require.Equal(t, name3, getKey(t, port, name3).Name, "Did not serve keys name correctly") + require.Equal(t, addr3Bech32, getKey(t, port, name3).Address, "Did not serve keys Address correctly") // select key key := getKey(t, port, name3) require.Equal(t, name3, key.Name, "Did not serve keys name correctly") - require.Equal(t, addr2Bech32, key.Address, "Did not serve keys Address correctly") + require.Equal(t, addr3Bech32, key.Address, "Did not serve keys Address correctly") // update key updateKey(t, port, name3, pw, altPw, false) diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 71c2a38d6ac2..d70327611002 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -538,11 +538,27 @@ func getKeys(t *testing.T, port string) []keys.KeyOutput { return m } +type postKeys struct { + Name string `json:"name"` + Password string `json:"password"` + Mnemonic string `json:"mnemonic"` + Account int `json:"account,string,omitempty"` + Index int `json:"index,string,omitempty"` +} + +type postRecoverKey struct { + Password string `json:"password"` + Mnemonic string `json:"mnemonic"` + Account int `json:"account,string,omitempty"` + Index int `json:"index,string,omitempty"` +} + // POST /keys Create a new account locally -func doKeysPost(t *testing.T, port, name, password, seed string) keys.KeyOutput { - pk := postKeys{name, password, seed} +func doKeysPost(t *testing.T, port, name, password, mnemonic string, account int, index int) keys.KeyOutput { + pk := postKeys{name, password, mnemonic, account, index} req, err := cdc.MarshalJSON(pk) require.NoError(t, err) + res, body := Request(t, port, "POST", "/keys", req) require.Equal(t, http.StatusOK, res.StatusCode, body) @@ -552,12 +568,6 @@ func doKeysPost(t *testing.T, port, name, password, seed string) keys.KeyOutput return resp } -type postKeys struct { - Name string `json:"name"` - Password string `json:"password"` - Seed string `json:"seed"` -} - // GET /keys/seed Create a new seed to create a new account defaultValidFor func getKeysSeed(t *testing.T, port string) string { res, body := Request(t, port, "GET", "/keys/seed", nil) @@ -570,13 +580,16 @@ func getKeysSeed(t *testing.T, port string) string { } // POST /keys/{name}/recover Recover a account from a seed -func doRecoverKey(t *testing.T, port, recoverName, recoverPassword, seed string) { - jsonStr := []byte(fmt.Sprintf(`{"password":"%s", "seed":"%s"}`, recoverPassword, seed)) - res, body := Request(t, port, "POST", fmt.Sprintf("/keys/%s/recover", recoverName), jsonStr) +func doRecoverKey(t *testing.T, port, recoverName, recoverPassword, mnemonic string, account uint32, index uint32) { + pk := postRecoverKey{recoverPassword, mnemonic, int(account), int(index)} + req, err := cdc.MarshalJSON(pk) + require.NoError(t, err) + + res, body := Request(t, port, "POST", fmt.Sprintf("/keys/%s/recover", recoverName), req) require.Equal(t, http.StatusOK, res.StatusCode, body) var resp keys.KeyOutput - err := codec.Cdc.UnmarshalJSON([]byte(body), &resp) + err = codec.Cdc.UnmarshalJSON([]byte(body), &resp) require.Nil(t, err, body) addr1Bech32 := resp.Address diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index f82abd861d94..029feef0911c 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -115,6 +115,11 @@ func (kb dbKeybase) CreateMnemonic(name string, language Language, passwd string return } +func (kb dbKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) { + hdPath := hd.NewFundraiserParams(account, index) + return kb.Derive(name, mnemonic, bip39Passwd, encryptPasswd, *hdPath) +} + func (kb dbKeybase) Derive(name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params) (info Info, err error) { seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase) if err != nil { @@ -127,18 +132,19 @@ func (kb dbKeybase) Derive(name, mnemonic, bip39Passphrase, encryptPasswd string // CreateLedger creates a new locally-stored reference to a Ledger keypair // It returns the created key info and an error if the Ledger could not be queried -func (kb dbKeybase) CreateLedger(name string, path hd.BIP44Params, algo SigningAlgo) (Info, error) { +func (kb dbKeybase) CreateLedger(name string, algo SigningAlgo, account uint32, index uint32) (Info, error) { if algo != Secp256k1 { return nil, ErrUnsupportedSigningAlgo } - priv, err := crypto.NewPrivKeyLedgerSecp256k1(path) + hdPath := hd.NewFundraiserParams(account, index) + priv, err := crypto.NewPrivKeyLedgerSecp256k1(*hdPath) if err != nil { return nil, err } pub := priv.PubKey() - return kb.writeLedgerKey(pub, path, name), nil + return kb.writeLedgerKey(pub, *hdPath, name), nil } // CreateOffline creates a new reference to an offline keypair diff --git a/crypto/keys/types.go b/crypto/keys/types.go index d81ecbabe91f..d73bcd0ae026 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -21,13 +21,18 @@ type Keybase interface { // CreateMnemonic creates a new mnemonic, and derives a hierarchical deterministic // key from that. CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) + + // CreateAccount creates an account based using the BIP44 path (44'/118'/{account}'/0/{index} + CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) + // Derive computes a BIP39 seed from th mnemonic and bip39Passwd. // Derive private key from the seed using the BIP44 params. // Encrypt the key to disk using encryptPasswd. // See https://github.com/cosmos/cosmos-sdk/issues/2095 Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error) + // CreateLedger creates, stores, and returns a new Ledger key reference - CreateLedger(name string, path hd.BIP44Params, algo SigningAlgo) (info Info, err error) + CreateLedger(name string, algo SigningAlgo, account uint32, index uint32) (info Info, err error) // CreateOffline creates, stores, and returns a new offline key reference CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error) From 7551c8fc598f0735548ee4f8164f29a92f4ce4a9 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Thu, 31 Jan 2019 17:45:53 +0100 Subject: [PATCH 05/21] Adding additional CLI tests --- cmd/gaia/cli_test/cli_test.go | 20 +++++++++++++++++++- cmd/gaia/cli_test/test_helpers.go | 6 ++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 6e2e60536c47..2f9903340a16 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -50,9 +50,27 @@ func TestGaiaCLIKeysAddRecover(t *testing.T) { f := InitFixtures(t) f.KeysAddRecover("test-recover", "dentist task convince chimney quality leave banana trade firm crawl eternal easily") - require.Equal(t, f.KeyAddress("test-recover").String(), "cosmos1qcfdf69js922qrdr4yaww3ax7gjml6pdds46f4") + require.Equal(t, "cosmos1qcfdf69js922qrdr4yaww3ax7gjml6pdds46f4", f.KeyAddress("test-recover").String(), ) } +func TestGaiaCLIKeysAddRecoverHDPath(t *testing.T) { + t.Parallel() + f := InitFixtures(t) + + f.KeysAddRecoverHDPath("test-recoverHD1", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 0, 0) + require.Equal(t, "cosmos1qcfdf69js922qrdr4yaww3ax7gjml6pdds46f4", f.KeyAddress("test-recoverHD1").String(), ) + + f.KeysAddRecoverHDPath("test-recoverH2", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 1, 5) + require.Equal(t, "cosmos1pdfav2cjhry9k79nu6r8kgknnjtq6a7rykmafy", f.KeyAddress("test-recoverH2").String(), ) + + f.KeysAddRecoverHDPath("test-recoverH3", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 1, 17) + require.Equal(t, "cosmos1909k354n6wl8ujzu6kmh49w4d02ax7qvlkv4sn", f.KeyAddress("test-recoverH3").String(), ) + + f.KeysAddRecoverHDPath("test-recoverH4", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 2, 17) + require.Equal(t, "cosmos1v9plmhvyhgxk3th9ydacm7j4z357s3nhtwsjat", f.KeyAddress("test-recoverH4").String(), ) +} + + func TestGaiaCLIMinimumFees(t *testing.T) { t.Parallel() f := InitFixtures(t) diff --git a/cmd/gaia/cli_test/test_helpers.go b/cmd/gaia/cli_test/test_helpers.go index b2288382f02c..92c0880f1249 100644 --- a/cmd/gaia/cli_test/test_helpers.go +++ b/cmd/gaia/cli_test/test_helpers.go @@ -232,6 +232,12 @@ func (f *Fixtures) KeysAddRecover(name, mnemonic string, flags ...string) { executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic) } +// KeysAdd is gaiacli keys add --recover --account --index +func (f *Fixtures) KeysAddRecoverHDPath(name, mnemonic string, account uint32, index uint32, flags ...string) { + cmd := fmt.Sprintf("gaiacli keys add --home=%s --recover %s --account %d --index %d", f.GCLIHome, name, account, index) + executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic) +} + // KeysShow is gaiacli keys show func (f *Fixtures) KeysShow(name string, flags ...string) keys.KeyOutput { cmd := fmt.Sprintf("gaiacli keys show --home=%s %s", f.GCLIHome, name) From 8eb5abefed957b6e42e62e65cb8bf9cc7edb4ea1 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Thu, 31 Jan 2019 17:54:11 +0100 Subject: [PATCH 06/21] updating pending.md --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index 042b9dd1163a..8822ddd8581e 100644 --- a/PENDING.md +++ b/PENDING.md @@ -77,6 +77,7 @@ BUG FIXES - [\#3419](https://github.com/cosmos/cosmos-sdk/pull/3419) Fix `q distr slashes` panic - [\#3453](https://github.com/cosmos/cosmos-sdk/pull/3453) The `rest-server` command didn't respect persistent flags such as `--chain-id` and `--trust-node` if they were passed on the command line. + - [\#3427](https://github.com/cosmos/cosmos-sdk/issues/3427) Gaiacli generates/recovers the same address irrespective of the --account or --index arguments. * Gaia From 83b68aef7dd8e05bf57f7be527faec57566e3e45 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Thu, 31 Jan 2019 19:37:41 +0100 Subject: [PATCH 07/21] Fixing linter problems --- client/keys/add_test.go | 76 ----------------------------------- crypto/keys/hd/hdpath_test.go | 21 +++++----- 2 files changed, 9 insertions(+), 88 deletions(-) delete mode 100644 client/keys/add_test.go diff --git a/client/keys/add_test.go b/client/keys/add_test.go deleted file mode 100644 index c6e9765265a8..000000000000 --- a/client/keys/add_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package keys - -import ( - "fmt" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/crypto/keys" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/stretchr/testify/assert" - "github.com/tendermint/tendermint/libs/cli" - "testing" -) - -const ( - testMnemonic1 = "snake island check kitten mobile member toe asthma betray symptom adjust maximum" -) - -func TestPrintCreateEmpty(t *testing.T) { - err := printCreate(nil, false, "") - assert.NotNil(t, err) -} - -func ExamplePrintNewAddressText() { - var kb keys.Keybase - kb = client.MockKeyBase() - - info, err := kb.CreateAccount("some_name", testMnemonic1, defaultBIP39Passphrase, "", 0, 0) - - if err != nil { - fmt.Println("ERROR") - } - - viper.Set(cli.OutputFlag, "text") - err = printCreate(info, true, "") - - // Output: - //NAME: TYPE: ADDRESS: PUBKEY: - //some_name offline cosmos143cm6xgtpwjm2s0dmmh5538cse478gn4eafsu8 cosmospub1addwnpepq0n89mkx74tykj8kwk443v6jjwqqylgnx0xnwdwgk34uakw7666nqmj8a8j - // - //**Important** write this mnemonic phrase in a safe place.It is the only way to recover your account if you ever forget your password. -} - -func ExamplePrintNewAddressJson() { - var kb keys.Keybase - kb = client.MockKeyBase() - - info, err := kb.CreateAccount("some_name", testMnemonic1, defaultBIP39Passphrase, "", 0, 0) - - if err != nil { - fmt.Println("ERROR") - } - - viper.Set(cli.OutputFlag, "json") - err = printCreate(info, true, "") - - // Output: - // {"name":"some_name","type":"offline","address":"cosmos143cm6xgtpwjm2s0dmmh5538cse478gn4eafsu8","pub_key":"cosmospub1addwnpepq0n89mkx74tykj8kwk443v6jjwqqylgnx0xnwdwgk34uakw7666nqmj8a8j"} -} - -func ExampleCLIAddNewAddress() { - cmd := cobra.Command{} - args := []string{"test1"} - - viper.Set(flagDryRun, true) - viper.Set(cli.OutputFlag, "text") - viper.Set(flagRecover, true) - - err := runAddCmd(&cmd, args) - if err != nil { - fmt.Printf(err.Error()) - } - - // TODO: Enable mocking - // Output: - // EOF -} diff --git a/crypto/keys/hd/hdpath_test.go b/crypto/keys/hd/hdpath_test.go index 2781bc01ecb5..b48e6164bf53 100644 --- a/crypto/keys/hd/hdpath_test.go +++ b/crypto/keys/hd/hdpath_test.go @@ -3,6 +3,7 @@ package hd import ( "encoding/hex" "fmt" + "github.com/stretchr/testify/require" "testing" "github.com/stretchr/testify/assert" @@ -28,24 +29,20 @@ func ExampleStringifyPathParams() { // 44'/33'/7'/1/9 } -func ExampleStringifyFundraiserPathParams() { +func TestStringifyFundraiserPathParams(t *testing.T) { path := NewFundraiserParams(4, 22) - fmt.Println(path.String()) + require.Equal(t, "44'/118'/4'/0/22", path.String()) + path = NewFundraiserParams(4, 57) - fmt.Println(path.String()) - // Output: - // 44'/118'/4'/0/22 - // 44'/118'/4'/0/57 + require.Equal(t, "44'/118'/4'/0/57", path.String()) } -func ExamplePathToArray() { +func TestPathToArray(t *testing.T) { path := NewParams(44, 118, 1, false, 4) - fmt.Println(path.DerivationPath()) + require.Equal(t, "[44 118 1 0 4]", path.DerivationPath()) + path = NewParams(44, 118, 2, true, 15) - fmt.Println(path.DerivationPath()) - // Output: - // [44 118 1 0 4] - // [44 118 2 1 15] + require.Equal(t, "[44 118 2 1 15]", path.DerivationPath()) } func TestParamsFromPath(t *testing.T) { From e6159c87747661d6994a41a62cd007f8b4284c68 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Thu, 31 Jan 2019 20:16:10 +0100 Subject: [PATCH 08/21] applying go fmt + fixing test --- client/keys/add.go | 6 +++--- client/lcd/lcd_test.go | 4 ++-- cmd/gaia/cli_test/cli_test.go | 11 +++++------ crypto/keys/hd/hdpath_test.go | 4 ++-- crypto/keys/types.go | 6 +++--- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/client/keys/add.go b/client/keys/add.go index 28a96417ac14..1ca3518d52ee 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -201,7 +201,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error { // Get bip39 mnemonic var mnemonic string - bip39Passphrase := defaultBIP39Passphrase + var bip39Passphrase string if interactive || viper.GetBool(flagRecover) { bip39Message := "Enter your bip39 mnemonic" @@ -405,7 +405,7 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { } // check if already exists - infos, err := kb.List() + infos, _ := kb.List() for _, info := range infos { if info.GetName() == m.Name { checkErrorREST(w, http.StatusConflict, errKeyNameConflict(m.Name)) @@ -499,7 +499,7 @@ func RecoverRequestHandler(indent bool) http.HandlerFunc { } // check if already exists - infos, err := kb.List() + infos, _ := kb.List() for _, info := range infos { if info.GetName() == name { checkErrorREST(w, http.StatusConflict, errKeyNameConflict(name)) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 6d472c768887..d33070ef6eb9 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -67,7 +67,7 @@ func TestKeyRecover(t *testing.T) { myName2 := "TestKeyRecover_2" mnemonic := getKeysSeed(t, port) - expectedInfo, _ := GetKeyBase(t).CreateAccount(myName1, mnemonic, "", pw, 0, 0, ) + expectedInfo, _ := GetKeyBase(t).CreateAccount(myName1, mnemonic, "", pw, 0, 0) expectedAddress := expectedInfo.GetAddress().String() expectedPubKey := sdk.MustBech32ifyAccPub(expectedInfo.GetPubKey()) @@ -126,7 +126,7 @@ func TestKeys(t *testing.T) { require.NoError(t, err, "Failed to return a correct bech32 address") // test if created account is the correct account - expectedInfo3, _ := GetKeyBase(t).CreateAccount(name3, mnemonic3, "", pw, 0, 0, ) + expectedInfo3, _ := GetKeyBase(t).CreateAccount(name3, mnemonic3, "", pw, 0, 0) expectedAddress3 := sdk.AccAddress(expectedInfo3.GetPubKey().Address()).String() require.Equal(t, expectedAddress3, addr3Bech32) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 2f9903340a16..2da2d05597a0 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -50,7 +50,7 @@ func TestGaiaCLIKeysAddRecover(t *testing.T) { f := InitFixtures(t) f.KeysAddRecover("test-recover", "dentist task convince chimney quality leave banana trade firm crawl eternal easily") - require.Equal(t, "cosmos1qcfdf69js922qrdr4yaww3ax7gjml6pdds46f4", f.KeyAddress("test-recover").String(), ) + require.Equal(t, "cosmos1qcfdf69js922qrdr4yaww3ax7gjml6pdds46f4", f.KeyAddress("test-recover").String()) } func TestGaiaCLIKeysAddRecoverHDPath(t *testing.T) { @@ -58,19 +58,18 @@ func TestGaiaCLIKeysAddRecoverHDPath(t *testing.T) { f := InitFixtures(t) f.KeysAddRecoverHDPath("test-recoverHD1", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 0, 0) - require.Equal(t, "cosmos1qcfdf69js922qrdr4yaww3ax7gjml6pdds46f4", f.KeyAddress("test-recoverHD1").String(), ) + require.Equal(t, "cosmos1qcfdf69js922qrdr4yaww3ax7gjml6pdds46f4", f.KeyAddress("test-recoverHD1").String()) f.KeysAddRecoverHDPath("test-recoverH2", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 1, 5) - require.Equal(t, "cosmos1pdfav2cjhry9k79nu6r8kgknnjtq6a7rykmafy", f.KeyAddress("test-recoverH2").String(), ) + require.Equal(t, "cosmos1pdfav2cjhry9k79nu6r8kgknnjtq6a7rykmafy", f.KeyAddress("test-recoverH2").String()) f.KeysAddRecoverHDPath("test-recoverH3", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 1, 17) - require.Equal(t, "cosmos1909k354n6wl8ujzu6kmh49w4d02ax7qvlkv4sn", f.KeyAddress("test-recoverH3").String(), ) + require.Equal(t, "cosmos1909k354n6wl8ujzu6kmh49w4d02ax7qvlkv4sn", f.KeyAddress("test-recoverH3").String()) f.KeysAddRecoverHDPath("test-recoverH4", "dentist task convince chimney quality leave banana trade firm crawl eternal easily", 2, 17) - require.Equal(t, "cosmos1v9plmhvyhgxk3th9ydacm7j4z357s3nhtwsjat", f.KeyAddress("test-recoverH4").String(), ) + require.Equal(t, "cosmos1v9plmhvyhgxk3th9ydacm7j4z357s3nhtwsjat", f.KeyAddress("test-recoverH4").String()) } - func TestGaiaCLIMinimumFees(t *testing.T) { t.Parallel() f := InitFixtures(t) diff --git a/crypto/keys/hd/hdpath_test.go b/crypto/keys/hd/hdpath_test.go index b48e6164bf53..f633030e3c36 100644 --- a/crypto/keys/hd/hdpath_test.go +++ b/crypto/keys/hd/hdpath_test.go @@ -39,10 +39,10 @@ func TestStringifyFundraiserPathParams(t *testing.T) { func TestPathToArray(t *testing.T) { path := NewParams(44, 118, 1, false, 4) - require.Equal(t, "[44 118 1 0 4]", path.DerivationPath()) + require.Equal(t, "[44 118 1 0 4]", fmt.Sprintf("%v", path.DerivationPath())) path = NewParams(44, 118, 2, true, 15) - require.Equal(t, "[44 118 2 1 15]", path.DerivationPath()) + require.Equal(t, "[44 118 2 1 15]", fmt.Sprintf("%v", path.DerivationPath())) } func TestParamsFromPath(t *testing.T) { diff --git a/crypto/keys/types.go b/crypto/keys/types.go index d73bcd0ae026..52ef88b4b94b 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -121,9 +121,9 @@ func (i localInfo) GetAddress() types.AccAddress { // ledgerInfo is the public information about a Ledger key type ledgerInfo struct { - Name string `json:"name"` - PubKey crypto.PubKey `json:"pubkey"` - Path hd.BIP44Params `json:"path"` + Name string `json:"name"` + PubKey crypto.PubKey `json:"pubkey"` + Path hd.BIP44Params `json:"path"` } func newLedgerInfo(name string, pub crypto.PubKey, path hd.BIP44Params) Info { From 1f9bc3715eec81381f3fc57b1a46c1ee99a769af Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Fri, 1 Feb 2019 12:06:55 +0100 Subject: [PATCH 09/21] applying suggestions from code review (step 1) --- client/keys/add.go | 107 +++++++++++++--------------------- client/keys/mnemonic.go | 9 ++- client/utils/rest.go | 11 ++++ crypto/keys/hd/hdpath.go | 3 + crypto/keys/hd/hdpath_test.go | 5 +- crypto/keys/keybase.go | 8 +-- 6 files changed, 63 insertions(+), 80 deletions(-) diff --git a/client/keys/add.go b/client/keys/add.go index 1ca3518d52ee..5cef2225424c 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -4,24 +4,26 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/tendermint/tendermint/crypto/multisig" "io/ioutil" - "log" "net/http" "os" "sort" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/utils" + "github.com/cosmos/cosmos-sdk/cmd/gaia/app" + "github.com/cosmos/cosmos-sdk/crypto/keys" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/go-bip39" "github.com/gorilla/mux" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/multisig" "github.com/tendermint/tendermint/libs/cli" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/crypto/keys" - sdk "github.com/cosmos/cosmos-sdk/types" ) const ( @@ -37,19 +39,10 @@ const ( const ( defaultBIP39Passphrase = "" - throwAwayPassword = "throwing-this-key-away" maxValidAccountValue = int(0x80000000 - 1) maxValidIndexalue = int(0x80000000 - 1) ) -var ( - logSErr *log.Logger -) - -func init() { - logSErr = log.New(os.Stderr, "", 0) -} - func addKeyCommand() *cobra.Command { cmd := &cobra.Command{ Use: "add ", @@ -156,7 +149,8 @@ func runAddCmd(cmd *cobra.Command, args []string) error { if _, err := kb.CreateOffline(name, pk); err != nil { return err } - logSErr.Printf("Key %q saved to disk.", name) + + fmt.Fprintf(os.Stderr, "Key %q saved to disk.", name) return nil } @@ -196,9 +190,6 @@ func runAddCmd(cmd *cobra.Command, args []string) error { return printCreate(info, false, "") } - ////////////////////////////// - ////////////////////////////// - // Get bip39 mnemonic var mnemonic string var bip39Passphrase string @@ -229,7 +220,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error { } if !bip39.IsMnemonicValid(mnemonic) { - logSErr.Printf("Error: Mnemonic is not valid") + fmt.Fprintf(os.Stderr, "Error: Mnemonic is not valid") return nil } @@ -255,9 +246,6 @@ func runAddCmd(cmd *cobra.Command, args []string) error { } } - ////////////////////////////// - ////////////////////////////// - info, err := kb.CreateAccount(name, mnemonic, defaultBIP39Passphrase, encryptPassword, account, index) if err != nil { return err @@ -339,21 +327,12 @@ type RecoverKeyBody struct { // function to just create a new seed to display in the UI before actually persisting it in the keybase func generateMnemonic(algo keys.SigningAlgo) string { kb := client.MockKeyBase() - pass := throwAwayPassword + pass := app.DefaultKeyPass name := "inmemorykey" _, seed, _ := kb.CreateMnemonic(name, keys.English, pass, algo) return seed } -func checkErrorREST(w http.ResponseWriter, httpErr int, err error) bool { - if err != nil { - w.WriteHeader(httpErr) - _, _ = w.Write([]byte(err.Error())) - return true - } - return false -} - // add new key REST handler func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -361,27 +340,27 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { var m NewKeyBody kb, err := GetKeyBaseWithWritePerm() - if checkErrorREST(w, http.StatusInternalServerError, err) { + if utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } body, err := ioutil.ReadAll(r.Body) - if checkErrorREST(w, http.StatusBadRequest, err) { + if utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { return } err = json.Unmarshal(body, &m) - if checkErrorREST(w, http.StatusBadRequest, err) { + if utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { return } // Check parameters if m.Name == "" { - checkErrorREST(w, http.StatusBadRequest, errMissingName()) + utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingName()) return } if m.Password == "" { - checkErrorREST(w, http.StatusBadRequest, errMissingPassword()) + utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingPassword()) return } @@ -391,38 +370,34 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { mnemonic = generateMnemonic(keys.Secp256k1) } if !bip39.IsMnemonicValid(mnemonic) { - checkErrorREST(w, http.StatusBadRequest, errInvalidMnemonic()) + utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidMnemonic()) } if m.Account < 0 || m.Account > maxValidAccountValue { - checkErrorREST(w, http.StatusBadRequest, errInvalidAccountNumber()) + utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidAccountNumber()) return } if m.Index < 0 || m.Index > maxValidIndexalue { - checkErrorREST(w, http.StatusBadRequest, errInvalidIndexNumber()) + utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidIndexNumber()) return } - // check if already exists - infos, _ := kb.List() - for _, info := range infos { - if info.GetName() == m.Name { - checkErrorREST(w, http.StatusConflict, errKeyNameConflict(m.Name)) - return - } + if _, tmpErr := kb.Get(m.Name); tmpErr != nil { + utils.CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(m.Name)) + return } // create account account := uint32(m.Account) index := uint32(m.Index) info, err := kb.CreateAccount(m.Name, mnemonic, defaultBIP39Passphrase, m.Password, account, index) - if checkErrorREST(w, http.StatusInternalServerError, err) { + if utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } keyOutput, err := Bech32KeyOutput(info) - if checkErrorREST(w, http.StatusInternalServerError, err) { + if utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } @@ -457,66 +432,62 @@ func RecoverRequestHandler(indent bool) http.HandlerFunc { var m RecoverKeyBody body, err := ioutil.ReadAll(r.Body) - if checkErrorREST(w, http.StatusBadRequest, err) { + if utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { return } err = cdc.UnmarshalJSON(body, &m) - if checkErrorREST(w, http.StatusBadRequest, err) { + if utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { return } kb, err := GetKeyBaseWithWritePerm() - checkErrorREST(w, http.StatusInternalServerError, err) + utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) if name == "" { - checkErrorREST(w, http.StatusBadRequest, errMissingName()) + utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingName()) return } if m.Password == "" { - checkErrorREST(w, http.StatusBadRequest, errMissingPassword()) + utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingPassword()) return } mnemonic := m.Mnemonic if !bip39.IsMnemonicValid(mnemonic) { - checkErrorREST(w, http.StatusBadRequest, errInvalidMnemonic()) + utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidMnemonic()) } if m.Mnemonic == "" { - checkErrorREST(w, http.StatusBadRequest, errMissingMnemonic()) + utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingMnemonic()) return } if m.Account < 0 || m.Account > maxValidAccountValue { - checkErrorREST(w, http.StatusBadRequest, errInvalidAccountNumber()) + utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidAccountNumber()) return } if m.Index < 0 || m.Index > maxValidIndexalue { - checkErrorREST(w, http.StatusBadRequest, errInvalidIndexNumber()) + utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidIndexNumber()) return } - // check if already exists - infos, _ := kb.List() - for _, info := range infos { - if info.GetName() == name { - checkErrorREST(w, http.StatusConflict, errKeyNameConflict(name)) - return - } + if _, tmpErr := kb.Get(name); tmpErr != nil { + utils.CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(name)) + return } account := uint32(m.Account) index := uint32(m.Index) info, err := kb.CreateAccount(name, mnemonic, defaultBIP39Passphrase, m.Password, account, index) - if checkErrorREST(w, http.StatusInternalServerError, err) { + if utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } keyOutput, err := Bech32KeyOutput(info) - if checkErrorREST(w, http.StatusInternalServerError, err) { + if utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index c2230a4c0c7c..c75e3a4b8717 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -3,12 +3,11 @@ package keys import ( "crypto/sha256" "fmt" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" + "os" bip39 "github.com/bartekn/go-bip39" + "github.com/cosmos/cosmos-sdk/client" + "github.com/spf13/cobra" ) const ( @@ -58,7 +57,7 @@ func runMnemonicCmd(cmd *cobra.Command, args []string) error { // hash input entropy to get entropy seed hashedEntropy := sha256.Sum256([]byte(inputEntropy)) entropySeed = hashedEntropy[:] - logSErr.Printf("-------------------------------------") + fmt.Fprintf(os.Stderr, "-------------------------------------") } else { // read entropy seed straight from crypto.Rand var err error diff --git a/client/utils/rest.go b/client/utils/rest.go index 2926a555133d..e8a0794ba520 100644 --- a/client/utils/rest.go +++ b/client/utils/rest.go @@ -24,6 +24,17 @@ type GasEstimateResponse struct { //----------------------------------------------------------------------------- // Basic HTTP utilities +// CheckAndWriteErrorResponse will check for errors and return +// a given error message when corresponding +func CheckAndWriteErrorResponse(w http.ResponseWriter, httpErr int, err error) bool { + if err != nil { + w.WriteHeader(httpErr) + _, _ = w.Write([]byte(err.Error())) + return true + } + return false +} + // WriteErrorResponse prepares and writes a HTTP error // given a status code and an error message. func WriteErrorResponse(w http.ResponseWriter, status int, err string) { diff --git a/crypto/keys/hd/hdpath.go b/crypto/keys/hd/hdpath.go index 301982c37bca..050b0a39e39e 100644 --- a/crypto/keys/hd/hdpath.go +++ b/crypto/keys/hd/hdpath.go @@ -14,6 +14,7 @@ package hd import ( "crypto/hmac" "crypto/sha512" + "encoding/binary" "errors" "fmt" @@ -254,8 +255,10 @@ func i64(key []byte, data []byte) (IL [32]byte, IR [32]byte) { mac := hmac.New(sha512.New, key) // sha512 does not err _, _ = mac.Write(data) + I := mac.Sum(nil) copy(IL[:], I[:32]) copy(IR[:], I[32:]) + return } diff --git a/crypto/keys/hd/hdpath_test.go b/crypto/keys/hd/hdpath_test.go index f633030e3c36..275b714ceaf3 100644 --- a/crypto/keys/hd/hdpath_test.go +++ b/crypto/keys/hd/hdpath_test.go @@ -3,12 +3,11 @@ package hd import ( "encoding/hex" "fmt" - "github.com/stretchr/testify/require" "testing" - "github.com/stretchr/testify/assert" - "github.com/cosmos/go-bip39" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var defaultBIP39Passphrase = "" diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index 029feef0911c..efaa0905cce1 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -8,19 +8,18 @@ import ( "github.com/pkg/errors" - "github.com/cosmos/go-bip39" - "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/go-bip39" + tmcrypto "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/encoding/amino" "github.com/tendermint/tendermint/crypto/secp256k1" dbm "github.com/tendermint/tendermint/libs/db" - - "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" ) var _ Keybase = dbKeybase{} @@ -115,6 +114,7 @@ func (kb dbKeybase) CreateMnemonic(name string, language Language, passwd string return } +// CreateAccount converts a mnemonic to a private key and persists it, encrypted with the given password. func (kb dbKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) { hdPath := hd.NewFundraiserParams(account, index) return kb.Derive(name, mnemonic, bip39Passwd, encryptPasswd, *hdPath) From 44b3e0cdfcb4c381e3e100d4cddeef2448a4f991 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Fri, 1 Feb 2019 15:22:23 +0100 Subject: [PATCH 10/21] unifying Rest request types --- client/keys/add.go | 100 +++++++++++------------- client/lcd/test_helpers.go | 146 +++++++---------------------------- client/types.go | 144 ++++++++++++++++++++++++++++++++++ client/utils/rest.go | 68 +--------------- x/auth/client/rest/sign.go | 9 ++- x/bank/client/rest/sendtx.go | 7 +- x/gov/client/rest/rest.go | 13 ++-- x/slashing/client/rest/tx.go | 5 +- x/staking/client/rest/tx.go | 13 ++-- 9 files changed, 248 insertions(+), 257 deletions(-) create mode 100644 client/types.go diff --git a/client/keys/add.go b/client/keys/add.go index 5cef2225424c..3c531ee16fd6 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -10,7 +10,6 @@ import ( "sort" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/utils" "github.com/cosmos/cosmos-sdk/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" @@ -105,19 +104,19 @@ func runAddCmd(cmd *cobra.Command, args []string) error { // we throw this away, so don't enforce args, // we want to get a new random seed phrase quickly kb = client.MockKeyBase() - encryptPassword = throwAwayPassword + encryptPassword = app.DefaultKeyPass } else { kb, err = GetKeyBaseWithWritePerm() if err != nil { return err } - _, err := kb.Get(name) + _, err = kb.Get(name) if err == nil { // account exists, ask for user confirmation - if response, err := client.GetConfirmation( - fmt.Sprintf("override the existing name %s", name), buf); err != nil || !response { - return err + if response, err2 := client.GetConfirmation( + fmt.Sprintf("override the existing name %s", name), buf); err2 != nil || !response { + return err2 } } @@ -271,10 +270,10 @@ func printCreate(info keys.Info, showMnemonic bool, mnemonic string) error { // print mnemonic unless requested not to. if showMnemonic { - fmt.Printf("\n**Important** write this mnemonic phrase in a safe place.") - fmt.Printf("It is the only way to recover your account if you ever forget your password.") - fmt.Println() - fmt.Println(mnemonic) + fmt.Fprintln(os.Stderr, "\n**Important** write this mnemonic phrase in a safe place.") + fmt.Fprintln(os.Stderr, "It is the only way to recover your account if you ever forget your password.") + fmt.Fprintln(os.Stderr, "") + fmt.Fprintln(os.Stderr, mnemonic) } case "json": out, err := Bech32KeyOutput(info) @@ -296,7 +295,7 @@ func printCreate(info keys.Info, showMnemonic bool, mnemonic string) error { if err != nil { return err } - fmt.Printf(string(jsonString)) + fmt.Fprintln(os.Stderr, string(jsonString)) default: return errors.Errorf("I can't speak: %s", output) } @@ -307,23 +306,6 @@ func printCreate(info keys.Info, showMnemonic bool, mnemonic string) error { ///////////////////////////// // REST -// new key request REST body -type NewKeyBody struct { - Name string `json:"name"` - Password string `json:"password"` - Mnemonic string `json:"mnemonic"` - Account int `json:"account,string,omitempty"` - Index int `json:"index,string,omitempty"` -} - -// RecoverKeyBody is recover key request REST body -type RecoverKeyBody struct { - Password string `json:"password"` - Mnemonic string `json:"mnemonic"` - Account int `json:"account,string,omitempty"` - Index int `json:"index,string,omitempty"` -} - // function to just create a new seed to display in the UI before actually persisting it in the keybase func generateMnemonic(algo keys.SigningAlgo) string { kb := client.MockKeyBase() @@ -333,34 +315,46 @@ func generateMnemonic(algo keys.SigningAlgo) string { return seed } +// CheckAndWriteErrorResponse will check for errors and return +// a given error message when corresponding +//TODO: Move to utils/rest or similar +func CheckAndWriteErrorResponse(w http.ResponseWriter, httpErr int, err error) bool { + if err != nil { + w.WriteHeader(httpErr) + _, _ = w.Write([]byte(err.Error())) + return true + } + return false +} + // add new key REST handler func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var kb keys.Keybase - var m NewKeyBody + var m client.NewKeyBody kb, err := GetKeyBaseWithWritePerm() - if utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { + if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } body, err := ioutil.ReadAll(r.Body) - if utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { + if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { return } err = json.Unmarshal(body, &m) - if utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { + if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { return } // Check parameters if m.Name == "" { - utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingName()) + CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingName()) return } if m.Password == "" { - utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingPassword()) + CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingPassword()) return } @@ -370,21 +364,21 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { mnemonic = generateMnemonic(keys.Secp256k1) } if !bip39.IsMnemonicValid(mnemonic) { - utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidMnemonic()) + CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidMnemonic()) } if m.Account < 0 || m.Account > maxValidAccountValue { - utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidAccountNumber()) + CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidAccountNumber()) return } if m.Index < 0 || m.Index > maxValidIndexalue { - utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidIndexNumber()) + CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidIndexNumber()) return } if _, tmpErr := kb.Get(m.Name); tmpErr != nil { - utils.CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(m.Name)) + CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(m.Name)) return } @@ -392,12 +386,12 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { account := uint32(m.Account) index := uint32(m.Index) info, err := kb.CreateAccount(m.Name, mnemonic, defaultBIP39Passphrase, m.Password, account, index) - if utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { + if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } keyOutput, err := Bech32KeyOutput(info) - if utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { + if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } @@ -429,52 +423,52 @@ func RecoverRequestHandler(indent bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) name := vars["name"] - var m RecoverKeyBody + var m client.RecoverKeyBody body, err := ioutil.ReadAll(r.Body) - if utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { + if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { return } err = cdc.UnmarshalJSON(body, &m) - if utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { + if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { return } kb, err := GetKeyBaseWithWritePerm() - utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) + CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) if name == "" { - utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingName()) + CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingName()) return } if m.Password == "" { - utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingPassword()) + CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingPassword()) return } mnemonic := m.Mnemonic if !bip39.IsMnemonicValid(mnemonic) { - utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidMnemonic()) + CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidMnemonic()) } if m.Mnemonic == "" { - utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingMnemonic()) + CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingMnemonic()) return } if m.Account < 0 || m.Account > maxValidAccountValue { - utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidAccountNumber()) + CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidAccountNumber()) return } if m.Index < 0 || m.Index > maxValidIndexalue { - utils.CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidIndexNumber()) + CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidIndexNumber()) return } if _, tmpErr := kb.Get(name); tmpErr != nil { - utils.CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(name)) + CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(name)) return } @@ -482,12 +476,12 @@ func RecoverRequestHandler(indent bool) http.HandlerFunc { index := uint32(m.Index) info, err := kb.CreateAccount(name, mnemonic, defaultBIP39Passphrase, m.Password, account, index) - if utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { + if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } keyOutput, err := Bech32KeyOutput(info) - if utils.CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { + if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index d70327611002..2e1ec15a906f 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -28,7 +28,6 @@ import ( "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/client/utils" gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/codec" crkeys "github.com/cosmos/cosmos-sdk/crypto/keys" @@ -143,14 +142,6 @@ func CreateAddr(t *testing.T, name, password string, kb crkeys.Keybase) (sdk.Acc return sdk.AccAddress(info.GetPubKey().Address()), seed } -// Type that combines an Address with the pnemonic of the private key to that address -type AddrSeed struct { - Address sdk.AccAddress - Seed string - Name string - Password string -} - // CreateAddr adds multiple address to the key store and returns the addresses and associated seeds in lexographical order by address. // It also requires that the keys could be created. func CreateAddrs(t *testing.T, kb crkeys.Keybase, numAddrs int) (addrs []sdk.AccAddress, seeds, names, passwords []string) { @@ -167,7 +158,7 @@ func CreateAddrs(t *testing.T, kb crkeys.Keybase, numAddrs int) (addrs []sdk.Acc password := "1234567890" info, seed, err = kb.CreateMnemonic(name, crkeys.English, password, crkeys.Secp256k1) require.NoError(t, err) - addrSeeds = append(addrSeeds, AddrSeed{Address: sdk.AccAddress(info.GetPubKey().Address()), Seed: seed, Name: name, Password: password}) + addrSeeds = append(addrSeeds, client.AddrSeed{Address: sdk.AccAddress(info.GetPubKey().Address()), Seed: seed, Name: name, Password: password}) } sort.Sort(addrSeeds) @@ -182,14 +173,14 @@ func CreateAddrs(t *testing.T, kb crkeys.Keybase, numAddrs int) (addrs []sdk.Acc return addrs, seeds, names, passwords } -// implement `Interface` in sort package. -type AddrSeedSlice []AddrSeed +// AddrSeedSlice implements `Interface` in sort package. +type AddrSeedSlice []client.AddrSeed func (b AddrSeedSlice) Len() int { return len(b) } -// Sorts lexographically by Address +// Less sorts lexicographically by Address func (b AddrSeedSlice) Less(i, j int) bool { // bytes package already implements Comparable for []byte. switch bytes.Compare(b[i].Address.Bytes(), b[j].Address.Bytes()) { @@ -538,24 +529,9 @@ func getKeys(t *testing.T, port string) []keys.KeyOutput { return m } -type postKeys struct { - Name string `json:"name"` - Password string `json:"password"` - Mnemonic string `json:"mnemonic"` - Account int `json:"account,string,omitempty"` - Index int `json:"index,string,omitempty"` -} - -type postRecoverKey struct { - Password string `json:"password"` - Mnemonic string `json:"mnemonic"` - Account int `json:"account,string,omitempty"` - Index int `json:"index,string,omitempty"` -} - // POST /keys Create a new account locally func doKeysPost(t *testing.T, port, name, password, mnemonic string, account int, index int) keys.KeyOutput { - pk := postKeys{name, password, mnemonic, account, index} + pk := client.NewKeyBody{name, password, mnemonic, account, index} req, err := cdc.MarshalJSON(pk) require.NoError(t, err) @@ -581,7 +557,7 @@ func getKeysSeed(t *testing.T, port string) string { // POST /keys/{name}/recover Recover a account from a seed func doRecoverKey(t *testing.T, port, recoverName, recoverPassword, mnemonic string, account uint32, index uint32) { - pk := postRecoverKey{recoverPassword, mnemonic, int(account), int(index)} + pk := client.RecoverKeyBody{recoverPassword, mnemonic, int(account), int(index)} req, err := cdc.MarshalJSON(pk) require.NoError(t, err) @@ -609,7 +585,7 @@ func getKey(t *testing.T, port, name string) keys.KeyOutput { // PUT /keys/{name} Update the password for this account in the KMS func updateKey(t *testing.T, port, name, oldPassword, newPassword string, fail bool) { - kr := updateKeyReq{oldPassword, newPassword} + kr := client.UpdateKeyReq{oldPassword, newPassword} req, err := cdc.MarshalJSON(kr) require.NoError(t, err) keyEndpoint := fmt.Sprintf("/keys/%s", name) @@ -621,14 +597,9 @@ func updateKey(t *testing.T, port, name, oldPassword, newPassword string, fail b require.Equal(t, http.StatusOK, res.StatusCode, body) } -type updateKeyReq struct { - OldPassword string `json:"old_password"` - NewPassword string `json:"new_password"` -} - // DELETE /keys/{name} Remove an account func deleteKey(t *testing.T, port, name, password string) { - dk := deleteKeyReq{password} + dk := client.DeleteKeyReq{password} req, err := cdc.MarshalJSON(dk) require.NoError(t, err) keyEndpoint := fmt.Sprintf("/keys/%s", name) @@ -636,10 +607,6 @@ func deleteKey(t *testing.T, port, name, password string) { require.Equal(t, http.StatusOK, res.StatusCode, body) } -type deleteKeyReq struct { - Password string `json:"password"` -} - // GET /auth/accounts/{address} Get the account information on blockchain func getAccount(t *testing.T, port string, addr sdk.AccAddress) auth.Account { res, body := Request(t, port, "GET", fmt.Sprintf("/auth/accounts/%s", addr.String()), nil) @@ -659,7 +626,7 @@ func doSign(t *testing.T, port, name, password, chainID string, accnum, sequence var signedMsg auth.StdTx payload := authrest.SignBody{ Tx: msg, - BaseReq: utils.NewBaseReq( + BaseReq: client.NewBaseReq( name, password, "", chainID, "", "", accnum, sequence, nil, nil, false, false, ), } @@ -673,7 +640,7 @@ func doSign(t *testing.T, port, name, password, chainID string, accnum, sequence // POST /tx/broadcast Send a signed Tx func doBroadcast(t *testing.T, port string, msg auth.StdTx) ctypes.ResultBroadcastTxCommit { - tx := broadcastReq{Tx: msg, Return: "block"} + tx := client.BroadcastReq{Tx: msg, Return: "block"} req, err := cdc.MarshalJSON(tx) require.Nil(t, err) res, body := Request(t, port, "POST", "/tx/broadcast", req) @@ -683,11 +650,6 @@ func doBroadcast(t *testing.T, port string, msg auth.StdTx) ctypes.ResultBroadca return resultTx } -type broadcastReq struct { - Tx auth.StdTx `json:"tx"` - Return string `json:"return"` -} - // GET /bank/balances/{address} Get the account balances // POST /bank/accounts/{address}/transfers Send coins (build -> sign -> send) @@ -725,13 +687,13 @@ func doTransferWithGas( from = addr.String() } - baseReq := utils.NewBaseReq( + baseReq := client.NewBaseReq( from, password, memo, chainID, gas, fmt.Sprintf("%f", gasAdjustment), accnum, sequence, fees, nil, generateOnly, simulate, ) - sr := sendReq{ + sr := client.SendReq{ Amount: sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 1)}, BaseReq: baseReq, } @@ -759,12 +721,12 @@ func doTransferWithGasAccAuto( receiveAddr = sdk.AccAddress(receiveInfo.GetPubKey().Address()) chainID := viper.GetString(client.FlagChainID) - baseReq := utils.NewBaseReq( + baseReq := client.NewBaseReq( from, password, memo, chainID, gas, fmt.Sprintf("%f", gasAdjustment), 0, 0, fees, nil, generateOnly, simulate, ) - sr := sendReq{ + sr := client.SendReq{ Amount: sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 1)}, BaseReq: baseReq, } @@ -776,11 +738,6 @@ func doTransferWithGasAccAuto( return } -type sendReq struct { - Amount sdk.Coins `json:"amount"` - BaseReq utils.BaseReq `json:"base_req"` -} - // ---------------------------------------------------------------------- // ICS 21 - Stake // ---------------------------------------------------------------------- @@ -792,8 +749,8 @@ func doDelegate(t *testing.T, port, name, password string, accnum := acc.GetAccountNumber() sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) - baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) - msg := msgDelegationsInput{ + baseReq := client.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) + msg := client.MsgDelegationsInput{ BaseReq: baseReq, DelegatorAddr: delAddr, ValidatorAddr: valAddr, @@ -811,13 +768,6 @@ func doDelegate(t *testing.T, port, name, password string, return result } -type msgDelegationsInput struct { - BaseReq utils.BaseReq `json:"base_req"` - DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 - ValidatorAddr sdk.ValAddress `json:"validator_addr"` // in bech32 - Delegation sdk.Coin `json:"delegation"` -} - // POST /staking/delegators/{delegatorAddr}/delegations Submit delegation func doUndelegate(t *testing.T, port, name, password string, delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount int64, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) { @@ -826,8 +776,8 @@ func doUndelegate(t *testing.T, port, name, password string, accnum := acc.GetAccountNumber() sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) - baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) - msg := msgUndelegateInput{ + baseReq := client.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) + msg := client.MsgUndelegateInput{ BaseReq: baseReq, DelegatorAddr: delAddr, ValidatorAddr: valAddr, @@ -846,13 +796,6 @@ func doUndelegate(t *testing.T, port, name, password string, return result } -type msgUndelegateInput struct { - BaseReq utils.BaseReq `json:"base_req"` - DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 - ValidatorAddr sdk.ValAddress `json:"validator_addr"` // in bech32 - SharesAmount sdk.Dec `json:"shares"` -} - // POST /staking/delegators/{delegatorAddr}/delegations Submit delegation func doBeginRedelegation(t *testing.T, port, name, password string, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, amount int64, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) { @@ -862,9 +805,9 @@ func doBeginRedelegation(t *testing.T, port, name, password string, sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) - baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) + baseReq := client.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) - msg := msgBeginRedelegateInput{ + msg := client.MsgBeginRedelegateInput{ BaseReq: baseReq, DelegatorAddr: delAddr, ValidatorSrcAddr: valSrcAddr, @@ -884,14 +827,6 @@ func doBeginRedelegation(t *testing.T, port, name, password string, return result } -type msgBeginRedelegateInput struct { - BaseReq utils.BaseReq `json:"base_req"` - DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 - ValidatorSrcAddr sdk.ValAddress `json:"validator_src_addr"` // in bech32 - ValidatorDstAddr sdk.ValAddress `json:"validator_dst_addr"` // in bech32 - SharesAmount sdk.Dec `json:"shares"` -} - // GET /staking/delegators/{delegatorAddr}/delegations Get all delegations from a delegator func getDelegatorDelegations(t *testing.T, port string, delegatorAddr sdk.AccAddress) []staking.Delegation { res, body := Request(t, port, "GET", fmt.Sprintf("/staking/delegators/%s/delegations", delegatorAddr), nil) @@ -1093,9 +1028,9 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA accnum := acc.GetAccountNumber() sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) - baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) + baseReq := client.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) - pr := postProposalReq{ + pr := client.PostProposalReq{ Title: "Test", Description: "test", ProposalType: "Text", @@ -1118,15 +1053,6 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA return results } -type postProposalReq struct { - BaseReq utils.BaseReq `json:"base_req"` - Title string `json:"title"` // Title of the proposal - Description string `json:"description"` // Description of the proposal - ProposalType string `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal} - Proposer sdk.AccAddress `json:"proposer"` // Address of the proposer - InitialDeposit sdk.Coins `json:"initial_deposit"` // Coins to add to the proposal's deposit -} - // GET /gov/proposals Query proposals func getProposalsAll(t *testing.T, port string) []gov.Proposal { res, body := Request(t, port, "GET", "/gov/proposals", nil) @@ -1189,9 +1115,9 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk accnum := acc.GetAccountNumber() sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) - baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) + baseReq := client.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) - dr := depositReq{ + dr := client.DepositReq{ Depositor: proposerAddr, Amount: sdk.Coins{sdk.NewCoin(stakingTypes.DefaultBondDenom, sdk.NewInt(amount))}, BaseReq: baseReq, @@ -1210,12 +1136,6 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk return results } -type depositReq struct { - BaseReq utils.BaseReq `json:"base_req"` - Depositor sdk.AccAddress `json:"depositor"` // Address of the depositor - Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit -} - // GET /gov/proposals/{proposalId}/deposits Query deposits func getDeposits(t *testing.T, port string, proposalID uint64) []gov.Deposit { res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), nil) @@ -1243,9 +1163,9 @@ func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.Ac accnum := acc.GetAccountNumber() sequence := acc.GetSequence() chainID := viper.GetString(client.FlagChainID) - baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) + baseReq := client.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) - vr := voteReq{ + vr := client.VoteReq{ Voter: proposerAddr, Option: option, BaseReq: baseReq, @@ -1264,12 +1184,6 @@ func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.Ac return results } -type voteReq struct { - BaseReq utils.BaseReq `json:"base_req"` - Voter sdk.AccAddress `json:"voter"` // address of the voter - Option string `json:"option"` // option from OptionSet chosen by the voter -} - // GET /gov/proposals/{proposalId}/votes Query voters func getVotes(t *testing.T, port string, proposalID uint64) []gov.Vote { res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/votes", proposalID), nil) @@ -1375,9 +1289,9 @@ func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing. func doUnjail(t *testing.T, port, seed, name, password string, valAddr sdk.ValAddress, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) { chainID := viper.GetString(client.FlagChainID) - baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", 1, 1, fees, nil, false, false) + baseReq := client.NewBaseReq(name, password, "", chainID, "", "", 1, 1, fees, nil, false, false) - ur := unjailReq{ + ur := client.UnjailReq{ BaseReq: baseReq, } req, err := cdc.MarshalJSON(ur) @@ -1391,7 +1305,3 @@ func doUnjail(t *testing.T, port, seed, name, password string, return results[0] } - -type unjailReq struct { - BaseReq utils.BaseReq `json:"base_req"` -} diff --git a/client/types.go b/client/types.go new file mode 100644 index 000000000000..874d24fd0114 --- /dev/null +++ b/client/types.go @@ -0,0 +1,144 @@ +package client + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" +) + +// BaseReq defines a structure that can be embedded in other request structures +// that all share common "base" fields. +type BaseReq struct { + From string `json:"from"` + Password string `json:"password"` + Memo string `json:"memo"` + ChainID string `json:"chain_id"` + AccountNumber uint64 `json:"account_number"` + Sequence uint64 `json:"sequence"` + Fees sdk.Coins `json:"fees"` + GasPrices sdk.DecCoins `json:"gas_prices"` + Gas string `json:"gas"` + GasAdjustment string `json:"gas_adjustment"` + GenerateOnly bool `json:"generate_only"` + Simulate bool `json:"simulate"` +} + +type SendReq struct { + Amount sdk.Coins `json:"amount"` + BaseReq BaseReq `json:"base_req"` +} + +type MsgDelegationsInput struct { + BaseReq BaseReq `json:"base_req"` + DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 + ValidatorAddr sdk.ValAddress `json:"validator_addr"` // in bech32 + Delegation sdk.Coin `json:"delegation"` +} + +type MsgUndelegateInput struct { + BaseReq BaseReq `json:"base_req"` + DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 + ValidatorAddr sdk.ValAddress `json:"validator_addr"` // in bech32 + SharesAmount sdk.Dec `json:"shares"` +} + +type MsgBeginRedelegateInput struct { + BaseReq BaseReq `json:"base_req"` + DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 + ValidatorSrcAddr sdk.ValAddress `json:"validator_src_addr"` // in bech32 + ValidatorDstAddr sdk.ValAddress `json:"validator_dst_addr"` // in bech32 + SharesAmount sdk.Dec `json:"shares"` +} + +type PostProposalReq struct { + BaseReq BaseReq `json:"base_req"` + Title string `json:"title"` // Title of the proposal + Description string `json:"description"` // Description of the proposal + ProposalType string `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal} + Proposer sdk.AccAddress `json:"proposer"` // Address of the proposer + InitialDeposit sdk.Coins `json:"initial_deposit"` // Coins to add to the proposal's deposit +} + +type DepositReq struct { + BaseReq BaseReq `json:"base_req"` + Depositor sdk.AccAddress `json:"depositor"` // Address of the depositor + Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit +} + +// AddrSeed combines an Address with the mnemonic of the private key to that address +type AddrSeed struct { + Address sdk.AccAddress + Seed string + Name string + Password string +} + +// NewKeyBody request a new key +type NewKeyBody struct { + Name string `json:"name"` + Password string `json:"password"` + Mnemonic string `json:"mnemonic"` + Account int `json:"account,string,omitempty"` + Index int `json:"index,string,omitempty"` +} + +// RecoverKeyBody recovers a key +type RecoverKeyBody struct { + Password string `json:"password"` + Mnemonic string `json:"mnemonic"` + Account int `json:"account,string,omitempty"` + Index int `json:"index,string,omitempty"` +} + +type UpdateKeyReq struct { + OldPassword string `json:"old_password"` + NewPassword string `json:"new_password"` +} + +type DeleteKeyReq struct { + Password string `json:"password"` +} + +type BroadcastReq struct { + Tx auth.StdTx `json:"tx"` + Return string `json:"return"` +} + +type VoteReq struct { + BaseReq BaseReq `json:"base_req"` + Voter sdk.AccAddress `json:"voter"` // address of the voter + Option string `json:"option"` // option from OptionSet chosen by the voter +} + +type UnjailReq struct { + BaseReq BaseReq `json:"base_req"` +} + +// NewBaseReq creates a new basic request instance and sanitizes its values +func NewBaseReq(from, password, memo, chainID string, gas, gasAdjustment string, + accNumber, seq uint64, fees sdk.Coins, gasPrices sdk.DecCoins, genOnly, simulate bool, +) BaseReq { + return BaseReq{ + From: strings.TrimSpace(from), + Password: password, + Memo: strings.TrimSpace(memo), + ChainID: strings.TrimSpace(chainID), + Fees: fees, + GasPrices: gasPrices, + Gas: strings.TrimSpace(gas), + GasAdjustment: strings.TrimSpace(gasAdjustment), + AccountNumber: accNumber, + Sequence: seq, + GenerateOnly: genOnly, + Simulate: simulate, + } +} + +// Sanitize performs basic sanitization on a BaseReq object. +func (br BaseReq) Sanitize() BaseReq { + return NewBaseReq( + br.From, br.Password, br.Memo, br.ChainID, br.Gas, br.GasAdjustment, + br.AccountNumber, br.Sequence, br.Fees, br.GasPrices, br.GenerateOnly, br.Simulate, + ) +} diff --git a/client/utils/rest.go b/client/utils/rest.go index e8a0794ba520..56576927f33d 100644 --- a/client/utils/rest.go +++ b/client/utils/rest.go @@ -5,7 +5,6 @@ import ( "io/ioutil" "net/http" "strconv" - "strings" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" @@ -24,17 +23,6 @@ type GasEstimateResponse struct { //----------------------------------------------------------------------------- // Basic HTTP utilities -// CheckAndWriteErrorResponse will check for errors and return -// a given error message when corresponding -func CheckAndWriteErrorResponse(w http.ResponseWriter, httpErr int, err error) bool { - if err != nil { - w.WriteHeader(httpErr) - _, _ = w.Write([]byte(err.Error())) - return true - } - return false -} - // WriteErrorResponse prepares and writes a HTTP error // given a status code and an error message. func WriteErrorResponse(w http.ResponseWriter, status int, err string) { @@ -104,57 +92,10 @@ func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEm //----------------------------------------------------------------------------- // Building / Sending utilities -// BaseReq defines a structure that can be embedded in other request structures -// that all share common "base" fields. -type BaseReq struct { - From string `json:"from"` - Password string `json:"password"` - Memo string `json:"memo"` - ChainID string `json:"chain_id"` - AccountNumber uint64 `json:"account_number"` - Sequence uint64 `json:"sequence"` - Fees sdk.Coins `json:"fees"` - GasPrices sdk.DecCoins `json:"gas_prices"` - Gas string `json:"gas"` - GasAdjustment string `json:"gas_adjustment"` - GenerateOnly bool `json:"generate_only"` - Simulate bool `json:"simulate"` -} - -// NewBaseReq creates a new basic request instance and sanitizes its values -func NewBaseReq( - from, password, memo, chainID string, gas, gasAdjustment string, - accNumber, seq uint64, fees sdk.Coins, gasPrices sdk.DecCoins, genOnly, simulate bool, -) BaseReq { - - return BaseReq{ - From: strings.TrimSpace(from), - Password: password, - Memo: strings.TrimSpace(memo), - ChainID: strings.TrimSpace(chainID), - Fees: fees, - GasPrices: gasPrices, - Gas: strings.TrimSpace(gas), - GasAdjustment: strings.TrimSpace(gasAdjustment), - AccountNumber: accNumber, - Sequence: seq, - GenerateOnly: genOnly, - Simulate: simulate, - } -} - -// Sanitize performs basic sanitization on a BaseReq object. -func (br BaseReq) Sanitize() BaseReq { - return NewBaseReq( - br.From, br.Password, br.Memo, br.ChainID, br.Gas, br.GasAdjustment, - br.AccountNumber, br.Sequence, br.Fees, br.GasPrices, br.GenerateOnly, br.Simulate, - ) -} - // ValidateBasic performs basic validation of a BaseReq. If custom validation // logic is needed, the implementing request handler should perform those // checks manually. -func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool { +func ValidateBasic(w http.ResponseWriter, br client.BaseReq) bool { if !br.GenerateOnly && !br.Simulate { switch { case len(br.Password) == 0: @@ -221,7 +162,7 @@ func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req i // NOTE: Also see CompleteAndBroadcastTxCLI. func CompleteAndBroadcastTxREST( w http.ResponseWriter, r *http.Request, cliCtx context.CLIContext, - baseReq BaseReq, msgs []sdk.Msg, cdc *codec.Codec, + baseReq client.BaseReq, msgs []sdk.Msg, cdc *codec.Codec, ) { gasAdj, ok := ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment) @@ -319,10 +260,7 @@ func PostProcessResponse(w http.ResponseWriter, cdc *codec.Codec, response inter } // WriteGenerateStdTxResponse writes response for the generate only mode. -func WriteGenerateStdTxResponse( - w http.ResponseWriter, cdc *codec.Codec, cliCtx context.CLIContext, br BaseReq, msgs []sdk.Msg, -) { - +func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec, br client.BaseReq, msgs []sdk.Msg) { gasAdj, ok := ParseFloat64OrReturnBadRequest(w, br.GasAdjustment, client.DefaultGasAdjustment) if !ok { return diff --git a/x/auth/client/rest/sign.go b/x/auth/client/rest/sign.go index 11b8c083ba88..21595d220ab9 100644 --- a/x/auth/client/rest/sign.go +++ b/x/auth/client/rest/sign.go @@ -3,6 +3,7 @@ package rest import ( "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/codec" @@ -14,9 +15,9 @@ import ( // SignBody defines the properties of a sign request's body. type SignBody struct { - Tx auth.StdTx `json:"tx"` - AppendSig bool `json:"append_sig"` - BaseReq utils.BaseReq `json:"base_req"` + Tx auth.StdTx `json:"tx"` + AppendSig bool `json:"append_sig"` + BaseReq client.BaseReq `json:"base_req"` } // nolint: unparam @@ -30,7 +31,7 @@ func SignTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha return } - if !m.BaseReq.ValidateBasic(w) { + if !utils.ValidateBasic(w, m.BaseReq) { return } diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index b4ef7d7a2458..5669e4d4afe9 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -3,6 +3,7 @@ package rest import ( "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/codec" @@ -21,8 +22,8 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec, } type sendReq struct { - BaseReq utils.BaseReq `json:"base_req"` - Amount sdk.Coins `json:"amount"` + BaseReq client.BaseReq `json:"base_req"` + Amount sdk.Coins `json:"amount"` } var msgCdc = codec.New() @@ -50,7 +51,7 @@ func SendRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIC } req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { + if !utils.ValidateBasic(w, req.BaseReq) { return } diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index f00c187a1a96..fca3fe0dd6c2 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -4,6 +4,7 @@ import ( "fmt" "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/codec" @@ -53,7 +54,7 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec) } type postProposalReq struct { - BaseReq utils.BaseReq `json:"base_req"` + BaseReq client.BaseReq `json:"base_req"` Title string `json:"title"` // Title of the proposal Description string `json:"description"` // Description of the proposal ProposalType string `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal} @@ -62,13 +63,13 @@ type postProposalReq struct { } type depositReq struct { - BaseReq utils.BaseReq `json:"base_req"` + BaseReq client.BaseReq `json:"base_req"` Depositor sdk.AccAddress `json:"depositor"` // Address of the depositor Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit } type voteReq struct { - BaseReq utils.BaseReq `json:"base_req"` + BaseReq client.BaseReq `json:"base_req"` Voter sdk.AccAddress `json:"voter"` // address of the voter Option string `json:"option"` // option from OptionSet chosen by the voter } @@ -83,7 +84,7 @@ func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han } req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { + if !utils.ValidateBasic(w, req.BaseReq) { return } @@ -133,7 +134,7 @@ func depositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerF } req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { + if !utils.ValidateBasic(w, req.BaseReq) { return } @@ -177,7 +178,7 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc } req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { + if !utils.ValidateBasic(w, req.BaseReq) { return } diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index 672928f3f8bb..d92aa8fdf012 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -4,6 +4,7 @@ import ( "bytes" "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/codec" @@ -23,7 +24,7 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec // Unjail TX body type UnjailReq struct { - BaseReq utils.BaseReq `json:"base_req"` + BaseReq client.BaseReq `json:"base_req"` } func unjailRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc { @@ -39,7 +40,7 @@ func unjailRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CL } req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { + if !utils.ValidateBasic(w, req.BaseReq) { return } diff --git a/x/staking/client/rest/tx.go b/x/staking/client/rest/tx.go index 1710d340ad4a..9fd6055bbf85 100644 --- a/x/staking/client/rest/tx.go +++ b/x/staking/client/rest/tx.go @@ -4,6 +4,7 @@ import ( "bytes" "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/codec" @@ -31,14 +32,14 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec type ( msgDelegationsInput struct { - BaseReq utils.BaseReq `json:"base_req"` + BaseReq client.BaseReq `json:"base_req"` DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 ValidatorAddr sdk.ValAddress `json:"validator_addr"` // in bech32 Delegation sdk.Coin `json:"delegation"` } msgBeginRedelegateInput struct { - BaseReq utils.BaseReq `json:"base_req"` + BaseReq client.BaseReq `json:"base_req"` DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 ValidatorSrcAddr sdk.ValAddress `json:"validator_src_addr"` // in bech32 ValidatorDstAddr sdk.ValAddress `json:"validator_dst_addr"` // in bech32 @@ -46,7 +47,7 @@ type ( } msgUndelegateInput struct { - BaseReq utils.BaseReq `json:"base_req"` + BaseReq client.BaseReq `json:"base_req"` DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 ValidatorAddr sdk.ValAddress `json:"validator_addr"` // in bech32 SharesAmount sdk.Dec `json:"shares"` @@ -64,7 +65,7 @@ func postDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context. } req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { + if !utils.ValidateBasic(w, req.BaseReq) { return } @@ -109,7 +110,7 @@ func postRedelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx contex } req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { + if !utils.ValidateBasic(w, req.BaseReq) { return } @@ -154,7 +155,7 @@ func postUnbondingDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx } req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { + if !utils.ValidateBasic(w, req.BaseReq) { return } From baffdef9dcf2715145827a1a210f9b06ca34b82e Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Fri, 1 Feb 2019 15:43:22 +0100 Subject: [PATCH 11/21] Linter: Adding missing comments --- client/types.go | 11 +++++++++++ x/ibc/client/rest/transfer.go | 8 +++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/client/types.go b/client/types.go index 874d24fd0114..4aae8efb6a52 100644 --- a/client/types.go +++ b/client/types.go @@ -24,11 +24,13 @@ type BaseReq struct { Simulate bool `json:"simulate"` } +// SendReq requests sending an amount of coins type SendReq struct { Amount sdk.Coins `json:"amount"` BaseReq BaseReq `json:"base_req"` } +// MsgDelegationsInput requests a delegation type MsgDelegationsInput struct { BaseReq BaseReq `json:"base_req"` DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 @@ -36,6 +38,7 @@ type MsgDelegationsInput struct { Delegation sdk.Coin `json:"delegation"` } +// MsgUndelegateInput request an undelegation type MsgUndelegateInput struct { BaseReq BaseReq `json:"base_req"` DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 @@ -43,6 +46,7 @@ type MsgUndelegateInput struct { SharesAmount sdk.Dec `json:"shares"` } +// MsgBeginRedelegateInput request to begin a redelegation type MsgBeginRedelegateInput struct { BaseReq BaseReq `json:"base_req"` DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 @@ -51,6 +55,7 @@ type MsgBeginRedelegateInput struct { SharesAmount sdk.Dec `json:"shares"` } +// PostProposalReq requests a proposals type PostProposalReq struct { BaseReq BaseReq `json:"base_req"` Title string `json:"title"` // Title of the proposal @@ -60,6 +65,7 @@ type PostProposalReq struct { InitialDeposit sdk.Coins `json:"initial_deposit"` // Coins to add to the proposal's deposit } +// DepositReq requests a deposit of an amount of coins type DepositReq struct { BaseReq BaseReq `json:"base_req"` Depositor sdk.AccAddress `json:"depositor"` // Address of the depositor @@ -91,26 +97,31 @@ type RecoverKeyBody struct { Index int `json:"index,string,omitempty"` } +// UpdateKeyReq requests updating a key type UpdateKeyReq struct { OldPassword string `json:"old_password"` NewPassword string `json:"new_password"` } +// DeleteKeyReq requests deleting a key type DeleteKeyReq struct { Password string `json:"password"` } +// BroadcastReq requests broadcasting a transaction type BroadcastReq struct { Tx auth.StdTx `json:"tx"` Return string `json:"return"` } +// VoteReq requests sending a vote type VoteReq struct { BaseReq BaseReq `json:"base_req"` Voter sdk.AccAddress `json:"voter"` // address of the voter Option string `json:"option"` // option from OptionSet chosen by the voter } +// UnjailReq request unjailing type UnjailReq struct { BaseReq BaseReq `json:"base_req"` } diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go index e732145e2a09..7cb3e22a2fa6 100644 --- a/x/ibc/client/rest/transfer.go +++ b/x/ibc/client/rest/transfer.go @@ -3,6 +3,8 @@ package rest import ( "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/codec" @@ -19,8 +21,8 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec, } type transferReq struct { - BaseReq utils.BaseReq `json:"base_req"` - Amount sdk.Coins `json:"amount"` + BaseReq client.BaseReq `json:"base_req"` + Amount sdk.Coins `json:"amount"` } // TransferRequestHandler - http request handler to transfer coins to a address @@ -44,7 +46,7 @@ func TransferRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context. } req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { + if !utils.ValidateBasic(w, req.BaseReq) { return } From 96ef7b4ccc68deb0c116d2cedd6932ac9c354ed3 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Fri, 1 Feb 2019 16:12:01 +0100 Subject: [PATCH 12/21] Unit test fix + removed warnings --- client/keys/add.go | 2 +- client/lcd/lcd_test.go | 2 +- cmd/gaia/cli_test/test_helpers.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/keys/add.go b/client/keys/add.go index 3c531ee16fd6..a8f6f7c58108 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -265,7 +265,7 @@ func printCreate(info keys.Info, showMnemonic bool, mnemonic string) error { switch output { case "text": - fmt.Println() + fmt.Fprintln(os.Stderr) printKeyInfo(info, Bech32KeyOutput) // print mnemonic unless requested not to. diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index d33070ef6eb9..34de9d4b7b68 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -374,7 +374,7 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) { payload := authrest.SignBody{ Tx: msg, - BaseReq: utils.NewBaseReq( + BaseReq: client.NewBaseReq( name1, pw, "", viper.GetString(client.FlagChainID), "", "", accnum, sequence, nil, nil, false, false, ), diff --git a/cmd/gaia/cli_test/test_helpers.go b/cmd/gaia/cli_test/test_helpers.go index 92c0880f1249..6790578a62ab 100644 --- a/cmd/gaia/cli_test/test_helpers.go +++ b/cmd/gaia/cli_test/test_helpers.go @@ -226,13 +226,13 @@ func (f *Fixtures) KeysAdd(name string, flags ...string) { executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass) } -// KeysAdd is gaiacli keys add --recover +// KeysAddRecover prepares gaiacli keys add --recover func (f *Fixtures) KeysAddRecover(name, mnemonic string, flags ...string) { cmd := fmt.Sprintf("gaiacli keys add --home=%s --recover %s", f.GCLIHome, name) executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic) } -// KeysAdd is gaiacli keys add --recover --account --index +// KeysAddRecoverHDPath prepares gaiacli keys add --recover --account --index func (f *Fixtures) KeysAddRecoverHDPath(name, mnemonic string, account uint32, index uint32, flags ...string) { cmd := fmt.Sprintf("gaiacli keys add --home=%s --recover %s --account %d --index %d", f.GCLIHome, name, account, index) executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic) From 88e8a57dff92b9cb2e0352342bcf284810c8f3e6 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Fri, 1 Feb 2019 20:03:52 +0100 Subject: [PATCH 13/21] fixing unit test --- client/keys/add.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/keys/add.go b/client/keys/add.go index a8f6f7c58108..e5c365575448 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -377,7 +377,8 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { return } - if _, tmpErr := kb.Get(m.Name); tmpErr != nil { + _, err = kb.Get(m.Name) + if err == nil { CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(m.Name)) return } @@ -467,7 +468,8 @@ func RecoverRequestHandler(indent bool) http.HandlerFunc { return } - if _, tmpErr := kb.Get(name); tmpErr != nil { + _, err = kb.Get(name) + if err == nil { CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(name)) return } From 0eb3f0477a13ab1a368748cac0adf596097a7f97 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Fri, 1 Feb 2019 21:35:46 +0100 Subject: [PATCH 14/21] unifying constants --- client/keys/add.go | 7 +++---- crypto/keys/keybase.go | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/client/keys/add.go b/client/keys/add.go index e5c365575448..f94bc8eef041 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -37,7 +37,6 @@ const ( ) const ( - defaultBIP39Passphrase = "" maxValidAccountValue = int(0x80000000 - 1) maxValidIndexalue = int(0x80000000 - 1) ) @@ -245,7 +244,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error { } } - info, err := kb.CreateAccount(name, mnemonic, defaultBIP39Passphrase, encryptPassword, account, index) + info, err := kb.CreateAccount(name, mnemonic, keys.DefaultBIP39Passphrase, encryptPassword, account, index) if err != nil { return err } @@ -386,7 +385,7 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { // create account account := uint32(m.Account) index := uint32(m.Index) - info, err := kb.CreateAccount(m.Name, mnemonic, defaultBIP39Passphrase, m.Password, account, index) + info, err := kb.CreateAccount(m.Name, mnemonic, keys.DefaultBIP39Passphrase, m.Password, account, index) if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } @@ -477,7 +476,7 @@ func RecoverRequestHandler(indent bool) http.HandlerFunc { account := uint32(m.Account) index := uint32(m.Index) - info, err := kb.CreateAccount(name, mnemonic, defaultBIP39Passphrase, m.Password, account, index) + info, err := kb.CreateAccount(name, mnemonic, keys.DefaultBIP39Passphrase, m.Password, account, index) if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index efaa0905cce1..635a62f772e5 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -54,7 +54,7 @@ const ( const ( // used for deriving seed from mnemonic - defaultBIP39Passphrase = "" + DefaultBIP39Passphrase = "" // bits of entropy to draw when creating a mnemonic defaultEntropySize = 256 @@ -109,7 +109,7 @@ func (kb dbKeybase) CreateMnemonic(name string, language Language, passwd string return } - seed := bip39.NewSeed(mnemonic, defaultBIP39Passphrase) + seed := bip39.NewSeed(mnemonic, DefaultBIP39Passphrase) info, err = kb.persistDerivedKey(seed, passwd, name, hd.FullFundraiserPath) return } From 095abc3b080aa22ada1a5d0a4bc28ae751c55468 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Sat, 2 Feb 2019 14:56:48 +0100 Subject: [PATCH 15/21] improving fmt --- client/keys/add.go | 4 ++-- crypto/ledger_test.go | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/client/keys/add.go b/client/keys/add.go index f94bc8eef041..ad7f2d38df5b 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -37,8 +37,8 @@ const ( ) const ( - maxValidAccountValue = int(0x80000000 - 1) - maxValidIndexalue = int(0x80000000 - 1) + maxValidAccountValue = int(0x80000000 - 1) + maxValidIndexalue = int(0x80000000 - 1) ) func addKeyCommand() *cobra.Command { diff --git a/crypto/ledger_test.go b/crypto/ledger_test.go index db49fb73eac2..cf14db74b583 100644 --- a/crypto/ledger_test.go +++ b/crypto/ledger_test.go @@ -2,10 +2,11 @@ package crypto import ( "fmt" - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "os" "testing" + "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/encoding/amino" ) From dd9a97f286ca865f3954632e6fb8da25206f4468 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Sat, 2 Feb 2019 15:33:39 +0100 Subject: [PATCH 16/21] Fixing issue introduced when rebasing --- client/utils/rest.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/utils/rest.go b/client/utils/rest.go index 56576927f33d..a9490564d33c 100644 --- a/client/utils/rest.go +++ b/client/utils/rest.go @@ -260,7 +260,8 @@ func PostProcessResponse(w http.ResponseWriter, cdc *codec.Codec, response inter } // WriteGenerateStdTxResponse writes response for the generate only mode. -func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec, br client.BaseReq, msgs []sdk.Msg) { +func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec, + cliCtx context.CLIContext, br client.BaseReq, msgs []sdk.Msg) { gasAdj, ok := ParseFloat64OrReturnBadRequest(w, br.GasAdjustment, client.DefaultGasAdjustment) if !ok { return From 65dbd0e3f938b33da8d6e7a21bc039e7a1fea887 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Sat, 2 Feb 2019 16:01:21 +0100 Subject: [PATCH 17/21] small fix --- crypto/keys/keybase_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index bc7783b67ce3..36a05d3741ff 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -344,7 +344,7 @@ func TestSeedPhrase(t *testing.T) { // let us re-create it from the mnemonic-phrase params := *hd.NewFundraiserParams(0, 0) - newInfo, err := cstore.Derive(n2, mnemonic, defaultBIP39Passphrase, p2, params) + newInfo, err := cstore.Derive(n2, mnemonic, DefaultBIP39Passphrase, p2, params) require.NoError(t, err) require.Equal(t, n2, newInfo.GetName()) require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) From a52e7c3628d88225779a2c948220613a206409e4 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Mon, 4 Feb 2019 07:30:08 +0100 Subject: [PATCH 18/21] Update mnemonic.go --- client/keys/mnemonic.go | 1 - 1 file changed, 1 deletion(-) diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index c75e3a4b8717..b5a528893585 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -57,7 +57,6 @@ func runMnemonicCmd(cmd *cobra.Command, args []string) error { // hash input entropy to get entropy seed hashedEntropy := sha256.Sum256([]byte(inputEntropy)) entropySeed = hashedEntropy[:] - fmt.Fprintf(os.Stderr, "-------------------------------------") } else { // read entropy seed straight from crypto.Rand var err error From 076185db2b7aa99c24032d9e010adfce94f8dfa3 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Mon, 4 Feb 2019 07:34:49 +0100 Subject: [PATCH 19/21] Update mnemonic.go --- client/keys/mnemonic.go | 1 - 1 file changed, 1 deletion(-) diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index b5a528893585..ffa72fff4097 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -3,7 +3,6 @@ package keys import ( "crypto/sha256" "fmt" - "os" bip39 "github.com/bartekn/go-bip39" "github.com/cosmos/cosmos-sdk/client" From 287fbba03abbc2a5e03142acbf06913f8c18088a Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Mon, 4 Feb 2019 18:32:07 +0100 Subject: [PATCH 20/21] Fixing merging problems + goimports --- client/keys/add.go | 4 +- client/keys/delete.go | 4 +- client/keys/types.go | 38 +++++++++ client/keys/utils.go | 9 -- client/lcd/lcd_test.go | 5 +- client/lcd/test_helpers.go | 64 +++++++-------- client/rest/types.go | 59 +++++++++++++ client/types.go | 155 ----------------------------------- x/auth/client/rest/sign.go | 3 +- x/bank/client/rest/sendtx.go | 2 +- x/gov/client/rest/rest.go | 6 +- x/slashing/client/rest/tx.go | 2 +- x/staking/client/rest/tx.go | 6 +- 13 files changed, 140 insertions(+), 217 deletions(-) create mode 100644 client/keys/types.go delete mode 100644 client/types.go diff --git a/client/keys/add.go b/client/keys/add.go index ad7f2d38df5b..ca5b58da4267 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -330,7 +330,7 @@ func CheckAndWriteErrorResponse(w http.ResponseWriter, httpErr int, err error) b func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var kb keys.Keybase - var m client.NewKeyBody + var m AddNewKey kb, err := GetKeyBaseWithWritePerm() if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { @@ -423,7 +423,7 @@ func RecoverRequestHandler(indent bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) name := vars["name"] - var m client.RecoverKeyBody + var m RecoverKey body, err := ioutil.ReadAll(r.Body) if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) { diff --git a/client/keys/delete.go b/client/keys/delete.go index 5f3ff4f095c4..0f8392270c06 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -13,8 +13,8 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client" - keys "github.com/cosmos/cosmos-sdk/crypto/keys" - keyerror "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" + "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keys/keyerror" "github.com/spf13/cobra" ) diff --git a/client/keys/types.go b/client/keys/types.go new file mode 100644 index 000000000000..d4a1032c2d13 --- /dev/null +++ b/client/keys/types.go @@ -0,0 +1,38 @@ +package keys + +// used for outputting keys.Info over REST +type KeyOutput struct { + Name string `json:"name"` + Type string `json:"type"` + Address string `json:"address"` + PubKey string `json:"pub_key"` + Mnemonic string `json:"mnemonic,omitempty"` +} + +// AddNewKey request a new key +type AddNewKey struct { + Name string `json:"name"` + Password string `json:"password"` + Mnemonic string `json:"mnemonic"` + Account int `json:"account,string,omitempty"` + Index int `json:"index,string,omitempty"` +} + +// RecoverKeyBody recovers a key +type RecoverKey struct { + Password string `json:"password"` + Mnemonic string `json:"mnemonic"` + Account int `json:"account,string,omitempty"` + Index int `json:"index,string,omitempty"` +} + +// UpdateKeyReq requests updating a key +type UpdateKeyReq struct { + OldPassword string `json:"old_password"` + NewPassword string `json:"new_password"` +} + +// DeleteKeyReq requests deleting a key +type DeleteKeyReq struct { + Password string `json:"password"` +} diff --git a/client/keys/utils.go b/client/keys/utils.go index 04aff72823d0..5f9bcfa59795 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -118,15 +118,6 @@ func SetKeyBase(kb keys.Keybase) { keybase = kb } -// used for outputting keys.Info over REST -type KeyOutput struct { - Name string `json:"name"` - Type string `json:"type"` - Address string `json:"address"` - PubKey string `json:"pub_key"` - Mnemonic string `json:"mnemonic,omitempty"` -} - // create a list of KeyOutput in bech32 format func Bech32KeysOutput(infos []keys.Info) ([]KeyOutput, error) { kos := make([]KeyOutput, len(infos)) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index a5715cab81ef..60909c9fc06f 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -12,13 +12,10 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/require" - ctypes "github.com/tendermint/tendermint/rpc/core/types" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/rest" "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/cmd/gaia/app" - "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" @@ -30,6 +27,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/staking" stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + ctypes "github.com/tendermint/tendermint/rpc/core/types" ) const ( diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 4c2fc27d4579..3465cba0e359 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -15,15 +15,6 @@ import ( "strings" "testing" - "github.com/tendermint/tendermint/crypto/secp256k1" - ctypes "github.com/tendermint/tendermint/rpc/core/types" - - cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys" - authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" - "github.com/cosmos/cosmos-sdk/x/gov" - "github.com/cosmos/cosmos-sdk/x/slashing" - stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/rest" @@ -32,12 +23,23 @@ import ( gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/codec" crkeys "github.com/cosmos/cosmos-sdk/crypto/keys" + cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" + authRest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" + authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" + txbuilder "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" + bankRest "github.com/cosmos/cosmos-sdk/x/bank/client/rest" + "github.com/cosmos/cosmos-sdk/x/gov" + govRest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils" + "github.com/cosmos/cosmos-sdk/x/slashing" + slashingRest "github.com/cosmos/cosmos-sdk/x/slashing/client/rest" "github.com/cosmos/cosmos-sdk/x/staking" + stakingRest "github.com/cosmos/cosmos-sdk/x/staking/client/rest" + stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/spf13/viper" "github.com/stretchr/testify/require" @@ -46,6 +48,7 @@ import ( tmcfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/tendermint/tendermint/libs/cli" dbm "github.com/tendermint/tendermint/libs/db" "github.com/tendermint/tendermint/libs/log" @@ -53,16 +56,9 @@ import ( "github.com/tendermint/tendermint/p2p" pvm "github.com/tendermint/tendermint/privval" "github.com/tendermint/tendermint/proxy" + ctypes "github.com/tendermint/tendermint/rpc/core/types" tmrpc "github.com/tendermint/tendermint/rpc/lib/server" tmtypes "github.com/tendermint/tendermint/types" - - txbuilder "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" - - authRest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" - bankRest "github.com/cosmos/cosmos-sdk/x/bank/client/rest" - govRest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" - slashingRest "github.com/cosmos/cosmos-sdk/x/slashing/client/rest" - stakingRest "github.com/cosmos/cosmos-sdk/x/staking/client/rest" ) // makePathname creates a unique pathname for each test. It will panic if it @@ -159,7 +155,7 @@ func CreateAddrs(t *testing.T, kb crkeys.Keybase, numAddrs int) (addrs []sdk.Acc password := "1234567890" info, seed, err = kb.CreateMnemonic(name, crkeys.English, password, crkeys.Secp256k1) require.NoError(t, err) - addrSeeds = append(addrSeeds, client.AddrSeed{Address: sdk.AccAddress(info.GetPubKey().Address()), Seed: seed, Name: name, Password: password}) + addrSeeds = append(addrSeeds, rest.AddrSeed{Address: sdk.AccAddress(info.GetPubKey().Address()), Seed: seed, Name: name, Password: password}) } sort.Sort(addrSeeds) @@ -175,7 +171,7 @@ func CreateAddrs(t *testing.T, kb crkeys.Keybase, numAddrs int) (addrs []sdk.Acc } // AddrSeedSlice implements `Interface` in sort package. -type AddrSeedSlice []client.AddrSeed +type AddrSeedSlice []rest.AddrSeed func (b AddrSeedSlice) Len() int { return len(b) @@ -532,7 +528,7 @@ func getKeys(t *testing.T, port string) []keys.KeyOutput { // POST /keys Create a new account locally func doKeysPost(t *testing.T, port, name, password, mnemonic string, account int, index int) keys.KeyOutput { - pk := client.NewKeyBody{name, password, mnemonic, account, index} + pk := keys.AddNewKey{name, password, mnemonic, account, index} req, err := cdc.MarshalJSON(pk) require.NoError(t, err) @@ -556,9 +552,9 @@ func getKeysSeed(t *testing.T, port string) string { return body } -// POST /keys/{name}/recover Recover a account from a seed +// POST /keys/{name}/recove Recover a account from a seed func doRecoverKey(t *testing.T, port, recoverName, recoverPassword, mnemonic string, account uint32, index uint32) { - pk := client.RecoverKeyBody{recoverPassword, mnemonic, int(account), int(index)} + pk := keys.RecoverKey{recoverPassword, mnemonic, int(account), int(index)} req, err := cdc.MarshalJSON(pk) require.NoError(t, err) @@ -586,7 +582,7 @@ func getKey(t *testing.T, port, name string) keys.KeyOutput { // PUT /keys/{name} Update the password for this account in the KMS func updateKey(t *testing.T, port, name, oldPassword, newPassword string, fail bool) { - kr := client.UpdateKeyReq{oldPassword, newPassword} + kr := keys.UpdateKeyReq{oldPassword, newPassword} req, err := cdc.MarshalJSON(kr) require.NoError(t, err) keyEndpoint := fmt.Sprintf("/keys/%s", name) @@ -600,7 +596,7 @@ func updateKey(t *testing.T, port, name, oldPassword, newPassword string, fail b // DELETE /keys/{name} Remove an account func deleteKey(t *testing.T, port, name, password string) { - dk := client.DeleteKeyReq{password} + dk := keys.DeleteKeyReq{password} req, err := cdc.MarshalJSON(dk) require.NoError(t, err) keyEndpoint := fmt.Sprintf("/keys/%s", name) @@ -641,7 +637,7 @@ func doSign(t *testing.T, port, name, password, chainID string, accnum, sequence // POST /tx/broadcast Send a signed Tx func doBroadcast(t *testing.T, port string, msg auth.StdTx) ctypes.ResultBroadcastTxCommit { - tx := client.BroadcastReq{Tx: msg, Return: "block"} + tx := rest.BroadcastReq{Tx: msg, Return: "block"} req, err := cdc.MarshalJSON(tx) require.Nil(t, err) res, body := Request(t, port, "POST", "/tx/broadcast", req) @@ -694,7 +690,7 @@ func doTransferWithGas( generateOnly, simulate, ) - sr := client.SendReq{ + sr := rest.SendReq{ Amount: sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 1)}, BaseReq: baseReq, } @@ -727,7 +723,7 @@ func doTransferWithGasAccAuto( fmt.Sprintf("%f", gasAdjustment), 0, 0, fees, nil, generateOnly, simulate, ) - sr := client.SendReq{ + sr := rest.SendReq{ Amount: sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 1)}, BaseReq: baseReq, } @@ -827,7 +823,7 @@ func doBeginRedelegation(t *testing.T, port, name, password string, chainID := viper.GetString(client.FlagChainID) baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) - msg := client.MsgBeginRedelegateInput{ + msg := rest.MsgBeginRedelegateInput{ BaseReq: baseReq, DelegatorAddr: delAddr, ValidatorSrcAddr: valSrcAddr, @@ -1058,7 +1054,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA chainID := viper.GetString(client.FlagChainID) baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) - pr := client.PostProposalReq{ + pr := rest.PostProposalReq{ Title: "Test", Description: "test", ProposalType: "Text", @@ -1154,7 +1150,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk chainID := viper.GetString(client.FlagChainID) baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) - dr := client.DepositReq{ + dr := rest.DepositReq{ Depositor: proposerAddr, Amount: sdk.Coins{sdk.NewCoin(stakingTypes.DefaultBondDenom, sdk.NewInt(amount))}, BaseReq: baseReq, @@ -1208,7 +1204,7 @@ func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.Ac chainID := viper.GetString(client.FlagChainID) baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false) - vr := client.VoteReq{ + vr := rest.VoteReq{ Voter: proposerAddr, Option: option, BaseReq: baseReq, @@ -1340,7 +1336,7 @@ func doUnjail(t *testing.T, port, seed, name, password string, chainID := viper.GetString(client.FlagChainID) baseReq := rest.NewBaseReq(name, password, "", chainID, "", "", 1, 1, fees, nil, false, false) - ur := client.UnjailReq{ + ur := rest.UnjailReq{ BaseReq: baseReq, } req, err := cdc.MarshalJSON(ur) @@ -1354,7 +1350,3 @@ func doUnjail(t *testing.T, port, seed, name, password string, return results[0] } - -type unjailReq struct { - BaseReq rest.BaseReq `json:"base_req"` -} diff --git a/client/rest/types.go b/client/rest/types.go index 113dc0650d02..f51e73b50e6b 100644 --- a/client/rest/types.go +++ b/client/rest/types.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" ) // GasEstimateResponse defines a response definition for tx gas estimation. @@ -124,3 +125,61 @@ func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req i return nil } + +// AddrSeed combines an Address with the mnemonic of the private key to that address +type AddrSeed struct { + Address sdk.AccAddress + Seed string + Name string + Password string +} + +// SendReq requests sending an amount of coins +type SendReq struct { + Amount sdk.Coins `json:"amount"` + BaseReq BaseReq `json:"base_req"` +} + +// MsgBeginRedelegateInput request to begin a redelegation +type MsgBeginRedelegateInput struct { + BaseReq BaseReq `json:"base_req"` + DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 + ValidatorSrcAddr sdk.ValAddress `json:"validator_src_addr"` // in bech32 + ValidatorDstAddr sdk.ValAddress `json:"validator_dst_addr"` // in bech32 + SharesAmount sdk.Dec `json:"shares"` +} + +// PostProposalReq requests a proposals +type PostProposalReq struct { + BaseReq BaseReq `json:"base_req"` + Title string `json:"title"` // Title of the proposal + Description string `json:"description"` // Description of the proposal + ProposalType string `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal} + Proposer sdk.AccAddress `json:"proposer"` // Address of the proposer + InitialDeposit sdk.Coins `json:"initial_deposit"` // Coins to add to the proposal's deposit +} + +// BroadcastReq requests broadcasting a transaction +type BroadcastReq struct { + Tx auth.StdTx `json:"tx"` + Return string `json:"return"` +} + +// DepositReq requests a deposit of an amount of coins +type DepositReq struct { + BaseReq BaseReq `json:"base_req"` + Depositor sdk.AccAddress `json:"depositor"` // Address of the depositor + Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit +} + +// VoteReq requests sending a vote +type VoteReq struct { + BaseReq BaseReq `json:"base_req"` + Voter sdk.AccAddress `json:"voter"` // address of the voter + Option string `json:"option"` // option from OptionSet chosen by the voter +} + +// UnjailReq request unjailing +type UnjailReq struct { + BaseReq BaseReq `json:"base_req"` +} diff --git a/client/types.go b/client/types.go deleted file mode 100644 index 4aae8efb6a52..000000000000 --- a/client/types.go +++ /dev/null @@ -1,155 +0,0 @@ -package client - -import ( - "strings" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" -) - -// BaseReq defines a structure that can be embedded in other request structures -// that all share common "base" fields. -type BaseReq struct { - From string `json:"from"` - Password string `json:"password"` - Memo string `json:"memo"` - ChainID string `json:"chain_id"` - AccountNumber uint64 `json:"account_number"` - Sequence uint64 `json:"sequence"` - Fees sdk.Coins `json:"fees"` - GasPrices sdk.DecCoins `json:"gas_prices"` - Gas string `json:"gas"` - GasAdjustment string `json:"gas_adjustment"` - GenerateOnly bool `json:"generate_only"` - Simulate bool `json:"simulate"` -} - -// SendReq requests sending an amount of coins -type SendReq struct { - Amount sdk.Coins `json:"amount"` - BaseReq BaseReq `json:"base_req"` -} - -// MsgDelegationsInput requests a delegation -type MsgDelegationsInput struct { - BaseReq BaseReq `json:"base_req"` - DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 - ValidatorAddr sdk.ValAddress `json:"validator_addr"` // in bech32 - Delegation sdk.Coin `json:"delegation"` -} - -// MsgUndelegateInput request an undelegation -type MsgUndelegateInput struct { - BaseReq BaseReq `json:"base_req"` - DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 - ValidatorAddr sdk.ValAddress `json:"validator_addr"` // in bech32 - SharesAmount sdk.Dec `json:"shares"` -} - -// MsgBeginRedelegateInput request to begin a redelegation -type MsgBeginRedelegateInput struct { - BaseReq BaseReq `json:"base_req"` - DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32 - ValidatorSrcAddr sdk.ValAddress `json:"validator_src_addr"` // in bech32 - ValidatorDstAddr sdk.ValAddress `json:"validator_dst_addr"` // in bech32 - SharesAmount sdk.Dec `json:"shares"` -} - -// PostProposalReq requests a proposals -type PostProposalReq struct { - BaseReq BaseReq `json:"base_req"` - Title string `json:"title"` // Title of the proposal - Description string `json:"description"` // Description of the proposal - ProposalType string `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal} - Proposer sdk.AccAddress `json:"proposer"` // Address of the proposer - InitialDeposit sdk.Coins `json:"initial_deposit"` // Coins to add to the proposal's deposit -} - -// DepositReq requests a deposit of an amount of coins -type DepositReq struct { - BaseReq BaseReq `json:"base_req"` - Depositor sdk.AccAddress `json:"depositor"` // Address of the depositor - Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit -} - -// AddrSeed combines an Address with the mnemonic of the private key to that address -type AddrSeed struct { - Address sdk.AccAddress - Seed string - Name string - Password string -} - -// NewKeyBody request a new key -type NewKeyBody struct { - Name string `json:"name"` - Password string `json:"password"` - Mnemonic string `json:"mnemonic"` - Account int `json:"account,string,omitempty"` - Index int `json:"index,string,omitempty"` -} - -// RecoverKeyBody recovers a key -type RecoverKeyBody struct { - Password string `json:"password"` - Mnemonic string `json:"mnemonic"` - Account int `json:"account,string,omitempty"` - Index int `json:"index,string,omitempty"` -} - -// UpdateKeyReq requests updating a key -type UpdateKeyReq struct { - OldPassword string `json:"old_password"` - NewPassword string `json:"new_password"` -} - -// DeleteKeyReq requests deleting a key -type DeleteKeyReq struct { - Password string `json:"password"` -} - -// BroadcastReq requests broadcasting a transaction -type BroadcastReq struct { - Tx auth.StdTx `json:"tx"` - Return string `json:"return"` -} - -// VoteReq requests sending a vote -type VoteReq struct { - BaseReq BaseReq `json:"base_req"` - Voter sdk.AccAddress `json:"voter"` // address of the voter - Option string `json:"option"` // option from OptionSet chosen by the voter -} - -// UnjailReq request unjailing -type UnjailReq struct { - BaseReq BaseReq `json:"base_req"` -} - -// NewBaseReq creates a new basic request instance and sanitizes its values -func NewBaseReq(from, password, memo, chainID string, gas, gasAdjustment string, - accNumber, seq uint64, fees sdk.Coins, gasPrices sdk.DecCoins, genOnly, simulate bool, -) BaseReq { - return BaseReq{ - From: strings.TrimSpace(from), - Password: password, - Memo: strings.TrimSpace(memo), - ChainID: strings.TrimSpace(chainID), - Fees: fees, - GasPrices: gasPrices, - Gas: strings.TrimSpace(gas), - GasAdjustment: strings.TrimSpace(gasAdjustment), - AccountNumber: accNumber, - Sequence: seq, - GenerateOnly: genOnly, - Simulate: simulate, - } -} - -// Sanitize performs basic sanitization on a BaseReq object. -func (br BaseReq) Sanitize() BaseReq { - return NewBaseReq( - br.From, br.Password, br.Memo, br.ChainID, br.Gas, br.GasAdjustment, - br.AccountNumber, br.Sequence, br.Fees, br.GasPrices, br.GenerateOnly, br.Simulate, - ) -} diff --git a/x/auth/client/rest/sign.go b/x/auth/client/rest/sign.go index aa8ff6a6a441..50ec660552fa 100644 --- a/x/auth/client/rest/sign.go +++ b/x/auth/client/rest/sign.go @@ -3,7 +3,6 @@ package rest import ( "net/http" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/rest" "github.com/cosmos/cosmos-sdk/client/utils" @@ -32,7 +31,7 @@ func SignTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha return } - if !utils.ValidateBasic(w, m.BaseReq) { + if !m.BaseReq.ValidateBasic(w) { return } diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index 4e75f0c01f48..70aae05fccc0 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -51,7 +51,7 @@ func SendRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIC } req.BaseReq = req.BaseReq.Sanitize() - if !utils.ValidateBasic(w, req.BaseReq) { + if !req.BaseReq.ValidateBasic(w) { return } diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index a12482f47172..e37f7870ecca 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -84,7 +84,7 @@ func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han } req.BaseReq = req.BaseReq.Sanitize() - if !utils.ValidateBasic(w, req.BaseReq) { + if !req.BaseReq.ValidateBasic(w) { return } @@ -134,7 +134,7 @@ func depositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerF } req.BaseReq = req.BaseReq.Sanitize() - if !utils.ValidateBasic(w, req.BaseReq) { + if !req.BaseReq.ValidateBasic(w) { return } @@ -178,7 +178,7 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc } req.BaseReq = req.BaseReq.Sanitize() - if !utils.ValidateBasic(w, req.BaseReq) { + if !req.BaseReq.ValidateBasic(w) { return } diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index d2aa7e1e357f..edbfaec92a2b 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -40,7 +40,7 @@ func unjailRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CL } req.BaseReq = req.BaseReq.Sanitize() - if !utils.ValidateBasic(w, req.BaseReq) { + if !req.BaseReq.ValidateBasic(w) { return } diff --git a/x/staking/client/rest/tx.go b/x/staking/client/rest/tx.go index 72ae3452541b..397e61a73370 100644 --- a/x/staking/client/rest/tx.go +++ b/x/staking/client/rest/tx.go @@ -65,7 +65,7 @@ func postDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context. } req.BaseReq = req.BaseReq.Sanitize() - if !utils.ValidateBasic(w, req.BaseReq) { + if !req.BaseReq.ValidateBasic(w) { return } @@ -110,7 +110,7 @@ func postRedelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx contex } req.BaseReq = req.BaseReq.Sanitize() - if !utils.ValidateBasic(w, req.BaseReq) { + if !req.BaseReq.ValidateBasic(w) { return } @@ -155,7 +155,7 @@ func postUnbondingDelegationsHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx } req.BaseReq = req.BaseReq.Sanitize() - if !utils.ValidateBasic(w, req.BaseReq) { + if !req.BaseReq.ValidateBasic(w) { return } From f1f44b762406bdd6977ef29f11b18204c40867cd Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Mon, 4 Feb 2019 18:37:34 +0100 Subject: [PATCH 21/21] fixing small issue --- x/ibc/client/rest/transfer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go index 246fa76710e9..fd35764b0dbf 100644 --- a/x/ibc/client/rest/transfer.go +++ b/x/ibc/client/rest/transfer.go @@ -45,7 +45,7 @@ func TransferRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context. } req.BaseReq = req.BaseReq.Sanitize() - if !utils.ValidateBasic(w, req.BaseReq) { + if !req.BaseReq.ValidateBasic(w) { return }