Merge PR #3514: don't lock keybase on lcd startup

This commit is contained in:
Alessio Treglia 2019-02-06 11:23:49 -08:00 committed by Jack Zampolin
parent 37b8e37567
commit 9a57ce0214
23 changed files with 333 additions and 219 deletions

1
Gopkg.lock generated
View File

@ -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",

View File

@ -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.

View File

@ -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
}

View File

@ -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())
}

View File

@ -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 == "" {

View File

@ -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()))

View File

@ -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()))

View File

@ -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()))

View File

@ -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

View File

@ -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()
}

View File

@ -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()

View File

@ -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

View File

@ -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 {

View File

@ -153,7 +153,7 @@ func CompleteAndBroadcastTxREST(
}
if baseReq.Simulate {
WriteSimulationResponse(w, cdc, txBldr.GetGas())
WriteSimulationResponse(w, cdc, txBldr.Gas())
return
}
}

View File

@ -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)

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

165
crypto/keys/lazy_keybase.go Normal file
View File

@ -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() {}

View File

@ -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
}

View File

@ -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 {

View File

@ -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")
}

View File

@ -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