From ae919727e91aedb8e3831900eccd9ec3cb9075a8 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Fri, 17 Aug 2018 02:07:14 -0700 Subject: [PATCH 01/12] Allow --from to be a name or an address Closes #1735. --- PENDING.md | 1 + client/context/context.go | 26 ++++++++++---------- client/context/query.go | 48 ++++++++++++++++++++++++++++++------- client/flags.go | 2 +- client/utils/utils.go | 8 +++++-- crypto/keys/keybase.go | 28 +++++++++++++++++++++- crypto/keys/keybase_test.go | 19 ++++++++++++++- crypto/keys/types.go | 2 ++ x/ibc/client/cli/relay.go | 13 ++++++++-- 9 files changed, 120 insertions(+), 27 deletions(-) diff --git a/PENDING.md b/PENDING.md index f45541ccdc19..ec06c90ccbdb 100644 --- a/PENDING.md +++ b/PENDING.md @@ -13,6 +13,7 @@ BREAKING CHANGES * [cli] \#2061 changed proposalID in governance REST endpoints to proposal-id * [cli] \#2014 `gaiacli advanced` no longer exists - to access `ibc`, `rest-server`, and `validator-set` commands use `gaiacli ibc`, `gaiacli rest-server`, and `gaiacli tendermint`, respectively * [makefile] `get_vendor_deps` no longer updates lock file it just updates vendor directory. Use `update_vendor_deps` to update the lock file. [#2152](https://github.com/cosmos/cosmos-sdk/pull/2152) + * [cli] \#2073 --from can now be either an address or a key name * Gaia * Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013) diff --git a/client/context/context.go b/client/context/context.go index 743c923552c8..37476e90a00a 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/viper" rpcclient "github.com/tendermint/tendermint/rpc/client" + "github.com/cosmos/cosmos-sdk/types" ) const ctxAccStoreName = "acc" @@ -32,6 +33,8 @@ type CLIContext struct { Async bool JSON bool PrintResponse bool +fromAddress types.AccAddress + fromName stringz } // NewCLIContext returns a new initialized CLIContext with parameters from the @@ -45,18 +48,18 @@ func NewCLIContext() CLIContext { } return CLIContext{ - Client: rpc, - NodeURI: nodeURI, - AccountStore: ctxAccStoreName, + Client: rpc, + NodeURI: nodeURI, + AccountStore: ctxAccStoreName, FromAddressName: viper.GetString(client.FlagFrom), Height: viper.GetInt64(client.FlagHeight), Gas: viper.GetInt64(client.FlagGas), GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment), - TrustNode: viper.GetBool(client.FlagTrustNode), - UseLedger: viper.GetBool(client.FlagUseLedger), - Async: viper.GetBool(client.FlagAsync), - JSON: viper.GetBool(client.FlagJson), - PrintResponse: viper.GetBool(client.FlagPrintResponse), + TrustNode: viper.GetBool(client.FlagTrustNode), + UseLedger: viper.GetBool(client.FlagUseLedger), + Async: viper.GetBool(client.FlagAsync), + JSON: viper.GetBool(client.FlagJson), + PrintResponse: viper.GetBool(client.FlagPrintResponse), } } @@ -85,10 +88,9 @@ func (ctx CLIContext) WithAccountStore(accountStore string) CLIContext { return ctx } -// WithFromAddressName returns a copy of the context with an updated from -// address. -func (ctx CLIContext) WithFromAddressName(addrName string) CLIContext { - ctx.FromAddressName = addrName +// WithFrom returns a copy of the context with an updated from address. +func (ctx CLIContext) WithFrom(addrName string) CLIContext { + ctx.From = addrName return ctx } diff --git a/client/context/query.go b/client/context/query.go index e526c0abbc90..6bb074bb6577 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -13,6 +13,7 @@ import ( cmn "github.com/tendermint/tendermint/libs/common" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" + cskeys "github.com/cosmos/cosmos-sdk/crypto/keys" ) // GetNode returns an RPC client. If the context's client is not defined, an @@ -76,22 +77,53 @@ func (ctx CLIContext) GetAccount(address []byte) (auth.Account, error) { } // GetFromAddress returns the from address from the context's name. -func (ctx CLIContext) GetFromAddress() (from sdk.AccAddress, err error) { - if ctx.FromAddressName == "" { - return nil, errors.Errorf("must provide a from address name") +func (ctx CLIContext) GetFromAddress() (sdk.AccAddress, error) { + if ctx.fromAddress == nil { + if err := ctx.populateFromFields(); err != nil { + return nil, err + } + } + + return ctx.fromAddress, nil +} + +// GetFromname returns the key name for the current context. +func (ctx CLIContext) GetFromName() (string, error) { + if ctx.fromName == "" { + if err := ctx.populateFromFields(); err != nil { + return "", err + } + } + + return ctx.fromName, nil +} + +func (ctx CLIContext) populateFromFields() error { + if ctx.From == "" { + return errors.Errorf("must provide a from address or name") } keybase, err := keys.GetKeyBase() if err != nil { - return nil, err + return err } - info, err := keybase.Get(ctx.FromAddressName) - if err != nil { - return nil, errors.Errorf("no key for: %s", ctx.FromAddressName) + var info cskeys.Info + if addr, err := sdk.AccAddressFromBech32(ctx.From); err == nil { + info, err = keybase.GetByAddress(addr) + if err != nil { + return err + } + } else { + info, err = keybase.Get(ctx.From) + if err != nil { + return err + } } - return sdk.AccAddress(info.GetPubKey().Address()), nil + ctx.fromAddress = (sdk.AccAddress)(info.GetPubKey().Address()) + ctx.fromName = info.GetName() + return nil } // GetAccountNumber returns the next account number for the given account diff --git a/client/flags.go b/client/flags.go index 81e06706784a..4cfae01a414d 100644 --- a/client/flags.go +++ b/client/flags.go @@ -45,7 +45,7 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command { // PostCommands adds common flags for commands to post tx func PostCommands(cmds ...*cobra.Command) []*cobra.Command { for _, c := range cmds { - c.Flags().String(FlagFrom, "", "Name of private key with which to sign") + c.Flags().String(FlagFrom, "", "Name or address of private key with which to sign") c.Flags().Int64(FlagAccountNumber, 0, "AccountNumber number to sign the tx") c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx") c.Flags().String(FlagMemo, "", "Memo to send along with transaction") diff --git a/client/utils/utils.go b/client/utils/utils.go index fb5d6198871d..35d0a775a712 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -54,7 +54,11 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) txCtx = txCtx.WithSequence(accSeq) } - passphrase, err := keys.GetPassphrase(cliCtx.FromAddressName) + name, err := cliCtx.GetFromName() + if err != nil { + return err + } + passphrase, err := keys.GetPassphrase(name) if err != nil { return err } @@ -67,7 +71,7 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) } // build and sign the transaction - txBytes, err := txCtx.BuildAndSign(cliCtx.FromAddressName, passphrase, msgs) + txBytes, err := txCtx.BuildAndSign(name, passphrase, msgs) if err != nil { return err } diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index ae036362e381..a9b321664def 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -14,6 +14,7 @@ import ( "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/types" ) var _ Keybase = dbKeybase{} @@ -179,6 +180,12 @@ func (kb dbKeybase) List() ([]Info, error) { iter := kb.db.Iterator(nil, nil) defer iter.Close() for ; iter.Valid(); iter.Next() { + key := string(iter.Key()) + + if strings.HasSuffix(key, ".address") { + continue + } + info, err := readInfo(iter.Value()) if err != nil { return nil, err @@ -197,6 +204,15 @@ func (kb dbKeybase) Get(name string) (Info, error) { return readInfo(bs) } +func (kb dbKeybase) GetByAddress(address types.AccAddress) (Info, error) { + ik := kb.db.Get(addrKey((tmcrypto.Address)(address))) + if len(ik) == 0 { + return nil, fmt.Errorf("Key with address %s not found", address.String()) + } + bs := kb.db.Get(ik) + return readInfo(bs) +} + // Sign signs the msg with the named key. // It returns an error if the key doesn't exist or the decryption fails. func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub tmcrypto.PubKey, err error) { @@ -341,6 +357,7 @@ func (kb dbKeybase) Delete(name, passphrase string) error { if err != nil { return err } + kb.db.DeleteSync(addrKey(linfo.GetPubKey().Address())) kb.db.DeleteSync(infoKey(name)) return nil case ledgerInfo: @@ -348,9 +365,11 @@ func (kb dbKeybase) Delete(name, passphrase string) error { if passphrase != "yes" { return fmt.Errorf("enter 'yes' exactly to delete the key - this cannot be undone") } + kb.db.DeleteSync(addrKey(info.GetPubKey().Address())) kb.db.DeleteSync(infoKey(name)) return nil } + return nil } @@ -407,7 +426,14 @@ func (kb dbKeybase) writeOfflineKey(pub tmcrypto.PubKey, name string) Info { func (kb dbKeybase) writeInfo(info Info, name string) { // write the info by key - kb.db.SetSync(infoKey(name), writeInfo(info)) + key := infoKey(name) + kb.db.SetSync(key, writeInfo(info)) + // store a pointer to the infokey by address for fast lookup + kb.db.SetSync(addrKey(info.GetPubKey().Address()), key) +} + +func addrKey(address tmcrypto.Address) []byte { + return []byte(fmt.Sprintf("%s.address", address.String())) } func infoKey(name string) []byte { diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index 652a36bcb02f..327403470a7b 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -11,6 +11,7 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" dbm "github.com/tendermint/tendermint/libs/db" + "github.com/cosmos/cosmos-sdk/types" ) func init() { @@ -20,8 +21,9 @@ func init() { // TestKeyManagement makes sure we can manipulate these keys well func TestKeyManagement(t *testing.T) { // make the storage with reasonable defaults + db := dbm.NewMemDB() cstore := New( - dbm.NewMemDB(), + db, ) algo := Secp256k1 @@ -51,6 +53,12 @@ func TestKeyManagement(t *testing.T) { require.NoError(t, err) _, err = cstore.Get(n3) require.NotNil(t, err) + _, err = cstore.GetByAddress(accAddr(i2)) + require.NoError(t, err) + addr, err := types.AccAddressFromBech32("cosmosaccaddr1jawd35d9aq4u76sr3fjalmcqc8hqygs9gtnmv3") + require.NoError(t, err) + _, err = cstore.GetByAddress(addr) + require.NotNil(t, err) // list shows them in order keyS, err := cstore.List() @@ -92,6 +100,11 @@ func TestKeyManagement(t *testing.T) { keyS, err = cstore.List() require.NoError(t, err) require.Equal(t, 1, len(keyS)) + + // addr cache gets nuked + err = cstore.Delete(n2, p2) + require.NoError(t, err) + require.False(t, db.Has(addrKey(i2.GetPubKey().Address()))) } // TestSignVerify does some detailed checks on how we sign and validate @@ -387,3 +400,7 @@ func ExampleNew() { // Carl // signed by Bob } + +func accAddr(info Info) types.AccAddress { + return (types.AccAddress)(info.GetPubKey().Address()) +} \ No newline at end of file diff --git a/crypto/keys/types.go b/crypto/keys/types.go index a68626489707..8af83a0cb51e 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -5,6 +5,7 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/cosmos/cosmos-sdk/types" ) // Keybase exposes operations on a generic keystore @@ -13,6 +14,7 @@ type Keybase interface { // CRUD on the keystore List() ([]Info, error) Get(name string) (Info, error) + GetByAddress(address types.AccAddress) (Info, error) Delete(name, passphrase string) error // Sign some bytes, looking up the private key to use diff --git a/x/ibc/client/cli/relay.go b/x/ibc/client/cli/relay.go index 92b03a66fcbb..8f150cac4661 100644 --- a/x/ibc/client/cli/relay.go +++ b/x/ibc/client/cli/relay.go @@ -95,7 +95,11 @@ func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) { func (c relayCommander) loop(fromChainID, fromChainNode, toChainID, toChainNode string) { cliCtx := context.NewCLIContext() - passphrase, err := keys.ReadPassphraseFromStdin(cliCtx.FromAddressName) + name, err := cliCtx.GetFromName() + if err != nil { + panic(err) + } + passphrase, err := keys.ReadPassphraseFromStdin(name) if err != nil { panic(err) } @@ -201,7 +205,12 @@ func (c relayCommander) refine(bz []byte, sequence int64, passphrase string) []b txCtx := authctx.NewTxContextFromCLI().WithSequence(sequence).WithCodec(c.cdc) cliCtx := context.NewCLIContext() - res, err := txCtx.BuildAndSign(cliCtx.FromAddressName, passphrase, []sdk.Msg{msg}) + name, err := cliCtx.GetFromName() + if err != nil { + panic(err) + } + + res, err := txCtx.BuildAndSign(name, passphrase, []sdk.Msg{msg}) if err != nil { panic(err) } From cd1cb1598e1708ab24f51ae8bd1fec63a956f69d Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Thu, 30 Aug 2018 01:25:59 -0700 Subject: [PATCH 02/12] Post-rebase fixes --- client/context/context.go | 42 +++++++++++++++++++-------------------- client/utils/utils.go | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index 37476e90a00a..93d64ce7f0b5 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -18,23 +18,23 @@ const ctxAccStoreName = "acc" // CLIContext implements a typical CLI context created in SDK modules for // transaction handling and queries. type CLIContext struct { - Codec *wire.Codec - AccDecoder auth.AccountDecoder - Client rpcclient.Client - Logger io.Writer - Height int64 - Gas int64 - GasAdjustment float64 - NodeURI string - FromAddressName string - AccountStore string - TrustNode bool - UseLedger bool - Async bool - JSON bool - PrintResponse bool -fromAddress types.AccAddress - fromName stringz + Codec *wire.Codec + AccDecoder auth.AccountDecoder + Client rpcclient.Client + Logger io.Writer + Height int64 + Gas int64 + GasAdjustment float64 + NodeURI string + From string + AccountStore string + TrustNode bool + UseLedger bool + Async bool + JSON bool + PrintResponse bool + fromAddress types.AccAddress + fromName string } // NewCLIContext returns a new initialized CLIContext with parameters from the @@ -51,10 +51,10 @@ func NewCLIContext() CLIContext { Client: rpc, NodeURI: nodeURI, AccountStore: ctxAccStoreName, - FromAddressName: viper.GetString(client.FlagFrom), - Height: viper.GetInt64(client.FlagHeight), - Gas: viper.GetInt64(client.FlagGas), - GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment), + From: viper.GetString(client.FlagFrom), + Height: viper.GetInt64(client.FlagHeight), + Gas: viper.GetInt64(client.FlagGas), + GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment), TrustNode: viper.GetBool(client.FlagTrustNode), UseLedger: viper.GetBool(client.FlagUseLedger), Async: viper.GetBool(client.FlagAsync), diff --git a/client/utils/utils.go b/client/utils/utils.go index 35d0a775a712..f61e9a0bd132 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -64,7 +64,7 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) } if cliCtx.Gas == 0 { - txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, passphrase, msgs) + txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, name, passphrase, msgs) if err != nil { return err } From b904fd5c3d693b4dabcd1c2a1c8e0530ab80a491 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Thu, 30 Aug 2018 01:28:12 -0700 Subject: [PATCH 03/12] Updates from code review --- client/context/context.go | 6 +++--- crypto/keys/keybase.go | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index 93d64ce7f0b5..311386ae966a 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -88,9 +88,9 @@ func (ctx CLIContext) WithAccountStore(accountStore string) CLIContext { return ctx } -// WithFrom returns a copy of the context with an updated from address. -func (ctx CLIContext) WithFrom(addrName string) CLIContext { - ctx.From = addrName +// WithFrom returns a copy of the context with an updated from address orname. +func (ctx CLIContext) WithFrom(from string) CLIContext { + ctx.From = from return ctx } diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index a9b321664def..bfe233b70781 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -182,6 +182,7 @@ func (kb dbKeybase) List() ([]Info, error) { for ; iter.Valid(); iter.Next() { key := string(iter.Key()) + // need to exclude any keys in storage that have an address suffix if strings.HasSuffix(key, ".address") { continue } From ac4bc2aaabf794f571113abad4628b22e00dc4c9 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Thu, 30 Aug 2018 01:41:59 -0700 Subject: [PATCH 04/12] Updates from code review --- client/context/context.go | 2 +- client/utils/utils.go | 50 +++++++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index 311386ae966a..89a1b25f09ba 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -88,7 +88,7 @@ func (ctx CLIContext) WithAccountStore(accountStore string) CLIContext { return ctx } -// WithFrom returns a copy of the context with an updated from address orname. +// WithFrom returns a copy of the context with an updated from address or name. func (ctx CLIContext) WithFrom(from string) CLIContext { ctx.From = from return ctx diff --git a/client/utils/utils.go b/client/utils/utils.go index f61e9a0bd132..ed038c21b898 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -32,27 +32,11 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) return err } - // TODO: (ref #1903) Allow for user supplied account number without - // automatically doing a manual lookup. - if txCtx.AccountNumber == 0 { - accNum, err := cliCtx.GetAccountNumber(from) - if err != nil { - return err - } - - txCtx = txCtx.WithAccountNumber(accNum) - } - - // TODO: (ref #1903) Allow for user supplied account sequence without - // automatically doing a manual lookup. - if txCtx.Sequence == 0 { - accSeq, err := cliCtx.GetAccountSequence(from) - if err != nil { - return err - } - - txCtx = txCtx.WithSequence(accSeq) + txCtxPtr, err := lookupTxCtx(txCtx, cliCtx, from) + if err != nil { + return err } + txCtx = *txCtxPtr name, err := cliCtx.GetFromName() if err != nil { @@ -79,6 +63,32 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) return cliCtx.EnsureBroadcastTx(txBytes) } +func lookupTxCtx(txCtx authctx.TxContext, cliCtx context.CLIContext, from []byte) (*authctx.TxContext, error) { + // TODO: (ref #1903) Allow for user supplied account number without + // automatically doing a manual lookup. + if txCtx.AccountNumber == 0 { + accNum, err := cliCtx.GetAccountNumber(from) + if err != nil { + return nil, err + } + + txCtx = txCtx.WithAccountNumber(accNum) + } + + // TODO: (ref #1903) Allow for user supplied account sequence without + // automatically doing a manual lookup. + if txCtx.Sequence == 0 { + accSeq, err := cliCtx.GetAccountSequence(from) + if err != nil { + return nil, err + } + + txCtx = txCtx.WithSequence(accSeq) + } + + return &txCtx, nil +} + // EnrichCtxWithGas calculates the gas estimate that would be consumed by the // transaction and set the transaction's respective value accordingly. func EnrichCtxWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name, passphrase string, msgs []sdk.Msg) (authctx.TxContext, error) { From 81df6f410be4b4a8e639338bcbacd7e60347bc8b Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Fri, 7 Sep 2018 09:25:49 -0700 Subject: [PATCH 05/12] Updates from code review --- client/context/query.go | 4 ++-- client/utils/utils.go | 11 +++++------ crypto/keys/keybase.go | 24 ++++++++++++------------ 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 6bb074bb6577..2d3d0da03629 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -13,7 +13,7 @@ import ( cmn "github.com/tendermint/tendermint/libs/common" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" - cskeys "github.com/cosmos/cosmos-sdk/crypto/keys" + cskeys "github.com/cosmos/cosmos-sdk/crypto/keys" ) // GetNode returns an RPC client. If the context's client is not defined, an @@ -87,7 +87,7 @@ func (ctx CLIContext) GetFromAddress() (sdk.AccAddress, error) { return ctx.fromAddress, nil } -// GetFromname returns the key name for the current context. +// GetFromName returns the key name for the current context. func (ctx CLIContext) GetFromName() (string, error) { if ctx.fromName == "" { if err := ctx.populateFromFields(); err != nil { diff --git a/client/utils/utils.go b/client/utils/utils.go index ed038c21b898..92f6196ba027 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -32,11 +32,10 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) return err } - txCtxPtr, err := lookupTxCtx(txCtx, cliCtx, from) + txCtx, err = lookupTxCtx(txCtx, cliCtx, from) if err != nil { return err } - txCtx = *txCtxPtr name, err := cliCtx.GetFromName() if err != nil { @@ -63,13 +62,13 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) return cliCtx.EnsureBroadcastTx(txBytes) } -func lookupTxCtx(txCtx authctx.TxContext, cliCtx context.CLIContext, from []byte) (*authctx.TxContext, error) { +func lookupTxCtx(txCtx authctx.TxContext, cliCtx context.CLIContext, from []byte) (authctx.TxContext, error) { // TODO: (ref #1903) Allow for user supplied account number without // automatically doing a manual lookup. if txCtx.AccountNumber == 0 { accNum, err := cliCtx.GetAccountNumber(from) if err != nil { - return nil, err + return txCtx, err } txCtx = txCtx.WithAccountNumber(accNum) @@ -80,13 +79,13 @@ func lookupTxCtx(txCtx authctx.TxContext, cliCtx context.CLIContext, from []byte if txCtx.Sequence == 0 { accSeq, err := cliCtx.GetAccountSequence(from) if err != nil { - return nil, err + return txCtx, err } txCtx = txCtx.WithSequence(accSeq) } - return &txCtx, nil + return txCtx, nil } // EnrichCtxWithGas calculates the gas estimate that would be consumed by the diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index bfe233b70781..2055d499def8 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -42,6 +42,8 @@ const ( French // Italian is currently not supported. Italian + addressSuffix = "address" + infoSuffix = "info" ) var ( @@ -182,16 +184,14 @@ func (kb dbKeybase) List() ([]Info, error) { for ; iter.Valid(); iter.Next() { key := string(iter.Key()) - // need to exclude any keys in storage that have an address suffix - if strings.HasSuffix(key, ".address") { - continue + // need to include only keys in storage that have an info suffix + if strings.HasSuffix(key, infoSuffix) { + info, err := readInfo(iter.Value()) + if err != nil { + return nil, err + } + res = append(res, info) } - - info, err := readInfo(iter.Value()) - if err != nil { - return nil, err - } - res = append(res, info) } return res, nil } @@ -208,7 +208,7 @@ func (kb dbKeybase) Get(name string) (Info, error) { func (kb dbKeybase) GetByAddress(address types.AccAddress) (Info, error) { ik := kb.db.Get(addrKey((tmcrypto.Address)(address))) if len(ik) == 0 { - return nil, fmt.Errorf("Key with address %s not found", address.String()) + return nil, fmt.Errorf("key with address %s not found", address.String()) } bs := kb.db.Get(ik) return readInfo(bs) @@ -434,9 +434,9 @@ func (kb dbKeybase) writeInfo(info Info, name string) { } func addrKey(address tmcrypto.Address) []byte { - return []byte(fmt.Sprintf("%s.address", address.String())) + return []byte(fmt.Sprintf("%s.%s", address.String(), addressSuffix)) } func infoKey(name string) []byte { - return []byte(fmt.Sprintf("%s.info", name)) + return []byte(fmt.Sprintf("%s.%s", name, infoSuffix)) } From 1ee14d5c708a9e68ef2892c997b34dd0cb3da0a8 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Fri, 7 Sep 2018 09:31:22 -0700 Subject: [PATCH 06/12] Fix merge artifacts --- client/utils/utils.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/client/utils/utils.go b/client/utils/utils.go index 554406b4aa4f..c4afda828eaf 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -24,9 +24,15 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) if err != nil { return err } + + name, err := cliCtx.GetFromName() + if err != nil { + return err + } + autogas := cliCtx.DryRun || (cliCtx.Gas == 0) if autogas { - txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, msgs) + txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, name, msgs) if err != nil { return err } @@ -36,13 +42,13 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) return nil } - passphrase, err := keys.GetPassphrase(cliCtx.FromAddressName) + passphrase, err := keys.GetPassphrase(name) if err != nil { return err } // build and sign the transaction - txBytes, err := txCtx.BuildAndSign(cliCtx.FromAddressName, passphrase, msgs) + txBytes, err := txCtx.BuildAndSign(name, passphrase, msgs) if err != nil { return err } @@ -195,7 +201,12 @@ func buildUnsignedStdTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs return } if txCtx.Gas == 0 { - txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, msgs) + var name string + name, err = cliCtx.GetFromName() + if err != nil { + return + } + txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, name, msgs) if err != nil { return } From e0261642d4a517f159353b1066ead4e587935a76 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Sun, 9 Sep 2018 05:15:25 -0700 Subject: [PATCH 07/12] Fix merge conflicts --- PENDING.md | 3 --- client/context/context.go | 42 +++++++++++++++++++-------------------- client/utils/utils.go | 12 +++++------ 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/PENDING.md b/PENDING.md index cea237f3fe5e..45cda0cd513b 100644 --- a/PENDING.md +++ b/PENDING.md @@ -17,9 +17,6 @@ BREAKING CHANGES utilize a validator's operator address must now use the new Bech32 prefix, `cosmosvaloper`. * [cli] [\#2190](https://github.com/cosmos/cosmos-sdk/issues/2190) `gaiacli init --gen-txs` is now `gaiacli init --with-txs` to reduce confusion - * [\#2040](https://github.com/cosmos/cosmos-sdk/issues/2040) All commands that utilize a validator's address must now use the new - bech32 prefix, `cosmosval`. A validator's Tendermint signing key and address - now use a new bech32 prefix, `cosmoscons`. * [cli] \#2073 --from can now be either an address or a key name diff --git a/client/context/context.go b/client/context/context.go index e3b553ac4e79..516169a121ce 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -23,24 +23,24 @@ const ctxAccStoreName = "acc" // CLIContext implements a typical CLI context created in SDK modules for // transaction handling and queries. type CLIContext struct { - Codec *wire.Codec - AccDecoder auth.AccountDecoder - Client rpcclient.Client - Logger io.Writer - Height int64 - Gas int64 - GasAdjustment float64 - NodeURI string - From string - AccountStore string - TrustNode bool - UseLedger bool - Async bool - JSON bool - PrintResponse bool - Certifier tmlite.Certifier - DryRun bool - GenerateOnly bool + Codec *wire.Codec + AccDecoder auth.AccountDecoder + Client rpcclient.Client + Logger io.Writer + Height int64 + Gas int64 + GasAdjustment float64 + NodeURI string + From string + AccountStore string + TrustNode bool + UseLedger bool + Async bool + JSON bool + PrintResponse bool + Certifier tmlite.Certifier + DryRun bool + GenerateOnly bool fromAddress types.AccAddress fromName string } @@ -68,9 +68,9 @@ func NewCLIContext() CLIContext { Async: viper.GetBool(client.FlagAsync), JSON: viper.GetBool(client.FlagJson), PrintResponse: viper.GetBool(client.FlagPrintResponse), - Certifier: createCertifier(), - DryRun: viper.GetBool(client.FlagDryRun), - GenerateOnly: viper.GetBool(client.FlagGenerateOnly), + Certifier: createCertifier(), + DryRun: viper.GetBool(client.FlagDryRun), + GenerateOnly: viper.GetBool(client.FlagGenerateOnly), } } diff --git a/client/utils/utils.go b/client/utils/utils.go index 575f958cf141..82db7b37f355 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -8,9 +8,9 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/keys" sdk "github.com/cosmos/cosmos-sdk/types" - auth "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth" authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder" - amino "github.com/tendermint/go-amino" + "github.com/tendermint/go-amino" "github.com/tendermint/tendermint/libs/common" ) @@ -32,7 +32,7 @@ func SendTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) autogas := cliCtx.DryRun || (cliCtx.Gas == 0) if autogas { - txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, cliCtx.FromAddressName, msgs) + txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, name, msgs) if err != nil { return err } @@ -48,7 +48,7 @@ func SendTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) } // build and sign the transaction - txBytes, err := txBldr.BuildAndSign(cliCtx.FromAddressName, passphrase, msgs) + txBytes, err := txBldr.BuildAndSign(name, passphrase, msgs) if err != nil { return err } @@ -202,12 +202,12 @@ func buildUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msg } if txBldr.Gas == 0 { var name string - txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, cliCtx.FromAddressName, msgs) + txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, name, msgs) if err != nil { return } fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.Gas) - } + } stdSignMsg, err := txBldr.Build(msgs) if err != nil { return From 77f958f66962465ae50e94abd985c5b669bc6961 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Sun, 9 Sep 2018 06:14:56 -0700 Subject: [PATCH 08/12] Fix integration tests --- client/context/query.go | 5 +++-- crypto/keys/keybase.go | 10 +++++----- crypto/keys/keybase_test.go | 2 +- crypto/keys/types.go | 15 ++++++++++++++- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/client/context/query.go b/client/context/query.go index 7d88bc2e9b2e..924108654060 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -104,7 +104,8 @@ func (ctx CLIContext) GetFromName() (string, error) { return ctx.fromName, nil } -func (ctx CLIContext) populateFromFields() error { +// NOTE: mutates state so must be pointer receiver +func (ctx *CLIContext) populateFromFields() error { if ctx.From == "" { return errors.Errorf("must provide a from address or name") } @@ -127,7 +128,7 @@ func (ctx CLIContext) populateFromFields() error { } } - ctx.fromAddress = (sdk.AccAddress)(info.GetPubKey().Address()) + ctx.fromAddress = info.GetAddress() ctx.fromName = info.GetName() return nil } diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index d7730e3691d0..4910c3beb8b8 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -206,7 +206,7 @@ func (kb dbKeybase) Get(name string) (Info, error) { } func (kb dbKeybase) GetByAddress(address types.AccAddress) (Info, error) { - ik := kb.db.Get(addrKey((tmcrypto.Address)(address))) + ik := kb.db.Get(addrKey(address)) if len(ik) == 0 { return nil, fmt.Errorf("key with address %s not found", address.String()) } @@ -364,7 +364,7 @@ func (kb dbKeybase) Delete(name, passphrase string) error { if err != nil { return err } - kb.db.DeleteSync(addrKey(linfo.GetPubKey().Address())) + kb.db.DeleteSync(addrKey(linfo.GetAddress())) kb.db.DeleteSync(infoKey(name)) return nil case ledgerInfo: @@ -372,7 +372,7 @@ func (kb dbKeybase) Delete(name, passphrase string) error { if passphrase != "yes" { return fmt.Errorf("enter 'yes' exactly to delete the key - this cannot be undone") } - kb.db.DeleteSync(addrKey(info.GetPubKey().Address())) + kb.db.DeleteSync(addrKey(info.GetAddress())) kb.db.DeleteSync(infoKey(name)) return nil } @@ -436,10 +436,10 @@ func (kb dbKeybase) writeInfo(info Info, name string) { key := infoKey(name) kb.db.SetSync(key, writeInfo(info)) // store a pointer to the infokey by address for fast lookup - kb.db.SetSync(addrKey(info.GetPubKey().Address()), key) + kb.db.SetSync(addrKey(info.GetAddress()), key) } -func addrKey(address tmcrypto.Address) []byte { +func addrKey(address types.AccAddress) []byte { return []byte(fmt.Sprintf("%s.%s", address.String(), addressSuffix)) } diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index 327403470a7b..0459db29b2c3 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -104,7 +104,7 @@ func TestKeyManagement(t *testing.T) { // addr cache gets nuked err = cstore.Delete(n2, p2) require.NoError(t, err) - require.False(t, db.Has(addrKey(i2.GetPubKey().Address()))) + require.False(t, db.Has(addrKey(i2.GetAddress()))) } // TestSignVerify does some detailed checks on how we sign and validate diff --git a/crypto/keys/types.go b/crypto/keys/types.go index 8af83a0cb51e..c5e97d5fba31 100644 --- a/crypto/keys/types.go +++ b/crypto/keys/types.go @@ -10,7 +10,6 @@ import ( // Keybase exposes operations on a generic keystore type Keybase interface { - // CRUD on the keystore List() ([]Info, error) Get(name string) (Info, error) @@ -75,6 +74,8 @@ type Info interface { GetName() string // Public key GetPubKey() crypto.PubKey + // Address + GetAddress() types.AccAddress } var _ Info = &localInfo{} @@ -108,6 +109,10 @@ func (i localInfo) GetPubKey() crypto.PubKey { return i.PubKey } +func (i localInfo) GetAddress() types.AccAddress { + return i.PubKey.Address().Bytes() +} + // ledgerInfo is the public information about a Ledger key type ledgerInfo struct { Name string `json:"name"` @@ -135,6 +140,10 @@ func (i ledgerInfo) GetPubKey() crypto.PubKey { return i.PubKey } +func (i ledgerInfo) GetAddress() types.AccAddress { + return i.PubKey.Address().Bytes() +} + // offlineInfo is the public information about an offline key type offlineInfo struct { Name string `json:"name"` @@ -160,6 +169,10 @@ func (i offlineInfo) GetPubKey() crypto.PubKey { return i.PubKey } +func (i offlineInfo) GetAddress() types.AccAddress { + return i.PubKey.Address().Bytes() +} + // encoding info func writeInfo(i Info) []byte { return cdc.MustMarshalBinary(i) From 3a6ac88a0a9495f6f310dc81283b87d0ece39559 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Sun, 9 Sep 2018 06:37:20 -0700 Subject: [PATCH 09/12] Add back GetFromName() check broken during merge --- client/utils/utils.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/utils/utils.go b/client/utils/utils.go index 82db7b37f355..9ca18c20ae45 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -202,6 +202,11 @@ func buildUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msg } if txBldr.Gas == 0 { var name string + name, err = cliCtx.GetFromName() + if err != nil { + return + } + txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, name, msgs) if err != nil { return From ed7d43c28211426638be272e0178a8eba85b3241 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Tue, 18 Sep 2018 22:03:09 -0700 Subject: [PATCH 10/12] Code review updates --- client/context/context.go | 55 +++++++++++++++++++++++++++++++------ client/context/query.go | 43 ----------------------------- client/utils/utils.go | 5 ++-- crypto/keys/keybase.go | 2 +- crypto/keys/keybase_test.go | 2 +- types/address_test.go | 2 +- 6 files changed, 51 insertions(+), 58 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index e783723d46ca..094b28e5a05a 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -16,6 +16,9 @@ import ( tmliteProxy "github.com/tendermint/tendermint/lite/proxy" rpcclient "github.com/tendermint/tendermint/rpc/client" "os" + "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/client/keys" + cskeys "github.com/cosmos/cosmos-sdk/crypto/keys" ) const ctxAccStoreName = "acc" @@ -23,15 +26,13 @@ const ctxAccStoreName = "acc" // CLIContext implements a typical CLI context created in SDK modules for // transaction handling and queries. type CLIContext struct { - Codec *codec.Codec - AccDecoder auth.AccountDecoder - Client rpcclient.Client - Logger io.Writer - Height int64 - NodeURI string - FromAddressName string - AccountStore string - TrustNode bool + Codec *codec.Codec + AccDecoder auth.AccountDecoder + Client rpcclient.Client + Logger io.Writer + Height int64 + NodeURI string + From string AccountStore string TrustNode bool UseLedger bool @@ -55,6 +56,9 @@ func NewCLIContext() CLIContext { rpc = rpcclient.NewHTTP(nodeURI, "/websocket") } + from := viper.GetString(client.FlagFrom) + fromAddress, fromName := fromFields(from) + return CLIContext{ Client: rpc, NodeURI: nodeURI, @@ -69,6 +73,8 @@ func NewCLIContext() CLIContext { Certifier: createCertifier(), DryRun: viper.GetBool(client.FlagDryRun), GenerateOnly: viper.GetBool(client.FlagGenerateOnly), + fromAddress: fromAddress, + fromName: fromName, } } @@ -110,6 +116,37 @@ func createCertifier() tmlite.Certifier { return certifier } +// NOTE: mutates state so must be pointer receiver +func fromFields(from string) (types.AccAddress, string) { + if from == "" { + fmt.Println("must provide a from address or name") + os.Exit(1) + } + + keybase, err := keys.GetKeyBase() + if err != nil { + fmt.Println("No keybase found.") + os.Exit(1) + } + + var info cskeys.Info + if addr, err := types.AccAddressFromBech32(from); err == nil { + info, err = keybase.GetByAddress(addr) + if err != nil { + fmt.Printf("could not find key %s\n", from) + os.Exit(1) + } + } else { + info, err = keybase.Get(from) + if err != nil { + fmt.Printf("could not find key %s\n", from) + os.Exit(1) + } + } + + return info.GetAddress(), info.GetName() +} + // WithCodec returns a copy of the context with an updated codec. func (ctx CLIContext) WithCodec(cdc *codec.Codec) CLIContext { ctx.Codec = cdc diff --git a/client/context/query.go b/client/context/query.go index e1a8cafd01a4..35402fbfbe72 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -4,7 +4,6 @@ import ( "fmt" "io" - "github.com/cosmos/cosmos-sdk/client/keys" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -21,7 +20,6 @@ import ( tmliteProxy "github.com/tendermint/tendermint/lite/proxy" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" - cskeys "github.com/cosmos/cosmos-sdk/crypto/keys" ) // GetNode returns an RPC client. If the context's client is not defined, an @@ -86,55 +84,14 @@ func (ctx CLIContext) GetAccount(address []byte) (auth.Account, error) { // GetFromAddress returns the from address from the context's name. func (ctx CLIContext) GetFromAddress() (sdk.AccAddress, error) { - if ctx.fromAddress == nil { - if err := ctx.populateFromFields(); err != nil { - return nil, err - } - } - return ctx.fromAddress, nil } // GetFromName returns the key name for the current context. func (ctx CLIContext) GetFromName() (string, error) { - if ctx.fromName == "" { - if err := ctx.populateFromFields(); err != nil { - return "", err - } - } - return ctx.fromName, nil } -// NOTE: mutates state so must be pointer receiver -func (ctx *CLIContext) populateFromFields() error { - if ctx.From == "" { - return errors.Errorf("must provide a from address or name") - } - - keybase, err := keys.GetKeyBase() - if err != nil { - return err - } - - var info cskeys.Info - if addr, err := sdk.AccAddressFromBech32(ctx.From); err == nil { - info, err = keybase.GetByAddress(addr) - if err != nil { - return err - } - } else { - info, err = keybase.Get(ctx.From) - if err != nil { - return err - } - } - - ctx.fromAddress = info.GetAddress() - ctx.fromName = info.GetName() - return nil -} - // GetAccountNumber returns the next account number for the given account // address. func (ctx CLIContext) GetAccountNumber(address []byte) (int64, error) { diff --git a/client/utils/utils.go b/client/utils/utils.go index 66ab74e35f65..76ee91585e17 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -26,12 +26,11 @@ func SendTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) } name, err := cliCtx.GetFromName() - if txBldr.SimulateGas || cliCtx.DryRun { + if err != nil { return err } - autogas := cliCtx.DryRun || (cliCtx.Gas == 0) - if autogas { + if txBldr.SimulateGas || cliCtx.DryRun { txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, name, msgs) if err != nil { return err diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index 4910c3beb8b8..c9bfd0812970 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -208,7 +208,7 @@ func (kb dbKeybase) Get(name string) (Info, error) { func (kb dbKeybase) GetByAddress(address types.AccAddress) (Info, error) { ik := kb.db.Get(addrKey(address)) if len(ik) == 0 { - return nil, fmt.Errorf("key with address %s not found", address.String()) + return nil, fmt.Errorf("key with address %s not found", address) } bs := kb.db.Get(ik) return readInfo(bs) diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index 0459db29b2c3..2a602461a162 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -55,7 +55,7 @@ func TestKeyManagement(t *testing.T) { require.NotNil(t, err) _, err = cstore.GetByAddress(accAddr(i2)) require.NoError(t, err) - addr, err := types.AccAddressFromBech32("cosmosaccaddr1jawd35d9aq4u76sr3fjalmcqc8hqygs9gtnmv3") + addr, err := types.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") require.NoError(t, err) _, err = cstore.GetByAddress(addr) require.NotNil(t, err) diff --git a/types/address_test.go b/types/address_test.go index e2ec36876cd5..6c6c78d6ec5b 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -10,7 +10,7 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" "github.com/cosmos/cosmos-sdk/types" -) + ) var invalidStrs = []string{ "", From ac3325c8c730c2b1c427c731150eaf330a994fe2 Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Tue, 18 Sep 2018 22:37:39 -0700 Subject: [PATCH 11/12] Fix failing test --- client/context/context.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index 094b28e5a05a..a246b3fc0285 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -119,8 +119,7 @@ func createCertifier() tmlite.Certifier { // NOTE: mutates state so must be pointer receiver func fromFields(from string) (types.AccAddress, string) { if from == "" { - fmt.Println("must provide a from address or name") - os.Exit(1) + return nil, "" } keybase, err := keys.GetKeyBase() From 0799aa8594b799b4fa2d9f522cdbc8a4fccf98bb Mon Sep 17 00:00:00 2001 From: Matthew Slipper Date: Tue, 25 Sep 2018 12:35:40 -0700 Subject: [PATCH 12/12] Updates from code review --- client/context/context.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/context/context.go b/client/context/context.go index a246b3fc0285..e4b045ca7fbc 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -116,15 +116,14 @@ func createCertifier() tmlite.Certifier { return certifier } -// NOTE: mutates state so must be pointer receiver -func fromFields(from string) (types.AccAddress, string) { +func fromFields(from string) (fromAddr types.AccAddress, fromName string) { if from == "" { return nil, "" } keybase, err := keys.GetKeyBase() if err != nil { - fmt.Println("No keybase found.") + fmt.Println("no keybase found") os.Exit(1) } @@ -143,7 +142,9 @@ func fromFields(from string) (types.AccAddress, string) { } } - return info.GetAddress(), info.GetName() + fromAddr = info.GetAddress() + fromName = info.GetName() + return } // WithCodec returns a copy of the context with an updated codec.