From 9a57ce0214124cb0ae3cd2c9e24a070917fe7425 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 6 Feb 2019 11:23:49 -0800 Subject: [PATCH] Merge PR #3514: don't lock keybase on lcd startup --- Gopkg.lock | 1 - PENDING.md | 6 + client/context/context.go | 3 +- client/keys.go | 11 +- client/keys/add.go | 6 +- client/keys/delete.go | 4 +- client/keys/list.go | 4 +- client/keys/update.go | 4 +- client/keys/utils.go | 53 ++------- client/keys/utils_test.go | 41 ------- client/lcd/lcd_test.go | 73 +++++++++--- client/lcd/root.go | 18 --- client/lcd/test_helpers.go | 42 +++---- client/rest/rest.go | 2 +- client/utils/utils.go | 23 ++-- cmd/gaia/init/genesis_accts.go | 2 +- cmd/gaia/init/gentx.go | 2 +- cmd/gaia/init/testnet.go | 8 +- crypto/keys/lazy_keybase.go | 165 +++++++++++++++++++++++++++ server/init.go | 2 +- x/auth/client/cli/multisign.go | 4 +- x/auth/client/cli/sign.go | 2 +- x/auth/client/txbuilder/txbuilder.go | 76 +++++++----- 23 files changed, 333 insertions(+), 219 deletions(-) delete mode 100644 client/keys/utils_test.go create mode 100644 crypto/keys/lazy_keybase.go diff --git a/Gopkg.lock b/Gopkg.lock index 9711a8447..b9ab3cbc4 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -680,7 +680,6 @@ "github.com/spf13/viper", "github.com/stretchr/testify/assert", "github.com/stretchr/testify/require", - "github.com/syndtr/goleveldb/leveldb/opt", "github.com/tendermint/btcd/btcec", "github.com/tendermint/go-amino", "github.com/tendermint/iavl", diff --git a/PENDING.md b/PENDING.md index 334878e7b..de670bea2 100644 --- a/PENDING.md +++ b/PENDING.md @@ -27,6 +27,9 @@ BREAKING CHANGES * [\#3487](https://github.com/cosmos/cosmos-sdk/pull/3487) Move HTTP/REST utilities out of client/utils into a new dedicated client/rest package. * [\#3490](https://github.com/cosmos/cosmos-sdk/issues/3490) ReadRESTReq() returns bool to avoid callers to write error responses twice. * [\#3502](https://github.com/cosmos/cosmos-sdk/pull/3502) Fixes issue when comparing genesis states + * [\#3514](https://github.com/cosmos/cosmos-sdk/pull/3514) Various clean ups: + - Replace all GetKeyBase* functions family in favor of NewKeyBaseFromDir and NewKeyBaseFromHomeFlag. + - Remove Get prefix from all TxBuilder's getters. * Tendermint @@ -48,6 +51,8 @@ FEATURES * SDK * \#3270 [x/staking] limit number of ongoing unbonding delegations /redelegations per pair/trio * [\#3477][distribution] new query endpoint "delegator_validators" + * [\#3514](https://github.com/cosmos/cosmos-sdk/pull/3514) Provided a lazy loading implementation of Keybase that locks the underlying + storage only for the time needed to perform the required operation. Also added Keybase reference to TxBuilder struct. * Tendermint @@ -62,6 +67,7 @@ IMPROVEMENTS * `from` field in the `base_req` body can be a Keybase name or account address * [\#3423](https://github.com/cosmos/cosmos-sdk/issues/3423) Allow simulation (auto gas) to work with generate only. + * [\#3514](https://github.com/cosmos/cosmos-sdk/pull/3514) REST server calls to keybase does not lock the underlying storage anymore. * Gaia CLI (`gaiacli`) * [\#3476](https://github.com/cosmos/cosmos-sdk/issues/3476) New `withdraw-all-rewards` command to withdraw all delegations rewards for delegators. diff --git a/client/context/context.go b/client/context/context.go index a9744408d..7364adbff 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -35,6 +35,7 @@ type CLIContext struct { Codec *codec.Codec AccDecoder auth.AccountDecoder Client rpcclient.Client + Keybase cryptokeys.Keybase Output io.Writer OutputFormat string Height int64 @@ -276,7 +277,7 @@ func GetFromFields(from string) (sdk.AccAddress, string, error) { return nil, "", nil } - keybase, err := keys.GetKeyBase() + keybase, err := keys.NewKeyBaseFromHomeFlag() if err != nil { return nil, "", err } diff --git a/client/keys.go b/client/keys.go index 1fc594a2a..3e0b61d46 100644 --- a/client/keys.go +++ b/client/keys.go @@ -6,18 +6,9 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys" ) -// GetKeyBase initializes a keybase based on the given db. -// The KeyBase manages all activity requiring access to a key. -func GetKeyBase(db dbm.DB) keys.Keybase { - keybase := keys.New( - db, - ) - return keybase -} - // MockKeyBase generates an in-memory keybase that will be discarded // useful for --dry-run to generate a seed phrase without // storing the key func MockKeyBase() keys.Keybase { - return GetKeyBase(dbm.NewMemDB()) + return keys.New(dbm.NewMemDB()) } diff --git a/client/keys/add.go b/client/keys/add.go index ca5b58da4..a7c8c6b52 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -105,7 +105,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error { kb = client.MockKeyBase() encryptPassword = app.DefaultKeyPass } else { - kb, err = GetKeyBaseWithWritePerm() + kb, err = NewKeyBaseFromHomeFlag() if err != nil { return err } @@ -332,7 +332,7 @@ func AddNewKeyRequestHandler(indent bool) http.HandlerFunc { var kb keys.Keybase var m AddNewKey - kb, err := GetKeyBaseWithWritePerm() + kb, err := NewKeyBaseFromHomeFlag() if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) { return } @@ -435,7 +435,7 @@ func RecoverRequestHandler(indent bool) http.HandlerFunc { return } - kb, err := GetKeyBaseWithWritePerm() + kb, err := NewKeyBaseFromHomeFlag() CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) if name == "" { diff --git a/client/keys/delete.go b/client/keys/delete.go index 0f8392270..11a9cf1af 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -49,7 +49,7 @@ gaiacli. func runDeleteCmd(cmd *cobra.Command, args []string) error { name := args[0] - kb, err := GetKeyBaseWithWritePerm() + kb, err := NewKeyBaseFromHomeFlag() if err != nil { return err } @@ -114,7 +114,7 @@ func DeleteKeyRequestHandler(w http.ResponseWriter, r *http.Request) { return } - kb, err = GetKeyBaseWithWritePerm() + kb, err = NewKeyBaseFromHomeFlag() if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) diff --git a/client/keys/list.go b/client/keys/list.go index 9d01d500b..ccd94dee3 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -18,7 +18,7 @@ along with their associated name and address.`, } func runListCmd(cmd *cobra.Command, args []string) error { - kb, err := GetKeyBase() + kb, err := NewKeyBaseFromHomeFlag() if err != nil { return err } @@ -36,7 +36,7 @@ func runListCmd(cmd *cobra.Command, args []string) error { // query key list REST handler func QueryKeysRequestHandler(indent bool) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - kb, err := GetKeyBase() + kb, err := NewKeyBaseFromHomeFlag() if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) diff --git a/client/keys/update.go b/client/keys/update.go index e72da240c..cbb704887 100644 --- a/client/keys/update.go +++ b/client/keys/update.go @@ -29,7 +29,7 @@ func runUpdateCmd(cmd *cobra.Command, args []string) error { name := args[0] buf := client.BufferStdin() - kb, err := GetKeyBaseWithWritePerm() + kb, err := NewKeyBaseFromHomeFlag() if err != nil { return err } @@ -77,7 +77,7 @@ func UpdateKeyRequestHandler(w http.ResponseWriter, r *http.Request) { return } - kb, err = GetKeyBaseWithWritePerm() + kb, err = NewKeyBaseFromHomeFlag() if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(err.Error())) diff --git a/client/keys/utils.go b/client/keys/utils.go index 5f9bcfa59..1aef97f7f 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -6,9 +6,7 @@ import ( "path/filepath" "github.com/spf13/viper" - "github.com/syndtr/goleveldb/leveldb/opt" "github.com/tendermint/tendermint/libs/cli" - dbm "github.com/tendermint/tendermint/libs/db" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" @@ -19,15 +17,12 @@ import ( // KeyDBName is the directory under root where we store the keys const KeyDBName = "keys" -// keybase is used to make GetKeyBase a singleton -var keybase keys.Keybase - type bechKeyOutFn func(keyInfo keys.Info) (KeyOutput, error) // GetKeyInfo returns key info for a given name. An error is returned if the // keybase cannot be retrieved or getting the info fails. func GetKeyInfo(name string) (keys.Info, error) { - keybase, err := GetKeyBase() + keybase, err := NewKeyBaseFromHomeFlag() if err != nil { return nil, err } @@ -73,49 +68,19 @@ func ReadPassphraseFromStdin(name string) (string, error) { return passphrase, nil } -// TODO make keybase take a database not load from the directory - -// GetKeyBase initializes a read-only KeyBase based on the configuration. -func GetKeyBase() (keys.Keybase, error) { +// NewKeyBaseFromHomeFlag initializes a Keybase based on the configuration. +func NewKeyBaseFromHomeFlag() (keys.Keybase, error) { rootDir := viper.GetString(cli.HomeFlag) - return GetKeyBaseFromDir(rootDir) + return NewKeyBaseFromDir(rootDir) } -// GetKeyBaseWithWritePerm initialize a keybase based on the configuration with write permissions. -func GetKeyBaseWithWritePerm() (keys.Keybase, error) { - rootDir := viper.GetString(cli.HomeFlag) - return GetKeyBaseFromDirWithWritePerm(rootDir) +// NewKeyBaseFromDir initializes a keybase at a particular dir. +func NewKeyBaseFromDir(rootDir string) (keys.Keybase, error) { + return getLazyKeyBaseFromDir(rootDir) } -// GetKeyBaseFromDirWithWritePerm initializes a keybase at a particular dir with write permissions. -func GetKeyBaseFromDirWithWritePerm(rootDir string) (keys.Keybase, error) { - return getKeyBaseFromDirWithOpts(rootDir, nil) -} - -// GetKeyBaseFromDir initializes a read-only keybase at a particular dir. -func GetKeyBaseFromDir(rootDir string) (keys.Keybase, error) { - // Disabled because of the inability to create a new keys database directory - // in the instance of when ReadOnly is set to true. - // - // ref: syndtr/goleveldb#240 - // return getKeyBaseFromDirWithOpts(rootDir, &opt.Options{ReadOnly: true}) - return getKeyBaseFromDirWithOpts(rootDir, nil) -} - -func getKeyBaseFromDirWithOpts(rootDir string, o *opt.Options) (keys.Keybase, error) { - if keybase == nil { - db, err := dbm.NewGoLevelDBWithOpts(KeyDBName, filepath.Join(rootDir, "keys"), o) - if err != nil { - return nil, err - } - keybase = client.GetKeyBase(db) - } - return keybase, nil -} - -// used to set the keybase manually in test -func SetKeyBase(kb keys.Keybase) { - keybase = kb +func getLazyKeyBaseFromDir(rootDir string) (keys.Keybase, error) { + return keys.NewLazyKeybase(KeyDBName, filepath.Join(rootDir, "keys")), nil } // create a list of KeyOutput in bech32 format diff --git a/client/keys/utils_test.go b/client/keys/utils_test.go deleted file mode 100644 index 5f3dd4560..000000000 --- a/client/keys/utils_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package keys - -import ( - "io/ioutil" - "os" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/crypto/keys" -) - -func TestGetKeyBaseLocks(t *testing.T) { - dir, err := ioutil.TempDir("", "cosmos-sdk-keys") - require.Nil(t, err) - defer os.RemoveAll(dir) - - // Acquire db - kb, err := GetKeyBaseFromDirWithWritePerm(dir) - require.Nil(t, err) - _, _, err = kb.CreateMnemonic("foo", keys.English, "12345678", keys.Secp256k1) - require.Nil(t, err) - // Reset global variable - keybase = nil - // Try to acquire another keybase from the same storage - _, err = GetKeyBaseFromDirWithWritePerm(dir) - require.NotNil(t, err) - _, err = GetKeyBaseFromDirWithWritePerm(dir) - require.NotNil(t, err) - - // Close the db and try to acquire the lock - kb.CloseDB() - kb, err = GetKeyBaseFromDirWithWritePerm(dir) - require.Nil(t, err) - - // Try to acquire another read-only keybase from the same storage - _, err = GetKeyBaseFromDir(dir) - require.Nil(t, err) - - kb.CloseDB() -} diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 0e7b860a2..98f55dc3c 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/rest" "github.com/cosmos/cosmos-sdk/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" @@ -46,7 +47,9 @@ func init() { } func TestSeedsAreDifferent(t *testing.T) { - addr, _ := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, _ := CreateAddr(t, name1, pw, kb) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() @@ -57,6 +60,8 @@ func TestSeedsAreDifferent(t *testing.T) { } func TestKeyRecover(t *testing.T) { + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true) defer cleanup() @@ -64,7 +69,7 @@ func TestKeyRecover(t *testing.T) { myName2 := "TestKeyRecover_2" mnemonic := getKeysSeed(t, port) - expectedInfo, _ := GetKeyBase(t).CreateAccount(myName1, mnemonic, "", pw, 0, 0) + expectedInfo, _ := kb.CreateAccount(myName1, mnemonic, "", pw, 0, 0) expectedAddress := expectedInfo.GetAddress().String() expectedPubKey := sdk.MustBech32ifyAccPub(expectedInfo.GetPubKey()) @@ -78,6 +83,8 @@ func TestKeyRecover(t *testing.T) { } func TestKeyRecoverHDPath(t *testing.T) { + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{}, true) defer cleanup() @@ -88,7 +95,7 @@ func TestKeyRecoverHDPath(t *testing.T) { 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) + expectedInfo, _ := kb.CreateAccount(name1Idx, mnemonic, "", pw, account, index) expectedAddress := expectedInfo.GetAddress().String() expectedPubKey := sdk.MustBech32ifyAccPub(expectedInfo.GetPubKey()) @@ -104,7 +111,9 @@ func TestKeyRecoverHDPath(t *testing.T) { } func TestKeys(t *testing.T) { - addr1, _ := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr1, _ := CreateAddr(t, name1, pw, kb) addr1Bech32 := addr1.String() cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr1}, true) @@ -119,11 +128,11 @@ func TestKeys(t *testing.T) { resp := doKeysPost(t, port, name3, pw, mnemonic3, 0, 0) addr3Bech32 := resp.Address - _, err := sdk.AccAddressFromBech32(addr3Bech32) + _, err = sdk.AccAddressFromBech32(addr3Bech32) 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, _ := kb.CreateAccount(name3, mnemonic3, "", pw, 0, 0) expectedAddress3 := sdk.AccAddress(expectedInfo3.GetPubKey().Address()).String() require.Equal(t, expectedAddress3, addr3Bech32) @@ -204,7 +213,9 @@ func TestValidators(t *testing.T) { } func TestCoinSend(t *testing.T) { - addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, seed := CreateAddr(t, name1, pw, kb) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() @@ -293,7 +304,9 @@ func TestCoinSend(t *testing.T) { } func TestCoinSendAccAuto(t *testing.T) { - addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, seed := CreateAddr(t, name1, pw, kb) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() @@ -314,7 +327,9 @@ func TestCoinSendAccAuto(t *testing.T) { } func TestCoinMultiSendGenerateOnly(t *testing.T) { - addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, seed := CreateAddr(t, name1, pw, kb) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() @@ -335,7 +350,9 @@ func TestCoinMultiSendGenerateOnly(t *testing.T) { } func TestCoinSendGenerateSignAndBroadcast(t *testing.T) { - addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, seed := CreateAddr(t, name1, pw, kb) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() acc := getAccount(t, port, addr) @@ -407,7 +424,9 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) { } func TestTxs(t *testing.T) { - addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, seed := CreateAddr(t, name1, pw, kb) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() @@ -446,7 +465,9 @@ func TestTxs(t *testing.T) { } func TestPoolParamsQuery(t *testing.T) { - addr, _ := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, _ := CreateAddr(t, name1, pw, kb) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() @@ -502,7 +523,9 @@ func TestValidatorQuery(t *testing.T) { } func TestBonding(t *testing.T) { - addr, _ := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, _ := CreateAddr(t, name1, pw, kb) cleanup, valPubKeys, operAddrs, port := InitializeTestLCD(t, 2, []sdk.AccAddress{addr}, true) defer cleanup() @@ -663,7 +686,9 @@ func TestBonding(t *testing.T) { } func TestSubmitProposal(t *testing.T) { - addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, seed := CreateAddr(t, name1, pw, kb) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() @@ -696,7 +721,9 @@ func TestSubmitProposal(t *testing.T) { } func TestDeposit(t *testing.T) { - addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, seed := CreateAddr(t, name1, pw, kb) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() @@ -751,7 +778,9 @@ func TestDeposit(t *testing.T) { } func TestVote(t *testing.T) { - addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, seed := CreateAddr(t, name1, pw, kb) cleanup, _, operAddrs, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() @@ -834,7 +863,9 @@ func TestVote(t *testing.T) { } func TestUnjail(t *testing.T) { - addr, _ := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, _ := CreateAddr(t, name1, pw, kb) cleanup, valPubKeys, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true) defer cleanup() @@ -849,7 +880,9 @@ func TestUnjail(t *testing.T) { } func TestProposalsQuery(t *testing.T) { - addrs, seeds, names, passwords := CreateAddrs(t, GetKeyBase(t), 2) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addrs, seeds, names, passwords := CreateAddrs(t, kb, 2) cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addrs[0], addrs[1]}, true) defer cleanup() @@ -992,7 +1025,9 @@ func TestDistributionGetParams(t *testing.T) { } func TestDistributionFlow(t *testing.T) { - addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t)) + kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, "")) + require.NoError(t, err) + addr, seed := CreateAddr(t, name1, pw, kb) cleanup, _, valAddrs, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, false) defer cleanup() diff --git a/client/lcd/root.go b/client/lcd/root.go index 7021149f2..0f6fb120a 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -16,7 +16,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" keybase "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/server" @@ -52,22 +51,6 @@ func NewRestServer(cdc *codec.Codec) *RestServer { } } -func (rs *RestServer) setKeybase(kb keybase.Keybase) { - // If a keybase is passed in, set it and return - if kb != nil { - rs.KeyBase = kb - return - } - - // Otherwise get the keybase and set it - kb, err := keys.GetKeyBase() //XXX - if err != nil { - fmt.Printf("Failed to open Keybase: %s, exiting...", err) - os.Exit(1) - } - rs.KeyBase = kb -} - // Start starts the rest server func (rs *RestServer) Start(listenAddr string, sslHosts string, certFile string, keyFile string, maxOpen int, secure bool) (err error) { @@ -136,7 +119,6 @@ func ServeCommand(cdc *codec.Codec, registerRoutesFn func(*RestServer)) *cobra.C RunE: func(cmd *cobra.Command, args []string) (err error) { rs := NewRestServer(cdc) - rs.setKeybase(nil) registerRoutesFn(rs) // Start the rest server and return error if one exists diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 588285233..fc47c534c 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -99,30 +99,6 @@ func GetConfig() *tmcfg.Config { return config } -// GetKeyBase returns the LCD test keybase. It also requires that a directory -// could be made and a keybase could be fetched. -// -// NOTE: memDB cannot be used because the request is expecting to interact with -// the default location. -func GetKeyBase(t *testing.T) crkeys.Keybase { - dir, err := ioutil.TempDir("", "lcd_test") - require.NoError(t, err) - - viper.Set(cli.HomeFlag, dir) - - keybase, err := keys.GetKeyBaseWithWritePerm() - require.NoError(t, err) - - return keybase -} - -// GetTestKeyBase fetches the current testing keybase -func GetTestKeyBase(t *testing.T) crkeys.Keybase { - keybase, err := keys.GetKeyBaseWithWritePerm() - require.NoError(t, err) - return keybase -} - // CreateAddr adds an address to the key store and returns an address and seed. // It also requires that the key could be created. func CreateAddr(t *testing.T, name, password string, kb crkeys.Keybase) (sdk.AccAddress, string) { @@ -193,6 +169,20 @@ func (b AddrSeedSlice) Swap(i, j int) { b[j], b[i] = b[i], b[j] } +// InitClientHome initialises client home dir. +func InitClientHome(t *testing.T, dir string) string { + var err error + if dir == "" { + dir, err = ioutil.TempDir("", "lcd_test") + require.NoError(t, err) + } + // TODO: this should be set in NewRestServer + // and pass down the CLIContext to achieve + // parallelism. + viper.Set(cli.HomeFlag, dir) + return dir +} + // TODO: Make InitializeTestLCD safe to call in multiple tests at the same time // InitializeTestLCD starts Tendermint and the LCD in process, listening on // their respective sockets where nValidators is the total number of validators @@ -308,9 +298,6 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress viper.Set(client.FlagChainID, genDoc.ChainID) // TODO Set to false once the upstream Tendermint proof verification issue is fixed. viper.Set(client.FlagTrustNode, true) - dir, err := ioutil.TempDir("", "lcd_test") - require.NoError(t, err) - viper.Set(cli.HomeFlag, dir) node, err := startTM(config, logger, genDoc, privVal, app) require.NoError(t, err) @@ -376,7 +363,6 @@ func startTM( // startLCD starts the LCD. func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec, t *testing.T) (net.Listener, error) { rs := NewRestServer(cdc) - rs.setKeybase(GetTestKeyBase(t)) registerRoutes(rs) listener, err := tmrpc.Listen(listenAddr, tmrpc.Config{}) if err != nil { diff --git a/client/rest/rest.go b/client/rest/rest.go index 0b87e084d..f7310835c 100644 --- a/client/rest/rest.go +++ b/client/rest/rest.go @@ -153,7 +153,7 @@ func CompleteAndBroadcastTxREST( } if baseReq.Simulate { - WriteSimulationResponse(w, cdc, txBldr.GetGas()) + WriteSimulationResponse(w, cdc, txBldr.Gas()) return } } diff --git a/client/utils/utils.go b/client/utils/utils.go index 0123f0952..5108f9563 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -43,13 +43,13 @@ func CompleteAndBroadcastTxCLI(txBldr authtxb.TxBuilder, cliCtx context.CLIConte fromName := cliCtx.GetFromName() - if txBldr.GetSimulateAndExecute() || cliCtx.Simulate { + if txBldr.SimulateAndExecute() || cliCtx.Simulate { txBldr, err = EnrichWithGas(txBldr, cliCtx, msgs) if err != nil { return err } - gasEst := GasEstimateResponse{GasEstimate: txBldr.GetGas()} + gasEst := GasEstimateResponse{GasEstimate: txBldr.Gas()} fmt.Fprintf(os.Stderr, gasEst.String()) } @@ -126,10 +126,7 @@ func PrintUnsignedStdTx(w io.Writer, txBldr authtxb.TxBuilder, cliCtx context.CL func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, stdTx auth.StdTx, appendSig bool, offline bool) (auth.StdTx, error) { var signedStdTx auth.StdTx - keybase, err := keys.GetKeyBase() - if err != nil { - return signedStdTx, err - } + keybase := txBldr.Keybase() info, err := keybase.Get(name) if err != nil { @@ -188,7 +185,7 @@ func SignStdTxWithSignerAddress(txBldr authtxb.TxBuilder, cliCtx context.CLICont func populateAccountFromState(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, addr sdk.AccAddress) (authtxb.TxBuilder, error) { - if txBldr.GetAccountNumber() == 0 { + if txBldr.AccountNumber() == 0 { accNum, err := cliCtx.GetAccountNumber(addr) if err != nil { return txBldr, err @@ -196,7 +193,7 @@ func populateAccountFromState(txBldr authtxb.TxBuilder, cliCtx context.CLIContex txBldr = txBldr.WithAccountNumber(accNum) } - if txBldr.GetSequence() == 0 { + if txBldr.Sequence() == 0 { accSeq, err := cliCtx.GetAccountSequence(addr) if err != nil { return txBldr, err @@ -224,7 +221,7 @@ func simulateMsgs(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sd if err != nil { return } - estimated, adjusted, err = CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, txBldr.GetGasAdjustment()) + estimated, adjusted, err = CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, txBldr.GasAdjustment()) return } @@ -250,7 +247,7 @@ func PrepareTxBuilder(txBldr authtxb.TxBuilder, cliCtx context.CLIContext) (auth // TODO: (ref #1903) Allow for user supplied account number without // automatically doing a manual lookup. - if txBldr.GetAccountNumber() == 0 { + if txBldr.AccountNumber() == 0 { accNum, err := cliCtx.GetAccountNumber(from) if err != nil { return txBldr, err @@ -260,7 +257,7 @@ func PrepareTxBuilder(txBldr authtxb.TxBuilder, cliCtx context.CLIContext) (auth // TODO: (ref #1903) Allow for user supplied account sequence without // automatically doing a manual lookup. - if txBldr.GetSequence() == 0 { + if txBldr.Sequence() == 0 { accSeq, err := cliCtx.GetAccountSequence(from) if err != nil { return txBldr, err @@ -281,13 +278,13 @@ func buildUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msg } func buildUnsignedStdTxOffline(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (stdTx auth.StdTx, err error) { - if txBldr.GetSimulateAndExecute() { + if txBldr.SimulateAndExecute() { txBldr, err = EnrichWithGas(txBldr, cliCtx, msgs) if err != nil { return } - fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.GetGas()) + fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.Gas()) } stdSignMsg, err := txBldr.Build(msgs) diff --git a/cmd/gaia/init/genesis_accts.go b/cmd/gaia/init/genesis_accts.go index 8b580584f..4ec108dcb 100644 --- a/cmd/gaia/init/genesis_accts.go +++ b/cmd/gaia/init/genesis_accts.go @@ -28,7 +28,7 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command addr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { - kb, err := keys.GetKeyBaseFromDir(viper.GetString(flagClientHome)) + kb, err := keys.NewKeyBaseFromDir(viper.GetString(flagClientHome)) if err != nil { return err } diff --git a/cmd/gaia/init/gentx.go b/cmd/gaia/init/gentx.go index 93e4b5da9..e9178da75 100644 --- a/cmd/gaia/init/gentx.go +++ b/cmd/gaia/init/gentx.go @@ -84,7 +84,7 @@ following delegation and commission default parameters: return err } - kb, err := keys.GetKeyBaseFromDir(viper.GetString(flagClientHome)) + kb, err := keys.NewKeyBaseFromDir(viper.GetString(flagClientHome)) if err != nil { return err } diff --git a/cmd/gaia/init/testnet.go b/cmd/gaia/init/testnet.go index 7ce811568..921f24f42 100644 --- a/cmd/gaia/init/testnet.go +++ b/cmd/gaia/init/testnet.go @@ -7,6 +7,8 @@ import ( "os" "path/filepath" + "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/codec" @@ -206,8 +208,12 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error { staking.NewDescription(nodeDirName, "", "", ""), staking.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), ) + kb, err := keys.NewKeyBaseFromDir(clientDir) + if err != nil { + return err + } tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo) - txBldr := authtx.NewTxBuilderFromCLI().WithChainID(chainID).WithMemo(memo) + txBldr := authtx.NewTxBuilderFromCLI().WithChainID(chainID).WithMemo(memo).WithKeybase(kb) signedTx, err := txBldr.SignStdTx(nodeDirName, app.DefaultKeyPass, tx, false) if err != nil { diff --git a/crypto/keys/lazy_keybase.go b/crypto/keys/lazy_keybase.go new file mode 100644 index 000000000..d63e6c06c --- /dev/null +++ b/crypto/keys/lazy_keybase.go @@ -0,0 +1,165 @@ +package keys + +import ( + "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/tendermint/crypto" + dbm "github.com/tendermint/tendermint/libs/db" +) + +var _ Keybase = lazyKeybase{} + +type lazyKeybase struct { + name string + dir string +} + +func NewLazyKeybase(name, dir string) Keybase { + return lazyKeybase{name: name, dir: dir} +} + +func (lkb lazyKeybase) List() ([]Info, error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return nil, err + } + defer db.Close() + return New(db).List() +} + +func (lkb lazyKeybase) Get(name string) (Info, error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return nil, err + } + defer db.Close() + return New(db).Get(name) +} + +func (lkb lazyKeybase) GetByAddress(address types.AccAddress) (Info, error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return nil, err + } + defer db.Close() + return New(db).GetByAddress(address) +} + +func (lkb lazyKeybase) Delete(name, passphrase string, skipPass bool) error { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return err + } + defer db.Close() + return New(db).Delete(name, passphrase, skipPass) +} + +func (lkb lazyKeybase) Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return nil, nil, err + } + defer db.Close() + return New(db).Sign(name, passphrase, msg) +} + +func (lkb lazyKeybase) CreateMnemonic(name string, language Language, passwd string, algo SigningAlgo) (info Info, seed string, err error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return nil, "", err + } + defer db.Close() + return New(db).CreateMnemonic(name, language, passwd, algo) +} + +func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return nil, err + } + defer db.Close() + return New(db).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, account, index) +} + +func (lkb lazyKeybase) Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (Info, error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return nil, err + } + defer db.Close() + return New(db).Derive(name, mnemonic, bip39Passwd, encryptPasswd, params) +} + +func (lkb lazyKeybase) CreateLedger(name string, algo SigningAlgo, account uint32, index uint32) (info Info, err error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return nil, err + } + defer db.Close() + return New(db).CreateLedger(name, algo, account, index) +} + +func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey) (info Info, err error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return nil, err + } + defer db.Close() + return New(db).CreateOffline(name, pubkey) +} + +func (lkb lazyKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return err + } + defer db.Close() + return New(db).Update(name, oldpass, getNewpass) +} + +func (lkb lazyKeybase) Import(name string, armor string) (err error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return err + } + defer db.Close() + return New(db).Import(name, armor) +} + +func (lkb lazyKeybase) ImportPubKey(name string, armor string) (err error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return err + } + defer db.Close() + return New(db).ImportPubKey(name, armor) +} + +func (lkb lazyKeybase) Export(name string) (armor string, err error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return "", err + } + defer db.Close() + return New(db).Export(name) +} + +func (lkb lazyKeybase) ExportPubKey(name string) (armor string, err error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return "", err + } + defer db.Close() + return New(db).ExportPubKey(name) +} + +func (lkb lazyKeybase) ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error) { + db, err := dbm.NewGoLevelDB(lkb.name, lkb.dir) + if err != nil { + return nil, err + } + defer db.Close() + return New(db).ExportPrivateKeyObject(name, passphrase) +} + +func (lkb lazyKeybase) CloseDB() {} diff --git a/server/init.go b/server/init.go index dd9e7b890..b0d44d1f0 100644 --- a/server/init.go +++ b/server/init.go @@ -108,7 +108,7 @@ func GenerateCoinKey() (sdk.AccAddress, string, error) { func GenerateSaveCoinKey(clientRoot, keyName, keyPass string, overwrite bool) (sdk.AccAddress, string, error) { // get the keystore from the client - keybase, err := clkeys.GetKeyBaseFromDirWithWritePerm(clientRoot) + keybase, err := clkeys.NewKeyBaseFromDir(clientRoot) if err != nil { return sdk.AccAddress([]byte{}), "", err } diff --git a/x/auth/client/cli/multisign.go b/x/auth/client/cli/multisign.go index 9fcc8a0a0..8acb2b601 100644 --- a/x/auth/client/cli/multisign.go +++ b/x/auth/client/cli/multisign.go @@ -57,7 +57,7 @@ func makeMultiSignCmd(cdc *amino.Codec) func(cmd *cobra.Command, args []string) return } - keybase, err := keys.GetKeyBaseFromDir(viper.GetString(cli.HomeFlag)) + keybase, err := keys.NewKeyBaseFromDir(viper.GetString(cli.HomeFlag)) if err != nil { return } @@ -100,7 +100,7 @@ func makeMultiSignCmd(cdc *amino.Codec) func(cmd *cobra.Command, args []string) // Validate each signature sigBytes := auth.StdSignBytes( - txBldr.GetChainID(), txBldr.GetAccountNumber(), txBldr.GetSequence(), + txBldr.ChainID(), txBldr.AccountNumber(), txBldr.Sequence(), stdTx.Fee, stdTx.GetMsgs(), stdTx.GetMemo(), ) if ok := stdSig.PubKey.VerifyBytes(sigBytes, stdSig.Signature); !ok { diff --git a/x/auth/client/cli/sign.go b/x/auth/client/cli/sign.go index 1e0bc895f..e8209951d 100644 --- a/x/auth/client/cli/sign.go +++ b/x/auth/client/cli/sign.go @@ -85,7 +85,7 @@ func makeSignCmd(cdc *amino.Codec) func(cmd *cobra.Command, args []string) error txBldr := authtxb.NewTxBuilderFromCLI() if viper.GetBool(flagValidateSigs) { - if !printAndValidateSigs(cliCtx, txBldr.GetChainID(), stdTx, offline) { + if !printAndValidateSigs(cliCtx, txBldr.ChainID(), stdTx, offline) { return fmt.Errorf("signatures validation failed") } diff --git a/x/auth/client/txbuilder/txbuilder.go b/x/auth/client/txbuilder/txbuilder.go index df8bb9782..a3ba7fa82 100644 --- a/x/auth/client/txbuilder/txbuilder.go +++ b/x/auth/client/txbuilder/txbuilder.go @@ -3,6 +3,8 @@ package context import ( "strings" + crkeys "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/keys" sdk "github.com/cosmos/cosmos-sdk/types" @@ -15,6 +17,7 @@ import ( // TxBuilder implements a transaction context created in SDK modules. type TxBuilder struct { txEncoder sdk.TxEncoder + keybase crkeys.Keybase accountNumber uint64 sequence uint64 gas uint64 @@ -34,6 +37,7 @@ func NewTxBuilder( return TxBuilder{ txEncoder: txEncoder, + keybase: nil, accountNumber: accNumber, sequence: seq, gas: gas, @@ -49,7 +53,12 @@ func NewTxBuilder( // NewTxBuilderFromCLI returns a new initialized TxBuilder with parameters from // the command line using Viper. func NewTxBuilderFromCLI() TxBuilder { + kb, err := keys.NewKeyBaseFromHomeFlag() + if err != nil { + panic(err) + } txbldr := TxBuilder{ + keybase: kb, accountNumber: uint64(viper.GetInt64(client.FlagAccountNumber)), sequence: uint64(viper.GetInt64(client.FlagSequence)), gas: client.GasFlagVar.Gas, @@ -65,36 +74,39 @@ func NewTxBuilderFromCLI() TxBuilder { return txbldr } -// GetTxEncoder returns the transaction encoder -func (bldr TxBuilder) GetTxEncoder() sdk.TxEncoder { return bldr.txEncoder } +// TxEncoder returns the transaction encoder +func (bldr TxBuilder) TxEncoder() sdk.TxEncoder { return bldr.txEncoder } -// GetAccountNumber returns the account number -func (bldr TxBuilder) GetAccountNumber() uint64 { return bldr.accountNumber } +// AccountNumber returns the account number +func (bldr TxBuilder) AccountNumber() uint64 { return bldr.accountNumber } -// GetSequence returns the transaction sequence -func (bldr TxBuilder) GetSequence() uint64 { return bldr.sequence } +// Sequence returns the transaction sequence +func (bldr TxBuilder) Sequence() uint64 { return bldr.sequence } -// GetGas returns the gas for the transaction -func (bldr TxBuilder) GetGas() uint64 { return bldr.gas } +// Gas returns the gas for the transaction +func (bldr TxBuilder) Gas() uint64 { return bldr.gas } -// GetGasAdjustment returns the gas adjustment -func (bldr TxBuilder) GetGasAdjustment() float64 { return bldr.gasAdjustment } +// GasAdjustment returns the gas adjustment +func (bldr TxBuilder) GasAdjustment() float64 { return bldr.gasAdjustment } -// GetSimulateAndExecute returns the option to simulate and then execute the transaction +// Keybase returns the keybase +func (bldr TxBuilder) Keybase() crkeys.Keybase { return bldr.keybase } + +// SimulateAndExecute returns the option to simulate and then execute the transaction // using the gas from the simulation results -func (bldr TxBuilder) GetSimulateAndExecute() bool { return bldr.simulateAndExecute } +func (bldr TxBuilder) SimulateAndExecute() bool { return bldr.simulateAndExecute } -// GetChainID returns the chain id -func (bldr TxBuilder) GetChainID() string { return bldr.chainID } +// ChainID returns the chain id +func (bldr TxBuilder) ChainID() string { return bldr.chainID } -// GetMemo returns the memo message -func (bldr TxBuilder) GetMemo() string { return bldr.memo } +// Memo returns the memo message +func (bldr TxBuilder) Memo() string { return bldr.memo } -// GetFees returns the fees for the transaction -func (bldr TxBuilder) GetFees() sdk.Coins { return bldr.fees } +// Fees returns the fees for the transaction +func (bldr TxBuilder) Fees() sdk.Coins { return bldr.fees } -// GetGasPrices returns the gas prices set for the transaction, if any. -func (bldr TxBuilder) GetGasPrices() sdk.DecCoins { return bldr.gasPrices } +// GasPrices returns the gas prices set for the transaction, if any. +func (bldr TxBuilder) GasPrices() sdk.DecCoins { return bldr.gasPrices } // WithTxEncoder returns a copy of the context with an updated codec. func (bldr TxBuilder) WithTxEncoder(txEncoder sdk.TxEncoder) TxBuilder { @@ -136,6 +148,12 @@ func (bldr TxBuilder) WithGasPrices(gasPrices string) TxBuilder { return bldr } +// WithKeybase returns a copy of the context with updated keybase. +func (bldr TxBuilder) WithKeybase(keybase crkeys.Keybase) TxBuilder { + bldr.keybase = keybase + return bldr +} + // WithSequence returns a copy of the context with an updated sequence number. func (bldr TxBuilder) WithSequence(sequence uint64) TxBuilder { bldr.sequence = sequence @@ -194,7 +212,7 @@ func (bldr TxBuilder) Build(msgs []sdk.Msg) (StdSignMsg, error) { // Sign signs a transaction given a name, passphrase, and a single message to // signed. An error is returned if signing fails. func (bldr TxBuilder) Sign(name, passphrase string, msg StdSignMsg) ([]byte, error) { - sig, err := MakeSignature(name, passphrase, msg) + sig, err := MakeSignature(bldr.keybase, name, passphrase, msg) if err != nil { return nil, err } @@ -230,7 +248,7 @@ func (bldr TxBuilder) BuildTxForSim(msgs []sdk.Msg) ([]byte, error) { // SignStdTx appends a signature to a StdTx and returns a copy of a it. If append // is false, it replaces the signatures already attached with the new signature. func (bldr TxBuilder) SignStdTx(name, passphrase string, stdTx auth.StdTx, appendSig bool) (signedStdTx auth.StdTx, err error) { - stdSignature, err := MakeSignature(name, passphrase, StdSignMsg{ + stdSignature, err := MakeSignature(bldr.keybase, name, passphrase, StdSignMsg{ ChainID: bldr.chainID, AccountNumber: bldr.accountNumber, Sequence: bldr.sequence, @@ -252,12 +270,16 @@ func (bldr TxBuilder) SignStdTx(name, passphrase string, stdTx auth.StdTx, appen return } -// MakeSignature builds a StdSignature given key name, passphrase, and a StdSignMsg. -func MakeSignature(name, passphrase string, msg StdSignMsg) (sig auth.StdSignature, err error) { - keybase, err := keys.GetKeyBase() - if err != nil { - return +// MakeSignature builds a StdSignature given keybase, key name, passphrase, and a StdSignMsg. +func MakeSignature(keybase crkeys.Keybase, name, passphrase string, + msg StdSignMsg) (sig auth.StdSignature, err error) { + if keybase == nil { + keybase, err = keys.NewKeyBaseFromHomeFlag() + if err != nil { + return + } } + sigBytes, pubkey, err := keybase.Sign(name, passphrase, msg.Bytes()) if err != nil { return