Update keybase back to cosmos-sdk with support (#147)
* Migrate keybase back to Cosmos-sdk using temporary fork * Cleaned up other affected code * Change to updated tendermint * fmt * Change auth codec update * clean up codec registration to respective packages * Fix import fmt * Remove no longer necessary replace * Fix function comment
This commit is contained in:
parent
327abc4edf
commit
9311f9efd0
@ -4,10 +4,12 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||||
"github.com/cosmos/ethermint/x/evm"
|
"github.com/cosmos/ethermint/x/evm"
|
||||||
|
|
||||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
cryptokeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/types/module"
|
"github.com/cosmos/cosmos-sdk/types/module"
|
||||||
"github.com/cosmos/cosmos-sdk/version"
|
"github.com/cosmos/cosmos-sdk/version"
|
||||||
@ -76,8 +78,10 @@ func MakeCodec() *codec.Codec {
|
|||||||
var cdc = codec.New()
|
var cdc = codec.New()
|
||||||
|
|
||||||
ModuleBasics.RegisterCodec(cdc)
|
ModuleBasics.RegisterCodec(cdc)
|
||||||
|
cryptokeys.RegisterCodec(cdc) // temporary
|
||||||
sdk.RegisterCodec(cdc)
|
sdk.RegisterCodec(cdc)
|
||||||
codec.RegisterCrypto(cdc)
|
codec.RegisterCrypto(cdc)
|
||||||
|
emintcrypto.RegisterCodec(cdc)
|
||||||
eminttypes.RegisterCodec(cdc)
|
eminttypes.RegisterCodec(cdc)
|
||||||
|
|
||||||
return cdc
|
return cdc
|
||||||
|
68
cmd/emintcli/keys.go
Normal file
68
cmd/emintcli/keys.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
|
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
|
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
|
|
||||||
|
emintCrypto "github.com/cosmos/ethermint/crypto"
|
||||||
|
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
flagDryRun = "dry-run"
|
||||||
|
)
|
||||||
|
|
||||||
|
// keyCommands registers a sub-tree of commands to interact with
|
||||||
|
// local private key storage.
|
||||||
|
func keyCommands() *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "keys",
|
||||||
|
Short: "Add or view local private keys",
|
||||||
|
Long: `Keys allows you to manage your local keystore for tendermint.
|
||||||
|
|
||||||
|
These keys may be in any format supported by go-crypto and can be
|
||||||
|
used by light-clients, full nodes, or any other application that
|
||||||
|
needs to sign with a private key.`,
|
||||||
|
}
|
||||||
|
addCmd := clientkeys.AddKeyCommand()
|
||||||
|
addCmd.RunE = runAddCmd
|
||||||
|
cmd.AddCommand(
|
||||||
|
clientkeys.MnemonicKeyCommand(),
|
||||||
|
addCmd,
|
||||||
|
clientkeys.ExportKeyCommand(),
|
||||||
|
clientkeys.ImportKeyCommand(),
|
||||||
|
clientkeys.ListKeysCmd(),
|
||||||
|
clientkeys.ShowKeysCmd(),
|
||||||
|
flags.LineBreak,
|
||||||
|
clientkeys.DeleteKeyCommand(),
|
||||||
|
clientkeys.UpdateKeyCommand(),
|
||||||
|
clientkeys.ParseKeyStringCommand(),
|
||||||
|
clientkeys.MigrateCommand(),
|
||||||
|
)
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKeybase(dryrun bool) (keys.Keybase, error) {
|
||||||
|
if dryrun {
|
||||||
|
return keys.NewInMemory(keys.WithKeygenFunc(ethermintKeygenFunc)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientkeys.NewKeyBaseFromHomeFlag(keys.WithKeygenFunc(ethermintKeygenFunc))
|
||||||
|
}
|
||||||
|
|
||||||
|
func runAddCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
kb, err := getKeybase(viper.GetBool(flagDryRun))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientkeys.RunAddCmd(cmd, args, kb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ethermintKeygenFunc(bz [32]byte) tmcrypto.PrivKey {
|
||||||
|
return emintCrypto.PrivKeySecp256k1(bz[:])
|
||||||
|
}
|
@ -4,19 +4,20 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
emintapp "github.com/cosmos/ethermint/app"
|
||||||
"github.com/cosmos/ethermint/rpc"
|
"github.com/cosmos/ethermint/rpc"
|
||||||
|
|
||||||
"github.com/tendermint/go-amino"
|
"github.com/tendermint/go-amino"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
sdkrpc "github.com/cosmos/cosmos-sdk/client/rpc"
|
sdkrpc "github.com/cosmos/cosmos-sdk/client/rpc"
|
||||||
|
cryptokeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
||||||
emintkeys "github.com/cosmos/ethermint/keys"
|
|
||||||
|
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||||
|
|
||||||
emintapp "github.com/cosmos/ethermint/app"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
@ -27,7 +28,8 @@ func main() {
|
|||||||
|
|
||||||
cdc := emintapp.MakeCodec()
|
cdc := emintapp.MakeCodec()
|
||||||
|
|
||||||
authtypes.ModuleCdc = cdc
|
cryptokeys.CryptoCdc = cdc
|
||||||
|
clientkeys.KeysCdc = cdc
|
||||||
|
|
||||||
// Read in the configuration file for the sdk
|
// Read in the configuration file for the sdk
|
||||||
config := sdk.GetConfig()
|
config := sdk.GetConfig()
|
||||||
@ -56,7 +58,7 @@ func main() {
|
|||||||
// TODO: Set up rest routes (if included, different from web3 api)
|
// TODO: Set up rest routes (if included, different from web3 api)
|
||||||
rpc.Web3RpcCmd(cdc),
|
rpc.Web3RpcCmd(cdc),
|
||||||
client.LineBreak,
|
client.LineBreak,
|
||||||
emintkeys.Commands(),
|
keyCommands(),
|
||||||
client.LineBreak,
|
client.LineBreak,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
@ -16,7 +17,6 @@ import (
|
|||||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||||
authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting"
|
authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting"
|
||||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||||
"github.com/cosmos/ethermint/keys"
|
|
||||||
|
|
||||||
ethermint "github.com/cosmos/ethermint/types"
|
ethermint "github.com/cosmos/ethermint/types"
|
||||||
)
|
)
|
||||||
|
@ -1,302 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
flag "github.com/spf13/pflag"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
cfg "github.com/tendermint/tendermint/config"
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
"github.com/tendermint/tendermint/libs/common"
|
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
|
||||||
kbkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/cosmos/cosmos-sdk/types/module"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/genutil/types"
|
|
||||||
|
|
||||||
"github.com/cosmos/ethermint/keys"
|
|
||||||
clientutils "github.com/cosmos/ethermint/x/evm/client/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
// StakingMsgBuildingHelpers helpers for message building gen-tx command
|
|
||||||
type StakingMsgBuildingHelpers interface {
|
|
||||||
CreateValidatorMsgHelpers(ipDefault string) (fs *flag.FlagSet, nodeIDFlag, pubkeyFlag, amountFlag, defaultsDesc string)
|
|
||||||
PrepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, chainID string, valPubKey crypto.PubKey)
|
|
||||||
BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) (auth.TxBuilder, sdk.Msg, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenTxCmd builds the application's gentx command.
|
|
||||||
// nolint: errcheck
|
|
||||||
func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, smbh StakingMsgBuildingHelpers,
|
|
||||||
genAccIterator types.GenesisAccountsIterator, defaultNodeHome, defaultCLIHome string) *cobra.Command {
|
|
||||||
|
|
||||||
ipDefault, _ := server.ExternalIP()
|
|
||||||
fsCreateValidator, flagNodeID, flagPubKey, flagAmount, defaultsDesc := smbh.CreateValidatorMsgHelpers(ipDefault)
|
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "gentx",
|
|
||||||
Short: "Generate a genesis tx carrying a self delegation",
|
|
||||||
Args: cobra.NoArgs,
|
|
||||||
Long: fmt.Sprintf(`This command is an alias of the 'tx create-validator' command'.
|
|
||||||
|
|
||||||
It creates a genesis transaction to create a validator.
|
|
||||||
The following default parameters are included:
|
|
||||||
%s`, defaultsDesc),
|
|
||||||
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
|
|
||||||
config := ctx.Config
|
|
||||||
config.SetRoot(viper.GetString(client.FlagHome))
|
|
||||||
nodeID, valPubKey, err := genutil.InitializeNodeValidatorFiles(ctx.Config)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to initialize node validator files")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read --nodeID, if empty take it from priv_validator.json
|
|
||||||
if nodeIDString := viper.GetString(flagNodeID); nodeIDString != "" {
|
|
||||||
nodeID = nodeIDString
|
|
||||||
}
|
|
||||||
// Read --pubkey, if empty take it from priv_validator.json
|
|
||||||
if valPubKeyString := viper.GetString(flagPubKey); valPubKeyString != "" {
|
|
||||||
valPubKey, err = sdk.GetConsPubKeyBech32(valPubKeyString)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to get consensus node public key")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
genDoc, err := tmtypes.GenesisDocFromFile(config.GenesisFile())
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to read genesis doc file %s", config.GenesisFile())
|
|
||||||
}
|
|
||||||
|
|
||||||
var genesisState map[string]json.RawMessage
|
|
||||||
if err = cdc.UnmarshalJSON(genDoc.AppState, &genesisState); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to unmarshal genesis state")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = mbm.ValidateGenesis(genesisState); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to validate genesis state")
|
|
||||||
}
|
|
||||||
|
|
||||||
// * Necessary to change keybase here
|
|
||||||
kb, err := keys.NewKeyBaseFromDir(viper.GetString(flagClientHome))
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to initialize keybase")
|
|
||||||
}
|
|
||||||
|
|
||||||
name := viper.GetString(client.FlagName)
|
|
||||||
key, err := kb.Get(name)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to read from keybase")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set flags for creating gentx
|
|
||||||
viper.Set(client.FlagHome, viper.GetString(flagClientHome))
|
|
||||||
smbh.PrepareFlagsForTxCreateValidator(config, nodeID, genDoc.ChainID, valPubKey)
|
|
||||||
|
|
||||||
// Fetch the amount of coins staked
|
|
||||||
amount := viper.GetString(flagAmount)
|
|
||||||
coins, err := sdk.ParseCoins(amount)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to parse coins")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = genutil.ValidateAccountInGenesis(genesisState, genAccIterator, key.GetAddress(), coins, cdc)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to validate account in genesis")
|
|
||||||
}
|
|
||||||
|
|
||||||
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)).WithKeybase(kb)
|
|
||||||
cliCtx := clientutils.NewETHCLIContext().WithCodec(cdc)
|
|
||||||
|
|
||||||
// Set the generate-only flag here after the CLI context has
|
|
||||||
// been created. This allows the from name/key to be correctly populated.
|
|
||||||
//
|
|
||||||
// TODO: Consider removing the manual setting of generate-only in
|
|
||||||
// favor of a 'gentx' flag in the create-validator command.
|
|
||||||
viper.Set(client.FlagGenerateOnly, true)
|
|
||||||
|
|
||||||
// create a 'create-validator' message
|
|
||||||
txBldr, msg, err := smbh.BuildCreateValidatorMsg(cliCtx, txBldr)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to build create-validator message")
|
|
||||||
}
|
|
||||||
|
|
||||||
info, err := kb.Get(name)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to read from tx builder keybase")
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.GetType() == kbkeys.TypeOffline || info.GetType() == kbkeys.TypeMulti {
|
|
||||||
fmt.Println("Offline key passed in. Use `tx sign` command to sign:")
|
|
||||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the unsigned transaction to the buffer
|
|
||||||
w := bytes.NewBuffer([]byte{})
|
|
||||||
cliCtx = cliCtx.WithOutput(w)
|
|
||||||
|
|
||||||
if err = utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to print unsigned std tx")
|
|
||||||
}
|
|
||||||
|
|
||||||
// read the transaction
|
|
||||||
stdTx, err := readUnsignedGenTxFile(cdc, w)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to read unsigned gen tx file")
|
|
||||||
}
|
|
||||||
|
|
||||||
// * Function needed to be overriden for signStdTx function using default keybase
|
|
||||||
// sign the transaction and write it to the output file
|
|
||||||
signedTx, err := signStdTx(txBldr, cliCtx, name, stdTx, false, true)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to sign std tx")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch output file name
|
|
||||||
outputDocument := viper.GetString(client.FlagOutputDocument)
|
|
||||||
if outputDocument == "" {
|
|
||||||
outputDocument, err = makeOutputFilepath(config.RootDir, nodeID)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create output file path")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := writeSignedGenTx(cdc, outputDocument, signedTx); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to write signed gen tx")
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "Genesis transaction written to %q\n", outputDocument)
|
|
||||||
return nil
|
|
||||||
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.Flags().String(client.FlagHome, defaultNodeHome, "node's home directory")
|
|
||||||
cmd.Flags().String(flagClientHome, defaultCLIHome, "client's home directory")
|
|
||||||
cmd.Flags().String(client.FlagName, "", "name of private key with which to sign the gentx")
|
|
||||||
cmd.Flags().String(client.FlagOutputDocument, "",
|
|
||||||
"write the genesis transaction JSON document to the given file instead of the default location")
|
|
||||||
cmd.Flags().AddFlagSet(fsCreateValidator)
|
|
||||||
|
|
||||||
if err := cmd.MarkFlagRequired(client.FlagName); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeOutputFilepath(rootDir, nodeID string) (string, error) {
|
|
||||||
writePath := filepath.Join(rootDir, "config", "gentx")
|
|
||||||
if err := common.EnsureDir(writePath, 0700); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readUnsignedGenTxFile(cdc *codec.Codec, r io.Reader) (auth.StdTx, error) {
|
|
||||||
var stdTx auth.StdTx
|
|
||||||
bytes, err := ioutil.ReadAll(r)
|
|
||||||
if err != nil {
|
|
||||||
return stdTx, err
|
|
||||||
}
|
|
||||||
err = cdc.UnmarshalJSON(bytes, &stdTx)
|
|
||||||
return stdTx, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeSignedGenTx(cdc *codec.Codec, outputDocument string, tx auth.StdTx) error {
|
|
||||||
outputFile, err := os.OpenFile(outputDocument, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err := outputFile.Close(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
json, err := cdc.MarshalJSON(tx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = fmt.Fprintf(outputFile, "%s\n", json)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignStdTx appends a signature to a StdTx and returns a copy of it. If appendSig
|
|
||||||
// is false, it replaces the signatures already attached with the new signature.
|
|
||||||
// Don't perform online validation or lookups if offline is true.
|
|
||||||
func signStdTx(
|
|
||||||
txBldr authtypes.TxBuilder, cliCtx context.CLIContext, name string,
|
|
||||||
stdTx authtypes.StdTx, appendSig bool, offline bool,
|
|
||||||
) (authtypes.StdTx, error) {
|
|
||||||
|
|
||||||
var signedStdTx authtypes.StdTx
|
|
||||||
|
|
||||||
info, err := txBldr.Keybase().Get(name)
|
|
||||||
if err != nil {
|
|
||||||
return signedStdTx, err
|
|
||||||
}
|
|
||||||
|
|
||||||
addr := info.GetPubKey().Address()
|
|
||||||
|
|
||||||
// check whether the address is a signer
|
|
||||||
if !isTxSigner(sdk.AccAddress(addr), stdTx.GetSigners()) {
|
|
||||||
return signedStdTx, fmt.Errorf("%s: %s", errors.New("tx intended signer does not match the given signer"), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !offline {
|
|
||||||
txBldr, err = populateAccountFromState(txBldr, cliCtx, sdk.AccAddress(addr))
|
|
||||||
if err != nil {
|
|
||||||
return signedStdTx, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// * Switched to use Ethermint keybase
|
|
||||||
passphrase, err := keys.GetPassphrase(name)
|
|
||||||
if err != nil {
|
|
||||||
return signedStdTx, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return txBldr.SignStdTx(name, passphrase, stdTx, appendSig)
|
|
||||||
}
|
|
||||||
|
|
||||||
func populateAccountFromState(
|
|
||||||
txBldr authtypes.TxBuilder, cliCtx context.CLIContext, addr sdk.AccAddress,
|
|
||||||
) (authtypes.TxBuilder, error) {
|
|
||||||
|
|
||||||
num, seq, err := authtypes.NewAccountRetriever(cliCtx).GetAccountNumberSequence(addr)
|
|
||||||
if err != nil {
|
|
||||||
return txBldr, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return txBldr.WithAccountNumber(num).WithSequence(seq), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isTxSigner(user sdk.AccAddress, signers []sdk.AccAddress) bool {
|
|
||||||
for _, s := range signers {
|
|
||||||
if bytes.Equal(user.Bytes(), s.Bytes()) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
@ -8,12 +8,13 @@ import (
|
|||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
|
cryptokeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
"github.com/cosmos/cosmos-sdk/store"
|
"github.com/cosmos/cosmos-sdk/store"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||||
genutil "github.com/cosmos/cosmos-sdk/x/genutil"
|
|
||||||
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
|
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
|
||||||
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||||
@ -36,9 +37,10 @@ func main() {
|
|||||||
|
|
||||||
cdc := emintapp.MakeCodec()
|
cdc := emintapp.MakeCodec()
|
||||||
|
|
||||||
|
cryptokeys.CryptoCdc = cdc
|
||||||
genutil.ModuleCdc = cdc
|
genutil.ModuleCdc = cdc
|
||||||
genutiltypes.ModuleCdc = cdc
|
genutiltypes.ModuleCdc = cdc
|
||||||
authtypes.ModuleCdc = cdc
|
clientkeys.KeysCdc = cdc
|
||||||
|
|
||||||
config := sdk.GetConfig()
|
config := sdk.GetConfig()
|
||||||
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
|
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
|
||||||
@ -57,7 +59,7 @@ func main() {
|
|||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
withChainIDValidation(genutilcli.InitCmd(ctx, cdc, emintapp.ModuleBasics, emintapp.DefaultNodeHome)),
|
withChainIDValidation(genutilcli.InitCmd(ctx, cdc, emintapp.ModuleBasics, emintapp.DefaultNodeHome)),
|
||||||
genutilcli.CollectGenTxsCmd(ctx, cdc, auth.GenesisAccountIterator{}, emintapp.DefaultNodeHome),
|
genutilcli.CollectGenTxsCmd(ctx, cdc, auth.GenesisAccountIterator{}, emintapp.DefaultNodeHome),
|
||||||
GenTxCmd(
|
genutilcli.GenTxCmd(
|
||||||
ctx, cdc, emintapp.ModuleBasics, staking.AppModuleBasic{}, auth.GenesisAccountIterator{}, emintapp.DefaultNodeHome, emintapp.DefaultCLIHome,
|
ctx, cdc, emintapp.ModuleBasics, staking.AppModuleBasic{}, auth.GenesisAccountIterator{}, emintapp.DefaultNodeHome, emintapp.DefaultCLIHome,
|
||||||
),
|
),
|
||||||
genutilcli.ValidateGenesisCmd(ctx, cdc, emintapp.ModuleBasics),
|
genutilcli.ValidateGenesisCmd(ctx, cdc, emintapp.ModuleBasics),
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
|
||||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
|
||||||
emintCrypto "github.com/cosmos/ethermint/crypto"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cdc *codec.Codec
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cdc = codec.New()
|
|
||||||
cryptoAmino.RegisterAmino(cdc)
|
|
||||||
cdc.RegisterInterface((*cosmosKeys.Info)(nil), nil)
|
|
||||||
emintCrypto.RegisterCodec(cdc)
|
|
||||||
cdc.RegisterConcrete(hd.BIP44Params{}, "crypto/keys/hd/BIP44Params", nil)
|
|
||||||
cdc.RegisterConcrete(localInfo{}, "crypto/keys/localInfo", nil)
|
|
||||||
cdc.RegisterConcrete(ledgerInfo{}, "crypto/keys/ledgerInfo", nil)
|
|
||||||
cdc.RegisterConcrete(offlineInfo{}, "crypto/keys/offlineInfo", nil)
|
|
||||||
// cdc.RegisterConcrete(multiInfo{}, "crypto/keys/multiInfo", nil)
|
|
||||||
cdc.Seal()
|
|
||||||
}
|
|
@ -1,512 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto"
|
|
||||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
|
|
||||||
"github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/cosmos/ethermint/crypto/keys/mintkey"
|
|
||||||
|
|
||||||
bip39 "github.com/cosmos/go-bip39"
|
|
||||||
|
|
||||||
emintCrypto "github.com/cosmos/ethermint/crypto"
|
|
||||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
|
||||||
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
|
||||||
dbm "github.com/tendermint/tm-db"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ cosmosKeys.Keybase = dbKeybase{}
|
|
||||||
|
|
||||||
// Language is a language to create the BIP 39 mnemonic in.
|
|
||||||
// Currently, only english is supported though.
|
|
||||||
// Find a list of all supported languages in the BIP 39 spec (word lists).
|
|
||||||
type Language int
|
|
||||||
|
|
||||||
//noinspection ALL
|
|
||||||
const (
|
|
||||||
// English is the default language to create a mnemonic.
|
|
||||||
// It is the only supported language by this package.
|
|
||||||
English Language = iota + 1
|
|
||||||
// Japanese is currently not supported.
|
|
||||||
Japanese
|
|
||||||
// Korean is currently not supported.
|
|
||||||
Korean
|
|
||||||
// Spanish is currently not supported.
|
|
||||||
Spanish
|
|
||||||
// ChineseSimplified is currently not supported.
|
|
||||||
ChineseSimplified
|
|
||||||
// ChineseTraditional is currently not supported.
|
|
||||||
ChineseTraditional
|
|
||||||
// French is currently not supported.
|
|
||||||
French
|
|
||||||
// Italian is currently not supported.
|
|
||||||
Italian
|
|
||||||
addressSuffix = "address"
|
|
||||||
infoSuffix = "info"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// used for deriving seed from mnemonic
|
|
||||||
DefaultBIP39Passphrase = ""
|
|
||||||
|
|
||||||
// bits of entropy to draw when creating a mnemonic
|
|
||||||
defaultEntropySize = 256
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrUnsupportedSigningAlgo is raised when the caller tries to use a
|
|
||||||
// different signing scheme than secp256k1.
|
|
||||||
ErrUnsupportedSigningAlgo = errors.New("unsupported signing algo: only secp256k1 is supported")
|
|
||||||
|
|
||||||
// ErrUnsupportedLanguage is raised when the caller tries to use a
|
|
||||||
// different language than english for creating a mnemonic sentence.
|
|
||||||
ErrUnsupportedLanguage = errors.New("unsupported language: only english is supported")
|
|
||||||
)
|
|
||||||
|
|
||||||
// dbKeybase combines encryption and storage implementation to provide
|
|
||||||
// a full-featured key manager
|
|
||||||
type dbKeybase struct {
|
|
||||||
db dbm.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
// newDbKeybase creates a new keybase instance using the passed DB for reading and writing keys.
|
|
||||||
func newDbKeybase(db dbm.DB) cosmosKeys.Keybase {
|
|
||||||
return dbKeybase{
|
|
||||||
db: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInMemory creates a transient keybase on top of in-memory storage
|
|
||||||
// instance useful for testing purposes and on-the-fly key generation.
|
|
||||||
func NewInMemory() cosmosKeys.Keybase { return dbKeybase{dbm.NewMemDB()} }
|
|
||||||
|
|
||||||
// CreateMnemonic generates a new key and persists it to storage, encrypted
|
|
||||||
// using the provided password.
|
|
||||||
// It returns the generated mnemonic and the key Info.
|
|
||||||
// It returns an error if it fails to
|
|
||||||
// generate a key for the given algo type, or if another key is
|
|
||||||
// already stored under the same name.
|
|
||||||
func (kb dbKeybase) CreateMnemonic(name string, language cosmosKeys.Language, passwd string, algo cosmosKeys.SigningAlgo) (info cosmosKeys.Info, mnemonic string, err error) {
|
|
||||||
if language != cosmosKeys.English {
|
|
||||||
return nil, "", ErrUnsupportedLanguage
|
|
||||||
}
|
|
||||||
if algo != Secp256k1 {
|
|
||||||
err = ErrUnsupportedSigningAlgo
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// default number of words (24):
|
|
||||||
// this generates a mnemonic directly from the number of words by reading system entropy.
|
|
||||||
entropy, err := bip39.NewEntropy(defaultEntropySize)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mnemonic, err = bip39.NewMnemonic(entropy)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
seed := bip39.NewSeed(mnemonic, DefaultBIP39Passphrase)
|
|
||||||
fullFundraiserPath := types.GetConfig().GetFullFundraiserPath()
|
|
||||||
info, err = kb.persistDerivedKey(seed, passwd, name, fullFundraiserPath)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateAccount converts a mnemonic to a private key and persists it, encrypted with the given password.
|
|
||||||
func (kb dbKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (cosmosKeys.Info, error) {
|
|
||||||
coinType := types.GetConfig().GetCoinType()
|
|
||||||
hdPath := hd.NewFundraiserParams(account, coinType, index)
|
|
||||||
return kb.Derive(name, mnemonic, bip39Passwd, encryptPasswd, *hdPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb dbKeybase) Derive(name, mnemonic, bip39Passphrase, encryptPasswd string, params hd.BIP44Params) (info cosmosKeys.Info, err error) {
|
|
||||||
seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
info, err = kb.persistDerivedKey(seed, encryptPasswd, name, params.String())
|
|
||||||
return info, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateLedger creates a new locally-stored reference to a Ledger keypair
|
|
||||||
// It returns the created key info and an error if the Ledger could not be queried
|
|
||||||
func (kb dbKeybase) CreateLedger(name string, algo cosmosKeys.SigningAlgo, hrp string, account, index uint32) (cosmosKeys.Info, error) {
|
|
||||||
if algo != Secp256k1 {
|
|
||||||
return nil, ErrUnsupportedSigningAlgo
|
|
||||||
}
|
|
||||||
|
|
||||||
coinType := types.GetConfig().GetCoinType()
|
|
||||||
hdPath := hd.NewFundraiserParams(account, coinType, index)
|
|
||||||
priv, _, err := crypto.NewPrivKeyLedgerSecp256k1(*hdPath, hrp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
pub := priv.PubKey()
|
|
||||||
|
|
||||||
// Note: Once Cosmos App v1.3.1 is compulsory, it could be possible to check that pubkey and addr match
|
|
||||||
return kb.writeLedgerKey(name, pub, *hdPath), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateOffline creates a new reference to an offline keypair. It returns the
|
|
||||||
// created key info.
|
|
||||||
func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey) (cosmosKeys.Info, error) {
|
|
||||||
return kb.writeOfflineKey(name, pub), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateMulti creates a new reference to a multisig (offline) keypair. It
|
|
||||||
// returns the created key info.
|
|
||||||
func (kb dbKeybase) CreateMulti(name string, pub tmcrypto.PubKey) (cosmosKeys.Info, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath string) (info cosmosKeys.Info, err error) {
|
|
||||||
// create master key and derive first key:
|
|
||||||
masterPriv, ch := hd.ComputeMastersFromSeed(seed)
|
|
||||||
derivedPriv, err := hd.DerivePrivateKeyForPath(masterPriv, ch, fullHdPath)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have a password, use it to encrypt the private key and store it
|
|
||||||
// else store the public key only
|
|
||||||
if passwd != "" {
|
|
||||||
info = kb.writeLocalKey(name, emintCrypto.PrivKeySecp256k1(derivedPriv[:]), passwd)
|
|
||||||
} else {
|
|
||||||
pubk := emintCrypto.PrivKeySecp256k1(derivedPriv[:]).PubKey()
|
|
||||||
info = kb.writeOfflineKey(name, pubk)
|
|
||||||
}
|
|
||||||
return info, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// List returns the keys from storage in alphabetical order.
|
|
||||||
func (kb dbKeybase) List() ([]cosmosKeys.Info, error) {
|
|
||||||
var res []cosmosKeys.Info
|
|
||||||
iter := kb.db.Iterator(nil, nil)
|
|
||||||
defer iter.Close()
|
|
||||||
for ; iter.Valid(); iter.Next() {
|
|
||||||
key := string(iter.Key())
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the public information about one key.
|
|
||||||
func (kb dbKeybase) Get(name string) (cosmosKeys.Info, error) {
|
|
||||||
bs := kb.db.Get(infoKey(name))
|
|
||||||
if len(bs) == 0 {
|
|
||||||
return nil, keyerror.NewErrKeyNotFound(name)
|
|
||||||
}
|
|
||||||
return readInfo(bs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb dbKeybase) GetByAddress(address types.AccAddress) (cosmosKeys.Info, error) {
|
|
||||||
ik := kb.db.Get(addrKey(address))
|
|
||||||
if len(ik) == 0 {
|
|
||||||
return nil, fmt.Errorf("key with address %s not found", address)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
info, err := kb.Get(name)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var priv tmcrypto.PrivKey
|
|
||||||
|
|
||||||
switch info := info.(type) {
|
|
||||||
case localInfo:
|
|
||||||
if info.PrivKeyArmor == "" {
|
|
||||||
err = fmt.Errorf("private key not available")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
priv, err = mintkey.UnarmorDecryptPrivKey(info.PrivKeyArmor, passphrase)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
case ledgerInfo:
|
|
||||||
priv, err = crypto.NewPrivKeyLedgerSecp256k1Unsafe(info.Path)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// case offlineInfo, multiInfo:
|
|
||||||
case offlineInfo:
|
|
||||||
_, err := fmt.Fprintf(os.Stderr, "Message to sign:\n\n%s\n", msg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := bufio.NewReader(os.Stdin)
|
|
||||||
_, err = fmt.Fprintf(os.Stderr, "\nEnter Amino-encoded signature:\n")
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Will block until user inputs the signature
|
|
||||||
signed, err := buf.ReadString('\n')
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cdc.UnmarshalBinaryLengthPrefixed([]byte(signed), sig); err != nil {
|
|
||||||
return nil, nil, errors.Wrap(err, "failed to decode signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
return sig, info.GetPubKey(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
sig, err = priv.Sign(msg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pub = priv.PubKey()
|
|
||||||
return sig, pub, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcrypto.PrivKey, error) {
|
|
||||||
info, err := kb.Get(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var priv tmcrypto.PrivKey
|
|
||||||
|
|
||||||
switch info := info.(type) {
|
|
||||||
case localInfo:
|
|
||||||
if info.PrivKeyArmor == "" {
|
|
||||||
err = fmt.Errorf("private key not available")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
priv, err = mintkey.UnarmorDecryptPrivKey(info.PrivKeyArmor, passphrase)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// case ledgerInfo, offlineInfo, multiInfo:
|
|
||||||
case ledgerInfo, offlineInfo:
|
|
||||||
return nil, errors.New("only works on local private keys")
|
|
||||||
}
|
|
||||||
|
|
||||||
return priv, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb dbKeybase) Export(name string) (armor string, err error) {
|
|
||||||
bz := kb.db.Get(infoKey(name))
|
|
||||||
if bz == nil {
|
|
||||||
return "", fmt.Errorf("no key to export with name %s", name)
|
|
||||||
}
|
|
||||||
return mintkey.ArmorInfoBytes(bz), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExportPubKey returns public keys in ASCII armored format.
|
|
||||||
// Retrieve a Info object by its name and return the public key in
|
|
||||||
// a portable format.
|
|
||||||
func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) {
|
|
||||||
bz := kb.db.Get(infoKey(name))
|
|
||||||
if bz == nil {
|
|
||||||
return "", fmt.Errorf("no key to export with name %s", name)
|
|
||||||
}
|
|
||||||
info, err := readInfo(bz)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExportPrivKey returns a private key in ASCII armored format.
|
|
||||||
// It returns an error if the key does not exist or a wrong encryption passphrase is supplied.
|
|
||||||
func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string,
|
|
||||||
encryptPassphrase string) (armor string, err error) {
|
|
||||||
priv, err := kb.ExportPrivateKeyObject(name, decryptPassphrase)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return mintkey.EncryptArmorPrivKey(priv, encryptPassphrase), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImportPrivKey imports a private key in ASCII armor format.
|
|
||||||
// It returns an error if a key with the same name exists or a wrong encryption passphrase is
|
|
||||||
// supplied.
|
|
||||||
func (kb dbKeybase) ImportPrivKey(name string, armor string, passphrase string) error {
|
|
||||||
if _, err := kb.Get(name); err == nil {
|
|
||||||
return errors.New("Cannot overwrite key " + name)
|
|
||||||
}
|
|
||||||
|
|
||||||
privKey, err := mintkey.UnarmorDecryptPrivKey(armor, passphrase)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "couldn't import private key")
|
|
||||||
}
|
|
||||||
|
|
||||||
kb.writeLocalKey(name, privKey, passphrase)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb dbKeybase) Import(name string, armor string) (err error) {
|
|
||||||
bz := kb.db.Get(infoKey(name))
|
|
||||||
if len(bz) > 0 {
|
|
||||||
return errors.New("Cannot overwrite data for name " + name)
|
|
||||||
}
|
|
||||||
infoBytes, err := mintkey.UnarmorInfoBytes(armor)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
kb.db.Set(infoKey(name), infoBytes)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImportPubKey imports ASCII-armored public keys.
|
|
||||||
// Store a new Info object holding a public key only, i.e. it will
|
|
||||||
// not be possible to sign with it as it lacks the secret key.
|
|
||||||
func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) {
|
|
||||||
bz := kb.db.Get(infoKey(name))
|
|
||||||
if len(bz) > 0 {
|
|
||||||
return errors.New("Cannot overwrite data for name " + name)
|
|
||||||
}
|
|
||||||
pubBytes, err := mintkey.UnarmorPubKeyBytes(armor)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pubKey, err := cryptoAmino.PubKeyFromBytes(pubBytes)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
kb.writeOfflineKey(name, pubKey)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete removes key forever, but we must present the
|
|
||||||
// proper passphrase before deleting it (for security).
|
|
||||||
// It returns an error if the key doesn't exist or
|
|
||||||
// passphrases don't match.
|
|
||||||
// Passphrase is ignored when deleting references to
|
|
||||||
// offline and Ledger / HW wallet keys.
|
|
||||||
func (kb dbKeybase) Delete(name, passphrase string, skipPass bool) error {
|
|
||||||
// verify we have the proper password before deleting
|
|
||||||
info, err := kb.Get(name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if linfo, ok := info.(localInfo); ok && !skipPass {
|
|
||||||
if _, err = mintkey.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kb.db.DeleteSync(addrKey(info.GetAddress()))
|
|
||||||
kb.db.DeleteSync(infoKey(name))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update changes the passphrase with which an already stored key is
|
|
||||||
// encrypted.
|
|
||||||
//
|
|
||||||
// oldpass must be the current passphrase used for encryption,
|
|
||||||
// getNewpass is a function to get the passphrase to permanently replace
|
|
||||||
// the current passphrase
|
|
||||||
func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error {
|
|
||||||
info, err := kb.Get(name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch info := info.(type) {
|
|
||||||
case localInfo:
|
|
||||||
key, err := mintkey.UnarmorDecryptPrivKey(info.PrivKeyArmor, oldpass)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
newpass, err := getNewpass()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
kb.writeLocalKey(name, key, newpass)
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("locally stored key required. Received: %v", reflect.TypeOf(info).String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CloseDB releases the lock and closes the storage backend.
|
|
||||||
func (kb dbKeybase) CloseDB() {
|
|
||||||
kb.db.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb dbKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string) cosmosKeys.Info {
|
|
||||||
privkey, ok := priv.(emintCrypto.PrivKeySecp256k1)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("invalid private key type: %T", priv))
|
|
||||||
}
|
|
||||||
// encrypt private key using passphrase
|
|
||||||
privArmor := mintkey.EncryptArmorPrivKey(privkey, passphrase)
|
|
||||||
// make Info
|
|
||||||
pub := privkey.PubKey()
|
|
||||||
pubkey, ok := pub.(emintCrypto.PubKeySecp256k1)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("invalid public key type: %T", pub))
|
|
||||||
}
|
|
||||||
info := newLocalInfo(name, pubkey, privArmor)
|
|
||||||
kb.writeInfo(name, info)
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb dbKeybase) writeLedgerKey(name string, pub tmcrypto.PubKey, path hd.BIP44Params) cosmosKeys.Info {
|
|
||||||
pubkey, ok := pub.(emintCrypto.PubKeySecp256k1)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("invalid public key type: %T", pub))
|
|
||||||
}
|
|
||||||
info := newLedgerInfo(name, pubkey, path)
|
|
||||||
kb.writeInfo(name, info)
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb dbKeybase) writeOfflineKey(name string, pub tmcrypto.PubKey) cosmosKeys.Info {
|
|
||||||
pubkey, ok := pub.(emintCrypto.PubKeySecp256k1)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("invalid public key type: %T", pub))
|
|
||||||
}
|
|
||||||
info := newOfflineInfo(name, pubkey)
|
|
||||||
kb.writeInfo(name, info)
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kb dbKeybase) writeInfo(name string, info cosmosKeys.Info) {
|
|
||||||
// write the info by key
|
|
||||||
key := infoKey(name)
|
|
||||||
serializedInfo := writeInfo(info)
|
|
||||||
kb.db.SetSync(key, serializedInfo)
|
|
||||||
// store a pointer to the infokey by address for fast lookup
|
|
||||||
kb.db.SetSync(addrKey(info.GetAddress()), key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addrKey(address types.AccAddress) []byte {
|
|
||||||
return []byte(fmt.Sprintf("%s.%s", address.String(), addressSuffix))
|
|
||||||
}
|
|
||||||
|
|
||||||
func infoKey(name string) []byte {
|
|
||||||
return []byte(fmt.Sprintf("%s.%s", name, infoSuffix))
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SigningAlgo defines an algorithm to derive key-pairs which can be used for cryptographic signing.
|
|
||||||
type SigningAlgo string
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Secp256k1 uses the Bitcoin secp256k1 ECDSA parameters.
|
|
||||||
Secp256k1 = cosmosKeys.SigningAlgo("emintsecp256k1")
|
|
||||||
)
|
|
@ -1,222 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
|
||||||
|
|
||||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ cosmosKeys.Keybase = lazyKeybase{}
|
|
||||||
|
|
||||||
type lazyKeybase struct {
|
|
||||||
name string
|
|
||||||
dir string
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new instance of a lazy keybase.
|
|
||||||
func New(name, dir string) cosmosKeys.Keybase {
|
|
||||||
if err := cmn.EnsureDir(dir, 0700); err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to create Keybase directory: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lazyKeybase{name: name, dir: dir}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) List() ([]cosmosKeys.Info, error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).List()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) Get(name string) (cosmosKeys.Info, error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).Get(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) GetByAddress(address sdk.AccAddress) (cosmosKeys.Info, error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).GetByAddress(address)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) Delete(name, passphrase string, skipPass bool) error {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).Delete(name, passphrase, skipPass)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) Sign(name, passphrase string, msg []byte) ([]byte, crypto.PubKey, error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).Sign(name, passphrase, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) CreateMnemonic(name string, language cosmosKeys.Language, passwd string, algo cosmosKeys.SigningAlgo) (info cosmosKeys.Info, seed string, err error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).CreateMnemonic(name, language, passwd, algo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (cosmosKeys.Info, error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd, account, index)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) Derive(name, mnemonic, bip39Passwd, encryptPasswd string, params hd.BIP44Params) (cosmosKeys.Info, error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).Derive(name, mnemonic, bip39Passwd, encryptPasswd, params)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) CreateLedger(name string, algo cosmosKeys.SigningAlgo, hrp string, account, index uint32) (info cosmosKeys.Info, err error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).CreateLedger(name, algo, hrp, account, index)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) CreateOffline(name string, pubkey crypto.PubKey) (info cosmosKeys.Info, err error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).CreateOffline(name, pubkey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) CreateMulti(name string, pubkey crypto.PubKey) (info cosmosKeys.Info, err error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).CreateMulti(name, pubkey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) Update(name, oldpass string, getNewpass func() (string, error)) error {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).Update(name, oldpass, getNewpass)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) Import(name string, armor string) (err error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).Import(name, armor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) ImportPrivKey(name string, armor string, passphrase string) error {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).ImportPrivKey(name, armor, passphrase)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) ImportPubKey(name string, armor string) (err error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).ImportPubKey(name, armor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) Export(name string) (armor string, err error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).Export(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) ExportPubKey(name string) (armor string, err error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).ExportPubKey(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error) {
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).ExportPrivateKeyObject(name, passphrase)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) ExportPrivKey(name string, decryptPassphrase string,
|
|
||||||
encryptPassphrase string) (armor string, err error) {
|
|
||||||
|
|
||||||
db, err := sdk.NewLevelDB(lkb.name, lkb.dir)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
return newDbKeybase(db).ExportPrivKey(name, decryptPassphrase, encryptPassphrase)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lkb lazyKeybase) CloseDB() {}
|
|
@ -1,111 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
|
|
||||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
|
||||||
)
|
|
||||||
|
|
||||||
// KeyOutput defines a structure wrapping around an Info object used for output
|
|
||||||
// functionality.
|
|
||||||
type KeyOutput struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Address string `json:"address"`
|
|
||||||
ETHAddress string `json:"ethaddress"`
|
|
||||||
PubKey string `json:"pubkey"`
|
|
||||||
ETHPubKey string `json:"ethpubkey"`
|
|
||||||
Mnemonic string `json:"mnemonic,omitempty"`
|
|
||||||
Threshold uint `json:"threshold,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewKeyOutput creates a default KeyOutput instance without Mnemonic, Threshold and PubKeys
|
|
||||||
func NewKeyOutput(name, keyType, address, ethaddress, pubkey, ethpubkey string) KeyOutput {
|
|
||||||
return KeyOutput{
|
|
||||||
Name: name,
|
|
||||||
Type: keyType,
|
|
||||||
Address: address,
|
|
||||||
ETHAddress: ethaddress,
|
|
||||||
PubKey: pubkey,
|
|
||||||
ETHPubKey: ethpubkey,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bech32KeysOutput returns a slice of KeyOutput objects, each with the "acc"
|
|
||||||
// Bech32 prefixes, given a slice of Info objects. It returns an error if any
|
|
||||||
// call to Bech32KeyOutput fails.
|
|
||||||
func Bech32KeysOutput(infos []cosmosKeys.Info) ([]KeyOutput, error) {
|
|
||||||
kos := make([]KeyOutput, len(infos))
|
|
||||||
for i, info := range infos {
|
|
||||||
ko, err := Bech32KeyOutput(info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
kos[i] = ko
|
|
||||||
}
|
|
||||||
|
|
||||||
return kos, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bech32ConsKeyOutput create a KeyOutput in with "cons" Bech32 prefixes.
|
|
||||||
func Bech32ConsKeyOutput(keyInfo cosmosKeys.Info) (KeyOutput, error) {
|
|
||||||
address := keyInfo.GetPubKey().Address()
|
|
||||||
|
|
||||||
bechPubKey, err := sdk.Bech32ifyConsPub(keyInfo.GetPubKey())
|
|
||||||
if err != nil {
|
|
||||||
return KeyOutput{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewKeyOutput(
|
|
||||||
keyInfo.GetName(),
|
|
||||||
keyInfo.GetType().String(),
|
|
||||||
sdk.ConsAddress(address.Bytes()).String(),
|
|
||||||
getEthAddress(keyInfo),
|
|
||||||
bechPubKey,
|
|
||||||
hex.EncodeToString(keyInfo.GetPubKey().Bytes()),
|
|
||||||
), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bech32ValKeyOutput create a KeyOutput in with "val" Bech32 prefixes.
|
|
||||||
func Bech32ValKeyOutput(keyInfo cosmosKeys.Info) (KeyOutput, error) {
|
|
||||||
address := keyInfo.GetPubKey().Address()
|
|
||||||
|
|
||||||
bechPubKey, err := sdk.Bech32ifyValPub(keyInfo.GetPubKey())
|
|
||||||
if err != nil {
|
|
||||||
return KeyOutput{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewKeyOutput(
|
|
||||||
keyInfo.GetName(),
|
|
||||||
keyInfo.GetType().String(),
|
|
||||||
sdk.ValAddress(address.Bytes()).String(),
|
|
||||||
getEthAddress(keyInfo),
|
|
||||||
bechPubKey,
|
|
||||||
hex.EncodeToString(keyInfo.GetPubKey().Bytes()),
|
|
||||||
), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bech32KeyOutput create a KeyOutput in with "acc" Bech32 prefixes.
|
|
||||||
func Bech32KeyOutput(keyInfo cosmosKeys.Info) (KeyOutput, error) {
|
|
||||||
address := keyInfo.GetPubKey().Address()
|
|
||||||
|
|
||||||
bechPubKey, err := sdk.Bech32ifyAccPub(keyInfo.GetPubKey())
|
|
||||||
if err != nil {
|
|
||||||
return KeyOutput{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewKeyOutput(
|
|
||||||
keyInfo.GetName(),
|
|
||||||
keyInfo.GetType().String(),
|
|
||||||
sdk.AccAddress(address.Bytes()).String(),
|
|
||||||
getEthAddress(keyInfo),
|
|
||||||
bechPubKey,
|
|
||||||
hex.EncodeToString(keyInfo.GetPubKey().Bytes()),
|
|
||||||
), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getEthAddress(info cosmosKeys.Info) string {
|
|
||||||
return info.GetPubKey().Address().String()
|
|
||||||
}
|
|
@ -1,156 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
|
||||||
emintCrypto "github.com/cosmos/ethermint/crypto"
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
|
||||||
"github.com/cosmos/cosmos-sdk/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// KeyType reflects a human-readable type for key listing.
|
|
||||||
type KeyType uint
|
|
||||||
|
|
||||||
// Info KeyTypes
|
|
||||||
const (
|
|
||||||
TypeLocal KeyType = 0
|
|
||||||
TypeLedger KeyType = 1
|
|
||||||
TypeOffline KeyType = 2
|
|
||||||
TypeMulti KeyType = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
var keyTypes = map[KeyType]string{
|
|
||||||
TypeLocal: "local",
|
|
||||||
TypeLedger: "ledger",
|
|
||||||
TypeOffline: "offline",
|
|
||||||
TypeMulti: "multi",
|
|
||||||
}
|
|
||||||
|
|
||||||
// String implements the stringer interface for KeyType.
|
|
||||||
func (kt KeyType) String() string {
|
|
||||||
return keyTypes[kt]
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ cosmosKeys.Info = &localInfo{}
|
|
||||||
_ cosmosKeys.Info = &ledgerInfo{}
|
|
||||||
_ cosmosKeys.Info = &offlineInfo{}
|
|
||||||
)
|
|
||||||
|
|
||||||
// localInfo is the public information about a locally stored key
|
|
||||||
type localInfo struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
PubKey emintCrypto.PubKeySecp256k1 `json:"pubkey"`
|
|
||||||
PrivKeyArmor string `json:"privkey.armor"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func newLocalInfo(name string, pub emintCrypto.PubKeySecp256k1, privArmor string) cosmosKeys.Info {
|
|
||||||
return &localInfo{
|
|
||||||
Name: name,
|
|
||||||
PubKey: pub,
|
|
||||||
PrivKeyArmor: privArmor,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i localInfo) GetType() cosmosKeys.KeyType {
|
|
||||||
return cosmosKeys.TypeLocal
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i localInfo) GetName() string {
|
|
||||||
return i.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i localInfo) GetPubKey() crypto.PubKey {
|
|
||||||
return i.PubKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i localInfo) GetAddress() types.AccAddress {
|
|
||||||
return i.PubKey.Address().Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i localInfo) GetPath() (*hd.BIP44Params, error) {
|
|
||||||
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ledgerInfo is the public information about a Ledger key
|
|
||||||
type ledgerInfo struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
PubKey emintCrypto.PubKeySecp256k1 `json:"pubkey"`
|
|
||||||
Path hd.BIP44Params `json:"path"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func newLedgerInfo(name string, pub emintCrypto.PubKeySecp256k1, path hd.BIP44Params) cosmosKeys.Info {
|
|
||||||
return &ledgerInfo{
|
|
||||||
Name: name,
|
|
||||||
PubKey: pub,
|
|
||||||
Path: path,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i ledgerInfo) GetType() cosmosKeys.KeyType {
|
|
||||||
return cosmosKeys.TypeLedger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i ledgerInfo) GetName() string {
|
|
||||||
return i.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i ledgerInfo) GetPubKey() crypto.PubKey {
|
|
||||||
return i.PubKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i ledgerInfo) GetAddress() types.AccAddress {
|
|
||||||
return i.PubKey.Address().Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) {
|
|
||||||
tmp := i.Path
|
|
||||||
return &tmp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// offlineInfo is the public information about an offline key
|
|
||||||
type offlineInfo struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
PubKey emintCrypto.PubKeySecp256k1 `json:"pubkey"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func newOfflineInfo(name string, pub emintCrypto.PubKeySecp256k1) cosmosKeys.Info {
|
|
||||||
return &offlineInfo{
|
|
||||||
Name: name,
|
|
||||||
PubKey: pub,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i offlineInfo) GetType() cosmosKeys.KeyType {
|
|
||||||
return cosmosKeys.TypeOffline
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i offlineInfo) GetName() string {
|
|
||||||
return i.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i offlineInfo) GetPubKey() crypto.PubKey {
|
|
||||||
return i.PubKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i offlineInfo) GetAddress() types.AccAddress {
|
|
||||||
return i.PubKey.Address().Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i offlineInfo) GetPath() (*hd.BIP44Params, error) {
|
|
||||||
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
|
|
||||||
}
|
|
||||||
|
|
||||||
// encoding info
|
|
||||||
func writeInfo(i cosmosKeys.Info) []byte {
|
|
||||||
return cdc.MustMarshalBinaryLengthPrefixed(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// decoding info
|
|
||||||
func readInfo(bz []byte) (info cosmosKeys.Info, err error) {
|
|
||||||
err = cdc.UnmarshalBinaryLengthPrefixed(bz, &info)
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
|
||||||
"github.com/cosmos/ethermint/crypto"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWriteReadInfo(t *testing.T) {
|
|
||||||
tmpKey, err := crypto.GenerateKey()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
pkey := tmpKey.PubKey()
|
|
||||||
pubkey, ok := pkey.(crypto.PubKeySecp256k1)
|
|
||||||
assert.True(t, ok)
|
|
||||||
|
|
||||||
info := newOfflineInfo("offline", pubkey)
|
|
||||||
bytes := writeInfo(info)
|
|
||||||
assert.NotNil(t, bytes)
|
|
||||||
|
|
||||||
regeneratedKey, err := readInfo(bytes)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, info.GetPubKey(), regeneratedKey.GetPubKey())
|
|
||||||
assert.Equal(t, info.GetName(), regeneratedKey.GetName())
|
|
||||||
|
|
||||||
info = newLocalInfo("local", pubkey, "testarmor")
|
|
||||||
bytes = writeInfo(info)
|
|
||||||
assert.NotNil(t, bytes)
|
|
||||||
|
|
||||||
regeneratedKey, err = readInfo(bytes)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, info.GetPubKey(), regeneratedKey.GetPubKey())
|
|
||||||
assert.Equal(t, info.GetName(), regeneratedKey.GetName())
|
|
||||||
|
|
||||||
info = newLedgerInfo("ledger", pubkey,
|
|
||||||
hd.BIP44Params{Purpose: 1, CoinType: 1, Account: 1, Change: false, AddressIndex: 1})
|
|
||||||
bytes = writeInfo(info)
|
|
||||||
assert.NotNil(t, bytes)
|
|
||||||
|
|
||||||
regeneratedKey, err = readInfo(bytes)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, info.GetPubKey(), regeneratedKey.GetPubKey())
|
|
||||||
assert.Equal(t, info.GetName(), regeneratedKey.GetName())
|
|
||||||
|
|
||||||
}
|
|
@ -7,9 +7,19 @@ import (
|
|||||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||||
ethsecp256k1 "github.com/ethereum/go-ethereum/crypto/secp256k1"
|
ethsecp256k1 "github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||||
|
|
||||||
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
|
|
||||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||||
|
tmamino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tmamino.RegisterKeyType(PubKeySecp256k1{}, PubKeyAminoName)
|
||||||
|
tmamino.RegisterKeyType(PrivKeySecp256k1{}, PrivKeyAminoName)
|
||||||
|
authtypes.RegisterAccountTypeCodec(PubKeySecp256k1{}, PubKeyAminoName)
|
||||||
|
authtypes.RegisterAccountTypeCodec(PrivKeySecp256k1{}, PrivKeyAminoName)
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// secp256k1 Private Key
|
// secp256k1 Private Key
|
||||||
|
|
||||||
|
13
go.mod
13
go.mod
@ -8,7 +8,7 @@ require (
|
|||||||
github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8 // indirect
|
github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8 // indirect
|
||||||
github.com/cespare/cp v1.1.1 // indirect
|
github.com/cespare/cp v1.1.1 // indirect
|
||||||
github.com/cosmos/cosmos-sdk v0.34.4-0.20191031200835-02c6c9fafd58
|
github.com/cosmos/cosmos-sdk v0.34.4-0.20191031200835-02c6c9fafd58
|
||||||
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d
|
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect
|
||||||
github.com/deckarep/golang-set v1.7.1 // indirect
|
github.com/deckarep/golang-set v1.7.1 // indirect
|
||||||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 // indirect
|
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 // indirect
|
||||||
github.com/elastic/gosigar v0.10.3 // indirect
|
github.com/elastic/gosigar v0.10.3 // indirect
|
||||||
@ -35,8 +35,7 @@ require (
|
|||||||
github.com/rjeczalik/notify v0.9.2 // indirect
|
github.com/rjeczalik/notify v0.9.2 // indirect
|
||||||
github.com/spf13/afero v1.2.2 // indirect
|
github.com/spf13/afero v1.2.2 // indirect
|
||||||
github.com/spf13/cobra v0.0.5
|
github.com/spf13/cobra v0.0.5
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/viper v1.5.0
|
||||||
github.com/spf13/viper v1.4.0
|
|
||||||
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 // indirect
|
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 // indirect
|
||||||
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 // indirect
|
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 // indirect
|
||||||
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect
|
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect
|
||||||
@ -54,8 +53,10 @@ require (
|
|||||||
google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 // indirect
|
google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||||
gopkg.in/urfave/cli.v1 v1.0.0-00010101000000-000000000000 // indirect
|
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.4
|
|
||||||
)
|
)
|
||||||
|
|
||||||
replace gopkg.in/urfave/cli.v1 => github.com/urfave/cli v1.21.0
|
replace (
|
||||||
|
github.com/cosmos/cosmos-sdk v0.34.4-0.20191031200835-02c6c9fafd58 => github.com/chainsafe/cosmos-sdk v0.34.4-0.20191105182341-b5e2a1dfdcf6
|
||||||
|
github.com/tendermint/tendermint v0.32.7 => github.com/chainsafe/tendermint v0.32.2-0.20191105211315-bd56da568e15
|
||||||
|
)
|
||||||
|
25
go.sum
25
go.sum
@ -40,6 +40,10 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f
|
|||||||
github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU=
|
github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU=
|
||||||
github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
github.com/chainsafe/cosmos-sdk v0.34.4-0.20191105182341-b5e2a1dfdcf6 h1:v3aiYKq2JKNp86QHW53GuyIljwnOm+zF4H9WoQwqir0=
|
||||||
|
github.com/chainsafe/cosmos-sdk v0.34.4-0.20191105182341-b5e2a1dfdcf6/go.mod h1:jfj68M7UAsSvG+XmGU5zVfSij5fzlOdiQc1NKt+YK2A=
|
||||||
|
github.com/chainsafe/tendermint v0.32.2-0.20191105211315-bd56da568e15 h1:wGxBiAN4kWM/XfQnOIcnQH6rdzwfMelph+Y5CjqzYcw=
|
||||||
|
github.com/chainsafe/tendermint v0.32.2-0.20191105211315-bd56da568e15/go.mod h1:zhk6jGOCB5pi7NF8XtP77lqcDZ5n0biPwl2/AyS/vPM=
|
||||||
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
@ -48,8 +52,6 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz
|
|||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cosmos/cosmos-sdk v0.34.4-0.20191031200835-02c6c9fafd58 h1:B3fXc6Y9ztj9glE2ANU0+NQJ0M1BXaG5LpnyKFwHW4M=
|
|
||||||
github.com/cosmos/cosmos-sdk v0.34.4-0.20191031200835-02c6c9fafd58/go.mod h1:PuN72vbZxlorpnHmoIl6RjzVMXEOMejmwORJlZ74K7Q=
|
|
||||||
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8 h1:Iwin12wRQtyZhH6FV3ykFcdGNlYEzoeR0jN8Vn+JWsI=
|
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8 h1:Iwin12wRQtyZhH6FV3ykFcdGNlYEzoeR0jN8Vn+JWsI=
|
||||||
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
|
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
|
||||||
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU=
|
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU=
|
||||||
@ -115,8 +117,6 @@ github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
|
|||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE=
|
|
||||||
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
|
||||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
@ -308,8 +308,8 @@ github.com/spf13/viper v1.0.0 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I=
|
|||||||
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
||||||
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
|
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
|
||||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
github.com/spf13/viper v1.5.0 h1:GpsTwfsQ27oS/Aha/6d1oD7tpKIqWnOA6tgOX9HHkt4=
|
||||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4=
|
||||||
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw=
|
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw=
|
||||||
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
||||||
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE=
|
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE=
|
||||||
@ -328,6 +328,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
|
|||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stumble/gorocksdb v0.0.3 h1:9UU+QA1pqFYJuf9+5p7z1IqdE5k0mma4UAeu2wmX8kA=
|
github.com/stumble/gorocksdb v0.0.3 h1:9UU+QA1pqFYJuf9+5p7z1IqdE5k0mma4UAeu2wmX8kA=
|
||||||
github.com/stumble/gorocksdb v0.0.3/go.mod h1:v6IHdFBXk5DJ1K4FZ0xi+eY737quiiBxYtSWXadLybY=
|
github.com/stumble/gorocksdb v0.0.3/go.mod h1:v6IHdFBXk5DJ1K4FZ0xi+eY737quiiBxYtSWXadLybY=
|
||||||
|
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw=
|
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw=
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
||||||
github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s=
|
github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s=
|
||||||
@ -341,8 +343,6 @@ github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoM
|
|||||||
github.com/tendermint/iavl v0.12.4 h1:hd1woxUGISKkfUWBA4mmmTwOua6PQZTJM/F0FDrmMV8=
|
github.com/tendermint/iavl v0.12.4 h1:hd1woxUGISKkfUWBA4mmmTwOua6PQZTJM/F0FDrmMV8=
|
||||||
github.com/tendermint/iavl v0.12.4/go.mod h1:8LHakzt8/0G3/I8FUU0ReNx98S/EP6eyPJkAUvEXT/o=
|
github.com/tendermint/iavl v0.12.4/go.mod h1:8LHakzt8/0G3/I8FUU0ReNx98S/EP6eyPJkAUvEXT/o=
|
||||||
github.com/tendermint/tendermint v0.32.1/go.mod h1:jmPDAKuNkev9793/ivn/fTBnfpA9mGBww8MPRNPNxnU=
|
github.com/tendermint/tendermint v0.32.1/go.mod h1:jmPDAKuNkev9793/ivn/fTBnfpA9mGBww8MPRNPNxnU=
|
||||||
github.com/tendermint/tendermint v0.32.7 h1:Szu5Fm1L3pvn3t4uQxPAcP+7ndZEQKgLie/yokM56rU=
|
|
||||||
github.com/tendermint/tendermint v0.32.7/go.mod h1:D2+A3pNjY+Po72X0mTfaXorFhiVI8dh/Zg640FGyGtE=
|
|
||||||
github.com/tendermint/tm-db v0.1.1 h1:G3Xezy3sOk9+ekhjZ/kjArYIs1SmwV+1OUgNkj7RgV0=
|
github.com/tendermint/tm-db v0.1.1 h1:G3Xezy3sOk9+ekhjZ/kjArYIs1SmwV+1OUgNkj7RgV0=
|
||||||
github.com/tendermint/tm-db v0.1.1/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw=
|
github.com/tendermint/tm-db v0.1.1/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw=
|
||||||
github.com/tendermint/tm-db v0.2.0 h1:rJxgdqn6fIiVJZy4zLpY1qVlyD0TU6vhkT4kEf71TQQ=
|
github.com/tendermint/tm-db v0.2.0 h1:rJxgdqn6fIiVJZy4zLpY1qVlyD0TU6vhkT4kEf71TQQ=
|
||||||
@ -352,8 +352,6 @@ github.com/tyler-smith/go-bip39 v1.0.0 h1:FOHg9gaQLeBBRbHE/QrTLfEiBHy5pQ/yXzf9JG
|
|||||||
github.com/tyler-smith/go-bip39 v1.0.0/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
github.com/tyler-smith/go-bip39 v1.0.0/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
github.com/urfave/cli v1.21.0 h1:wYSSj06510qPIzGSua9ZqsncMmWE3Zr55KBERygyrxE=
|
|
||||||
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
|
|
||||||
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk=
|
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk=
|
||||||
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
|
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
@ -414,6 +412,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM=
|
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM=
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -447,8 +446,8 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
|
|||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw=
|
google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw=
|
||||||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk=
|
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
|
||||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@ -463,6 +462,8 @@ gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHN
|
|||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
|
||||||
|
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
258
keys/add.go
258
keys/add.go
@ -1,258 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/input"
|
|
||||||
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
|
||||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/cosmos/ethermint/crypto/keys"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/cosmos/go-bip39"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
flagInteractive = "interactive"
|
|
||||||
flagRecover = "recover"
|
|
||||||
flagNoBackup = "no-backup"
|
|
||||||
// flagDryRun = "dry-run"
|
|
||||||
flagAccount = "account"
|
|
||||||
flagIndex = "index"
|
|
||||||
// flagNoSort = "nosort"
|
|
||||||
|
|
||||||
// DefaultKeyPass contains the default key password for genesis transactions
|
|
||||||
DefaultKeyPass = "12345678"
|
|
||||||
|
|
||||||
mnemonicEntropySize = 256
|
|
||||||
)
|
|
||||||
|
|
||||||
func addKeyCommand() *cobra.Command {
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "add <name>",
|
|
||||||
Short: "Add an encrypted private key (either newly generated or recovered), encrypt it, and save to disk",
|
|
||||||
Long: `Derive a new private key and encrypt to disk.
|
|
||||||
Optionally specify a BIP39 mnemonic, a BIP39 passphrase to further secure the mnemonic,
|
|
||||||
and a bip32 HD path to derive a specific account. The key will be stored under the given name
|
|
||||||
and encrypted with the given password. The only input that is required is the encryption password.
|
|
||||||
|
|
||||||
If run with -i, it will prompt the user for BIP44 path, BIP39 mnemonic, and passphrase.
|
|
||||||
The flag --recover allows one to recover a key from a seed passphrase.
|
|
||||||
If run with --dry-run, a key would be generated (or recovered) but not stored to the
|
|
||||||
local keystore.
|
|
||||||
Use the --pubkey flag to add arbitrary public keys to the keystore for constructing
|
|
||||||
multisig transactions.
|
|
||||||
`,
|
|
||||||
Args: cobra.ExactArgs(1),
|
|
||||||
RunE: runAddCmd,
|
|
||||||
}
|
|
||||||
// cmd.Flags().StringSlice(flagMultisig, nil, "Construct and store a multisig public key (implies --pubkey)")
|
|
||||||
// cmd.Flags().Uint(flagMultiSigThreshold, 1, "K out of N required signatures. For use in conjunction with --multisig")
|
|
||||||
// cmd.Flags().Bool(flagNoSort, false, "Keys passed to --multisig are taken in the order they're supplied")
|
|
||||||
cmd.Flags().String(FlagPublicKey, "", "Parse a public key in bech32 format and save it to disk")
|
|
||||||
cmd.Flags().BoolP(flagInteractive, "i", false, "Interactively prompt user for BIP39 passphrase and mnemonic")
|
|
||||||
// cmd.Flags().Bool(flags.FlagUseLedger, false, "Store a local reference to a private key on a Ledger device")
|
|
||||||
cmd.Flags().Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating")
|
|
||||||
cmd.Flags().Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)")
|
|
||||||
// cmd.Flags().Bool(flagDryRun, false, "Perform action, but don't add key to local keystore")
|
|
||||||
cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation")
|
|
||||||
cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation")
|
|
||||||
cmd.Flags().Bool(flags.FlagIndentResponse, false, "Add indent to JSON response")
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
input
|
|
||||||
- bip39 mnemonic
|
|
||||||
- bip39 passphrase
|
|
||||||
- bip44 path
|
|
||||||
- local encryption password
|
|
||||||
output
|
|
||||||
- armor encrypted private key (saved to file)
|
|
||||||
*/
|
|
||||||
func runAddCmd(cmd *cobra.Command, args []string) error {
|
|
||||||
var kb cosmosKeys.Keybase
|
|
||||||
var err error
|
|
||||||
var encryptPassword string
|
|
||||||
|
|
||||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
|
||||||
name := args[0]
|
|
||||||
|
|
||||||
interactive := viper.GetBool(flagInteractive)
|
|
||||||
showMnemonic := !viper.GetBool(flagNoBackup)
|
|
||||||
|
|
||||||
kb, err = NewKeyBaseFromHomeFlag()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = kb.Get(name)
|
|
||||||
if err == nil {
|
|
||||||
// account exists, ask for user confirmation
|
|
||||||
response, err2 := input.GetConfirmation(fmt.Sprintf("override the existing name %s", name), inBuf)
|
|
||||||
if err2 != nil {
|
|
||||||
return err2
|
|
||||||
}
|
|
||||||
if !response {
|
|
||||||
return errors.New("aborted")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ask for a password when generating a local key
|
|
||||||
if viper.GetString(FlagPublicKey) == "" && !viper.GetBool(flags.FlagUseLedger) {
|
|
||||||
encryptPassword, err = input.GetCheckPassword(
|
|
||||||
"Enter a passphrase to encrypt your key to disk:",
|
|
||||||
"Repeat the passphrase:", inBuf)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
|
|
||||||
if viper.GetString(FlagPublicKey) != "" {
|
|
||||||
pk, err := sdk.GetAccPubKeyBech32(viper.GetString(FlagPublicKey))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = kb.CreateOffline(name, pk)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
account := uint32(viper.GetInt(flagAccount))
|
|
||||||
index := uint32(viper.GetInt(flagIndex))
|
|
||||||
|
|
||||||
// // If we're using ledger, only thing we need is the path and the bech32 prefix.
|
|
||||||
// if viper.GetBool(flags.FlagUseLedger) {
|
|
||||||
// bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix()
|
|
||||||
// info, err := kb.CreateLedger(name, keys.Secp256k1, bech32PrefixAccAddr, account, index)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return printCreate(cmd, info, false, "")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Get bip39 mnemonic
|
|
||||||
var mnemonic string
|
|
||||||
var bip39Passphrase string
|
|
||||||
|
|
||||||
if interactive || viper.GetBool(flagRecover) {
|
|
||||||
bip39Message := "Enter your bip39 mnemonic"
|
|
||||||
if !viper.GetBool(flagRecover) {
|
|
||||||
bip39Message = "Enter your bip39 mnemonic, or hit enter to generate one."
|
|
||||||
}
|
|
||||||
|
|
||||||
mnemonic, err = input.GetString(bip39Message, inBuf)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bip39.IsMnemonicValid(mnemonic) {
|
|
||||||
return errors.New("invalid mnemonic")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(mnemonic) == 0 {
|
|
||||||
// read entropy seed straight from crypto.Rand and convert to mnemonic
|
|
||||||
entropySeed, err := bip39.NewEntropy(mnemonicEntropySize)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mnemonic, err = bip39.NewMnemonic(entropySeed[:])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// override bip39 passphrase
|
|
||||||
if interactive {
|
|
||||||
bip39Passphrase, err = input.GetString(
|
|
||||||
"Enter your bip39 passphrase. This is combined with the mnemonic to derive the seed. "+
|
|
||||||
"Most users should just hit enter to use the default, \"\"", inBuf)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// if they use one, make them re-enter it
|
|
||||||
if len(bip39Passphrase) != 0 {
|
|
||||||
p2, err := input.GetString("Repeat the passphrase:", inBuf)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if bip39Passphrase != p2 {
|
|
||||||
return errors.New("passphrases don't match")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info, err := kb.CreateAccount(name, mnemonic, bip39Passphrase, encryptPassword, account, index)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recover key from seed passphrase
|
|
||||||
if viper.GetBool(flagRecover) {
|
|
||||||
// Hide mnemonic from output
|
|
||||||
showMnemonic = false
|
|
||||||
mnemonic = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return printCreate(cmd, info, showMnemonic, mnemonic)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printCreate(cmd *cobra.Command, info cosmosKeys.Info, showMnemonic bool, mnemonic string) error {
|
|
||||||
output := viper.Get(cli.OutputFlag)
|
|
||||||
|
|
||||||
switch output {
|
|
||||||
case clientkeys.OutputFormatText:
|
|
||||||
cmd.PrintErrln()
|
|
||||||
printKeyInfo(info, keys.Bech32KeyOutput)
|
|
||||||
|
|
||||||
// print mnemonic unless requested not to.
|
|
||||||
if showMnemonic {
|
|
||||||
cmd.PrintErrln("\n**Important** write this mnemonic phrase in a safe place.")
|
|
||||||
cmd.PrintErrln("It is the only way to recover your account if you ever forget your password.")
|
|
||||||
cmd.PrintErrln("")
|
|
||||||
cmd.PrintErrln(mnemonic)
|
|
||||||
}
|
|
||||||
case clientkeys.OutputFormatJSON:
|
|
||||||
out, err := keys.Bech32KeyOutput(info)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if showMnemonic {
|
|
||||||
out.Mnemonic = mnemonic
|
|
||||||
}
|
|
||||||
|
|
||||||
var jsonString []byte
|
|
||||||
if viper.GetBool(flags.FlagIndentResponse) {
|
|
||||||
jsonString, err = cdc.MarshalJSONIndent(out, "", " ")
|
|
||||||
} else {
|
|
||||||
jsonString, err = cdc.MarshalJSON(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cmd.PrintErrln(string(jsonString))
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("I can't speak: %s", output)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
||||||
"github.com/cosmos/cosmos-sdk/tests"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAddCommandBasic(t *testing.T) {
|
|
||||||
cmd := addKeyCommand()
|
|
||||||
assert.NotNil(t, cmd)
|
|
||||||
mockIn, _, _ := tests.ApplyMockIO(cmd)
|
|
||||||
|
|
||||||
kbHome, kbCleanUp := tests.NewTestCaseDir(t)
|
|
||||||
assert.NotNil(t, kbHome)
|
|
||||||
defer kbCleanUp()
|
|
||||||
viper.Set(flags.FlagHome, kbHome)
|
|
||||||
|
|
||||||
viper.Set(cli.OutputFlag, OutputFormatText)
|
|
||||||
|
|
||||||
mockIn.Reset("test1234\ntest1234\n")
|
|
||||||
err := runAddCmd(cmd, []string{"keyname1"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
viper.Set(cli.OutputFlag, OutputFormatText)
|
|
||||||
|
|
||||||
mockIn.Reset("test1234\ntest1234\n")
|
|
||||||
err = runAddCmd(cmd, []string{"keyname1"})
|
|
||||||
assert.Error(t, err)
|
|
||||||
|
|
||||||
viper.Set(cli.OutputFlag, OutputFormatText)
|
|
||||||
|
|
||||||
mockIn.Reset("y\ntest1234\ntest1234\n")
|
|
||||||
err = runAddCmd(cmd, []string{"keyname1"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
viper.Set(cli.OutputFlag, OutputFormatJSON)
|
|
||||||
|
|
||||||
mockIn.Reset("test1234\ntest1234\n")
|
|
||||||
err = runAddCmd(cmd, []string{"keyname2"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cdc *codec.Codec
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cdc = codec.New()
|
|
||||||
codec.RegisterCrypto(cdc)
|
|
||||||
cdc.Seal()
|
|
||||||
}
|
|
||||||
|
|
||||||
// marshal keys
|
|
||||||
func MarshalJSON(o interface{}) ([]byte, error) {
|
|
||||||
return cdc.MarshalJSON(o)
|
|
||||||
}
|
|
||||||
|
|
||||||
// unmarshal json
|
|
||||||
func UnmarshalJSON(bz []byte, ptr interface{}) error {
|
|
||||||
return cdc.UnmarshalJSON(bz, ptr)
|
|
||||||
}
|
|
34
keys/root.go
34
keys/root.go
@ -1,34 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Commands registers a sub-tree of commands to interact with
|
|
||||||
// local private key storage.
|
|
||||||
func Commands() *cobra.Command {
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "emintkeys",
|
|
||||||
Short: "Add or view local private keys",
|
|
||||||
Long: `Keys allows you to manage your local keystore for tendermint.
|
|
||||||
|
|
||||||
These keys may be in any format supported by go-crypto and can be
|
|
||||||
used by light-clients, full nodes, or any other application that
|
|
||||||
needs to sign with a private key.`,
|
|
||||||
}
|
|
||||||
cmd.AddCommand(
|
|
||||||
// mnemonicKeyCommand(),
|
|
||||||
addKeyCommand(),
|
|
||||||
// exportKeyCommand(),
|
|
||||||
// importKeyCommand(),
|
|
||||||
// listKeysCmd(),
|
|
||||||
showKeysCmd(),
|
|
||||||
flags.LineBreak,
|
|
||||||
// deleteKeyCommand(),
|
|
||||||
// updateKeyCommand(),
|
|
||||||
// parseKeyStringCommand(),
|
|
||||||
)
|
|
||||||
return cmd
|
|
||||||
}
|
|
132
keys/show.go
132
keys/show.go
@ -1,132 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto"
|
|
||||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/cosmos/ethermint/crypto/keys"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// FlagAddress is the flag for the user's address on the command line.
|
|
||||||
FlagAddress = "address"
|
|
||||||
// FlagAddress is the flag for the user's address on the command line.
|
|
||||||
FlagETHAddress = "ethwallet"
|
|
||||||
// FlagPublicKey represents the user's public key on the command line.
|
|
||||||
FlagPublicKey = "pubkey"
|
|
||||||
// FlagBechPrefix defines a desired Bech32 prefix encoding for a key.
|
|
||||||
FlagBechPrefix = "bech"
|
|
||||||
// FlagDevice indicates that the information should be shown in the device
|
|
||||||
FlagDevice = "device"
|
|
||||||
)
|
|
||||||
|
|
||||||
func showKeysCmd() *cobra.Command {
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "show <name>",
|
|
||||||
Short: "Show key info for the given name",
|
|
||||||
Long: `Return public details of a single local key.`,
|
|
||||||
Args: cobra.MinimumNArgs(1),
|
|
||||||
RunE: runShowCmd,
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.Flags().String(FlagBechPrefix, sdk.PrefixAccount, "The Bech32 prefix encoding for a key (acc|val|cons)")
|
|
||||||
cmd.Flags().BoolP(FlagAddress, "a", false, "Output the address only (overrides --output)")
|
|
||||||
cmd.Flags().BoolP(FlagETHAddress, "w", false, "Output the Ethereum address only (overrides --output)")
|
|
||||||
cmd.Flags().BoolP(FlagPublicKey, "p", false, "Output the public key only (overrides --output)")
|
|
||||||
cmd.Flags().BoolP(FlagDevice, "d", false, "Output the address in a ledger device")
|
|
||||||
cmd.Flags().Bool(flags.FlagIndentResponse, false, "Add indent to JSON response")
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func runShowCmd(cmd *cobra.Command, args []string) (err error) {
|
|
||||||
var info cosmosKeys.Info
|
|
||||||
|
|
||||||
if len(args) == 1 {
|
|
||||||
info, err = GetKeyInfo(args[0])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return errors.New("Must provide only one name")
|
|
||||||
}
|
|
||||||
|
|
||||||
isShowAddr := viper.GetBool(FlagAddress)
|
|
||||||
isShowEthAddr := viper.GetBool(FlagETHAddress)
|
|
||||||
isShowPubKey := viper.GetBool(FlagPublicKey)
|
|
||||||
isShowDevice := viper.GetBool(FlagDevice)
|
|
||||||
|
|
||||||
isOutputSet := false
|
|
||||||
tmp := cmd.Flag(cli.OutputFlag)
|
|
||||||
if tmp != nil {
|
|
||||||
isOutputSet = tmp.Changed
|
|
||||||
}
|
|
||||||
|
|
||||||
isShowEitherAddr := isShowAddr || isShowEthAddr
|
|
||||||
|
|
||||||
if isShowEitherAddr && isShowPubKey {
|
|
||||||
return errors.New("cannot get address, with --address or --ethwallet, and --pubkey at once")
|
|
||||||
}
|
|
||||||
|
|
||||||
if isOutputSet && (isShowEitherAddr || isShowPubKey) {
|
|
||||||
return errors.New("cannot use --output with --address or --pubkey")
|
|
||||||
}
|
|
||||||
|
|
||||||
keyOutputFunction := keys.Bech32KeyOutput
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case isShowAddr:
|
|
||||||
printKeyAddress(info, keyOutputFunction)
|
|
||||||
case isShowEthAddr:
|
|
||||||
printKeyEthAddress(info, keyOutputFunction)
|
|
||||||
case isShowPubKey:
|
|
||||||
printPubKey(info, keyOutputFunction)
|
|
||||||
default:
|
|
||||||
printKeyInfo(info, keyOutputFunction)
|
|
||||||
}
|
|
||||||
|
|
||||||
if isShowDevice {
|
|
||||||
if isShowPubKey {
|
|
||||||
return fmt.Errorf("the device flag (-d) can only be used for addresses not pubkeys")
|
|
||||||
}
|
|
||||||
if viper.GetString(FlagBechPrefix) != "acc" {
|
|
||||||
return fmt.Errorf("the device flag (-d) can only be used for accounts")
|
|
||||||
}
|
|
||||||
// Override and show in the device
|
|
||||||
if info.GetType() != cosmosKeys.TypeLedger {
|
|
||||||
return fmt.Errorf("the device flag (-d) can only be used for accounts stored in devices")
|
|
||||||
}
|
|
||||||
|
|
||||||
hdpath, err := info.GetPath()
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return crypto.LedgerShowAddress(*hdpath, info.GetPubKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Determine if the different prefixes are necessary for ethermint
|
|
||||||
// func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) {
|
|
||||||
// switch bechPrefix {
|
|
||||||
// case sdk.PrefixAccount:
|
|
||||||
// return keys.Bech32KeyOutput, nil
|
|
||||||
// case sdk.PrefixValidator:
|
|
||||||
// return keys.Bech32ValKeyOutput, nil
|
|
||||||
// case sdk.PrefixConsensus:
|
|
||||||
// return keys.Bech32ConsKeyOutput, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix)
|
|
||||||
// }
|
|
@ -1,51 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
||||||
"github.com/cosmos/cosmos-sdk/tests"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestShowKeysCmd(t *testing.T) {
|
|
||||||
cmd := showKeysCmd()
|
|
||||||
assert.NotNil(t, cmd)
|
|
||||||
assert.Equal(t, "false", cmd.Flag(FlagAddress).DefValue)
|
|
||||||
assert.Equal(t, "false", cmd.Flag(FlagPublicKey).DefValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunShowCmd(t *testing.T) {
|
|
||||||
cmd := showKeysCmd()
|
|
||||||
|
|
||||||
err := runShowCmd(cmd, []string{"invalid"})
|
|
||||||
assert.EqualError(t, err, "Key invalid not found")
|
|
||||||
|
|
||||||
// Prepare a key base
|
|
||||||
// Now add a temporary keybase
|
|
||||||
kbHome, cleanUp := tests.NewTestCaseDir(t)
|
|
||||||
defer cleanUp()
|
|
||||||
viper.Set(flags.FlagHome, kbHome)
|
|
||||||
|
|
||||||
fakeKeyName1 := "runShowCmd_Key1"
|
|
||||||
fakeKeyName2 := "runShowCmd_Key2"
|
|
||||||
kb, err := NewKeyBaseFromHomeFlag()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
_, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", 0, 0)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
_, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", 0, 1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// // Now try single key
|
|
||||||
// err = runShowCmd(cmd, []string{fakeKeyName1})
|
|
||||||
// assert.EqualError(t, err, "invalid Bech32 prefix encoding provided: ")
|
|
||||||
|
|
||||||
// // Now try single key - set bech to acc
|
|
||||||
// viper.Set(FlagBechPrefix, sdk.PrefixAccount)
|
|
||||||
err = runShowCmd(cmd, []string{fakeKeyName1})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
err = runShowCmd(cmd, []string{fakeKeyName2})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
167
keys/utils.go
167
keys/utils.go
@ -1,167 +0,0 @@
|
|||||||
package keys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
|
|
||||||
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
||||||
cosmosKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
|
||||||
emintKeys "github.com/cosmos/ethermint/crypto/keys"
|
|
||||||
)
|
|
||||||
|
|
||||||
// available output formats.
|
|
||||||
const (
|
|
||||||
OutputFormatText = "text"
|
|
||||||
OutputFormatJSON = "json"
|
|
||||||
|
|
||||||
defaultKeyDBName = "emintkeys"
|
|
||||||
)
|
|
||||||
|
|
||||||
type bechKeyOutFn func(keyInfo cosmosKeys.Info) (emintKeys.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) (cosmosKeys.Info, error) {
|
|
||||||
keybase, err := NewKeyBaseFromHomeFlag()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return keybase.Get(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewKeyBaseFromHomeFlag initializes a Keybase based on the configuration.
|
|
||||||
func NewKeyBaseFromHomeFlag() (cosmosKeys.Keybase, error) {
|
|
||||||
rootDir := viper.GetString(flags.FlagHome)
|
|
||||||
return NewKeyBaseFromDir(rootDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewKeyBaseFromDir initializes a keybase at a particular dir.
|
|
||||||
func NewKeyBaseFromDir(rootDir string) (cosmosKeys.Keybase, error) {
|
|
||||||
return getLazyKeyBaseFromDir(rootDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInMemoryKeyBase returns a storage-less keybase.
|
|
||||||
func NewInMemoryKeyBase() cosmosKeys.Keybase { return emintKeys.NewInMemory() }
|
|
||||||
|
|
||||||
func getLazyKeyBaseFromDir(rootDir string) (cosmosKeys.Keybase, error) {
|
|
||||||
return emintKeys.New(defaultKeyDBName, filepath.Join(rootDir, defaultKeyDBName)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPassphrase returns a passphrase for a given name. It will first retrieve
|
|
||||||
// the key info for that name if the type is local, it'll fetch input from
|
|
||||||
// STDIN. Otherwise, an empty passphrase is returned. An error is returned if
|
|
||||||
// the key info cannot be fetched or reading from STDIN fails.
|
|
||||||
func GetPassphrase(name string) (string, error) {
|
|
||||||
var passphrase string
|
|
||||||
|
|
||||||
keyInfo, err := GetKeyInfo(name)
|
|
||||||
if err != nil {
|
|
||||||
return passphrase, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// we only need a passphrase for locally stored keys
|
|
||||||
if keyInfo.GetType().String() == emintKeys.TypeLocal.String() {
|
|
||||||
passphrase, err = clientkeys.ReadPassphraseFromStdin(name)
|
|
||||||
if err != nil {
|
|
||||||
return passphrase, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return passphrase, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func printKeyInfo(keyInfo cosmosKeys.Info, bechKeyOut bechKeyOutFn) {
|
|
||||||
ko, err := bechKeyOut(keyInfo)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch viper.Get(cli.OutputFlag) {
|
|
||||||
case OutputFormatText:
|
|
||||||
printTextInfos([]emintKeys.KeyOutput{ko})
|
|
||||||
|
|
||||||
case OutputFormatJSON:
|
|
||||||
var out []byte
|
|
||||||
var err error
|
|
||||||
if viper.GetBool(flags.FlagIndentResponse) {
|
|
||||||
out, err = cdc.MarshalJSONIndent(ko, "", " ")
|
|
||||||
} else {
|
|
||||||
out, err = cdc.MarshalJSON(ko)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(string(out))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// func printInfos(infos []keys.Info) {
|
|
||||||
// kos, err := keys.Bech32KeysOutput(infos)
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// switch viper.Get(cli.OutputFlag) {
|
|
||||||
// case OutputFormatText:
|
|
||||||
// printTextInfos(kos)
|
|
||||||
|
|
||||||
// case OutputFormatJSON:
|
|
||||||
// var out []byte
|
|
||||||
// var err error
|
|
||||||
|
|
||||||
// if viper.GetBool(flags.FlagIndentResponse) {
|
|
||||||
// out, err = cdc.MarshalJSONIndent(kos, "", " ")
|
|
||||||
// } else {
|
|
||||||
// out, err = cdc.MarshalJSON(kos)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
// fmt.Printf("%s", out)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
func printTextInfos(kos []emintKeys.KeyOutput) {
|
|
||||||
out, err := yaml.Marshal(&kos)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(string(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
func printKeyAddress(info cosmosKeys.Info, bechKeyOut bechKeyOutFn) {
|
|
||||||
ko, err := bechKeyOut(info)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(ko.Address)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printKeyEthAddress(info cosmosKeys.Info, bechKeyOut bechKeyOutFn) {
|
|
||||||
ko, err := bechKeyOut(info)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(ko.ETHAddress)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printPubKey(info cosmosKeys.Info, bechKeyOut bechKeyOutFn) {
|
|
||||||
ko, err := bechKeyOut(info)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(ko.PubKey)
|
|
||||||
}
|
|
@ -4,10 +4,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
|
emintkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/client/lcd"
|
"github.com/cosmos/cosmos-sdk/client/lcd"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||||
emintkeys "github.com/cosmos/ethermint/keys"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||||
emintkeys "github.com/cosmos/ethermint/keys"
|
|
||||||
params "github.com/cosmos/ethermint/rpc/args"
|
params "github.com/cosmos/ethermint/rpc/args"
|
||||||
emint "github.com/cosmos/ethermint/types"
|
emint "github.com/cosmos/ethermint/types"
|
||||||
etypes "github.com/cosmos/ethermint/types"
|
etypes "github.com/cosmos/ethermint/types"
|
||||||
@ -108,7 +108,7 @@ func (e *PublicEthAPI) Accounts() ([]common.Address, error) {
|
|||||||
e.keybaseLock.Lock()
|
e.keybaseLock.Lock()
|
||||||
|
|
||||||
addresses := make([]common.Address, 0) // return [] instead of nil if empty
|
addresses := make([]common.Address, 0) // return [] instead of nil if empty
|
||||||
keybase, err := emintkeys.NewKeyBaseFromHomeFlag()
|
keybase, err := keys.NewKeyBaseFromHomeFlag()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return addresses, err
|
return addresses, err
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||||
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
|
|
||||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
@ -23,6 +24,10 @@ const (
|
|||||||
// Main Ethermint account
|
// Main Ethermint account
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
authtypes.RegisterAccountTypeCodec(Account{}, EthermintAccountName)
|
||||||
|
}
|
||||||
|
|
||||||
// Account implements the auth.Account interface and embeds an
|
// Account implements the auth.Account interface and embeds an
|
||||||
// auth.BaseAccount type. It is compatible with the auth.AccountMapper.
|
// auth.BaseAccount type. It is compatible with the auth.AccountMapper.
|
||||||
type Account struct {
|
type Account struct {
|
||||||
|
@ -10,8 +10,13 @@ func init() {
|
|||||||
RegisterCodec(typesCodec)
|
RegisterCodec(typesCodec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Amino encoding name
|
||||||
|
EthermintAccountName = "emint/Account"
|
||||||
|
)
|
||||||
|
|
||||||
// RegisterCodec registers all the necessary types with amino for the given
|
// RegisterCodec registers all the necessary types with amino for the given
|
||||||
// codec.
|
// codec.
|
||||||
func RegisterCodec(cdc *codec.Codec) {
|
func RegisterCodec(cdc *codec.Codec) {
|
||||||
cdc.RegisterConcrete(&Account{}, "types/Account", nil)
|
cdc.RegisterConcrete(&Account{}, EthermintAccountName, nil)
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,13 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"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"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
||||||
emintkeys "github.com/cosmos/ethermint/keys"
|
|
||||||
emintTypes "github.com/cosmos/ethermint/types"
|
emintTypes "github.com/cosmos/ethermint/types"
|
||||||
emintUtils "github.com/cosmos/ethermint/x/evm/client/utils"
|
|
||||||
"github.com/cosmos/ethermint/x/evm/types"
|
"github.com/cosmos/ethermint/x/evm/types"
|
||||||
|
|
||||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||||
@ -32,7 +32,6 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
|
|||||||
evmTxCmd.AddCommand(client.PostCommands(
|
evmTxCmd.AddCommand(client.PostCommands(
|
||||||
// TODO: Add back generating cosmos tx for Ethereum tx message
|
// TODO: Add back generating cosmos tx for Ethereum tx message
|
||||||
// GetCmdGenTx(cdc),
|
// GetCmdGenTx(cdc),
|
||||||
GetCmdGenETHTx(cdc),
|
|
||||||
)...)
|
)...)
|
||||||
|
|
||||||
return evmTxCmd
|
return evmTxCmd
|
||||||
@ -46,11 +45,11 @@ func GetCmdGenTx(cdc *codec.Codec) *cobra.Command {
|
|||||||
Args: cobra.ExactArgs(5),
|
Args: cobra.ExactArgs(5),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
// TODO: remove inputs and infer based on StdTx
|
// TODO: remove inputs and infer based on StdTx
|
||||||
cliCtx := emintUtils.NewETHCLIContext().WithCodec(cdc)
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
|
|
||||||
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
|
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
|
||||||
|
|
||||||
kb, err := emintkeys.NewKeyBaseFromHomeFlag()
|
kb, err := keys.NewKeyBaseFromHomeFlag()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -80,63 +79,7 @@ func GetCmdGenTx(cdc *codec.Codec) *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: possibly overwrite gas values in txBldr
|
// TODO: possibly overwrite gas values in txBldr
|
||||||
return emintUtils.GenerateOrBroadcastETHMsgs(cliCtx, txBldr.WithKeybase(kb), []sdk.Msg{msg})
|
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr.WithKeybase(kb), []sdk.Msg{msg})
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCmdGenTx generates an ethereum transaction
|
|
||||||
func GetCmdGenETHTx(cdc *codec.Codec) *cobra.Command {
|
|
||||||
return &cobra.Command{
|
|
||||||
Use: "generate-eth-tx [amount] [gaslimit] [gasprice] [payload] [<ethereum-address>]",
|
|
||||||
Short: "generate and broadcast an Ethereum tx. If address is not specified, contract will be created",
|
|
||||||
Args: cobra.RangeArgs(4, 5),
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
cliCtx := emintUtils.NewETHCLIContext().WithCodec(cdc)
|
|
||||||
|
|
||||||
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
|
|
||||||
|
|
||||||
kb, err := emintkeys.NewKeyBaseFromHomeFlag()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
coins, err := sdk.ParseCoins(args[0])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
gasLimit, err := strconv.ParseUint(args[1], 0, 64)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
gasPrice, err := strconv.ParseUint(args[2], 0, 64)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
payload := args[3]
|
|
||||||
|
|
||||||
txBldr, err = utils.PrepareTxBuilder(txBldr, cliCtx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var tx *types.EthereumTxMsg
|
|
||||||
if len(args) == 5 {
|
|
||||||
addr := ethcmn.HexToAddress(args[4])
|
|
||||||
tx = types.NewEthereumTxMsg(txBldr.Sequence(), &addr, big.NewInt(coins.AmountOf(emintTypes.DenomDefault).Int64()), gasLimit, new(big.Int).SetUint64(gasPrice), []byte(payload))
|
|
||||||
} else {
|
|
||||||
tx = types.NewEthereumTxMsgContract(txBldr.Sequence(), big.NewInt(coins.AmountOf(emintTypes.DenomDefault).Int64()), gasLimit, new(big.Int).SetUint64(gasPrice), []byte(payload))
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tx.ValidateBasic()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return emintUtils.BroadcastETHTx(cliCtx, txBldr.WithKeybase(kb), tx)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,344 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/input"
|
|
||||||
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
||||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
|
||||||
emintkeys "github.com/cosmos/ethermint/keys"
|
|
||||||
emint "github.com/cosmos/ethermint/types"
|
|
||||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
|
||||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
|
||||||
)
|
|
||||||
|
|
||||||
// * Code from this file is a modified version of cosmos-sdk/auth/client/utils/tx.go
|
|
||||||
// * to allow for using the Ethermint keybase for signing the transaction
|
|
||||||
|
|
||||||
// GenerateOrBroadcastMsgs creates a StdTx given a series of messages. If
|
|
||||||
// the provided context has generate-only enabled, the tx will only be printed
|
|
||||||
// to STDOUT in a fully offline manner. Otherwise, the tx will be signed and
|
|
||||||
// broadcasted.
|
|
||||||
func GenerateOrBroadcastETHMsgs(cliCtx context.CLIContext, txBldr authtypes.TxBuilder, msgs []sdk.Msg) error {
|
|
||||||
if cliCtx.GenerateOnly {
|
|
||||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, msgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return completeAndBroadcastETHTxCLI(txBldr, cliCtx, msgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BroadcastETHTx Broadcasts an Ethereum Tx not wrapped in a Std Tx
|
|
||||||
func BroadcastETHTx(cliCtx context.CLIContext, txBldr authtypes.TxBuilder, tx *evmtypes.EthereumTxMsg) error {
|
|
||||||
|
|
||||||
fromName := cliCtx.GetFromName()
|
|
||||||
|
|
||||||
passphrase, err := emintkeys.GetPassphrase(fromName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign V, R, S fields for tx
|
|
||||||
ethTx, err := signEthTx(txBldr.Keybase(), fromName, passphrase, tx, txBldr.ChainID())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use default Tx Encoder since it will just be broadcasted to TM node at this point
|
|
||||||
txEncoder := txBldr.TxEncoder()
|
|
||||||
|
|
||||||
txBytes, err := txEncoder(ethTx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// broadcast to a Tendermint node
|
|
||||||
res, err := cliCtx.BroadcastTx(txBytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return cliCtx.PrintOutput(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
// completeAndBroadcastETHTxCLI implements a utility function that facilitates
|
|
||||||
// sending a series of messages in a signed transaction given a TxBuilder and a
|
|
||||||
// QueryContext. It ensures that the account exists, has a proper number and
|
|
||||||
// sequence set. In addition, it builds and signs a transaction with the
|
|
||||||
// supplied messages. Finally, it broadcasts the signed transaction to a node.
|
|
||||||
// * Modified version from github.com/cosmos/cosmos-sdk/x/auth/client/utils/tx.go
|
|
||||||
func completeAndBroadcastETHTxCLI(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) error {
|
|
||||||
txBldr, err := utils.PrepareTxBuilder(txBldr, cliCtx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fromName := cliCtx.GetFromName()
|
|
||||||
|
|
||||||
if txBldr.SimulateAndExecute() || cliCtx.Simulate {
|
|
||||||
txBldr, err = utils.EnrichWithGas(txBldr, cliCtx, msgs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
gasEst := utils.GasEstimateResponse{GasEstimate: txBldr.Gas()}
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "%s\n", gasEst.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliCtx.Simulate {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !cliCtx.SkipConfirm {
|
|
||||||
stdSignMsg, err := txBldr.BuildSignMsg(msgs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var json []byte
|
|
||||||
if viper.GetBool(flags.FlagIndentResponse) {
|
|
||||||
json, err = cliCtx.Codec.MarshalJSONIndent(stdSignMsg, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
json = cliCtx.Codec.MustMarshalJSON(stdSignMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "%s\n\n", json)
|
|
||||||
|
|
||||||
buf := bufio.NewReader(os.Stdin)
|
|
||||||
ok, err := input.GetConfirmation("confirm transaction before signing and broadcasting", buf)
|
|
||||||
if err != nil || !ok {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "%s\n", "cancelled transaction")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// * This function is overridden to change the keybase reference here
|
|
||||||
passphrase, err := emintkeys.GetPassphrase(fromName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// build and sign the transaction
|
|
||||||
// * needed to be modified also to change how the data is signed
|
|
||||||
txBytes, err := buildAndSign(txBldr, fromName, passphrase, msgs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// broadcast to a Tendermint node
|
|
||||||
res, err := cliCtx.BroadcastTx(txBytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return cliCtx.PrintOutput(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BuildAndSign builds a single message to be signed, and signs a transaction
|
|
||||||
// with the built message given a name, passphrase, and a set of messages.
|
|
||||||
// * overridden from github.com/cosmos/cosmos-sdk/x/auth/types/txbuilder.go
|
|
||||||
// * This is just modified to change the functionality in makeSignature, through sign
|
|
||||||
func buildAndSign(bldr authtypes.TxBuilder, name, passphrase string, msgs []sdk.Msg) ([]byte, error) {
|
|
||||||
msg, err := bldr.BuildSignMsg(msgs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sign(bldr, name, passphrase, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign signs a transaction given a name, passphrase, and a single message to
|
|
||||||
// signed. An error is returned if signing fails.
|
|
||||||
func sign(bldr authtypes.TxBuilder, name, passphrase string, msg authtypes.StdSignMsg) ([]byte, error) {
|
|
||||||
sig, err := makeSignature(bldr.Keybase(), name, passphrase, msg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
txEncoder := bldr.TxEncoder()
|
|
||||||
|
|
||||||
return txEncoder(authtypes.NewStdTx(msg.Msgs, msg.Fee, []authtypes.StdSignature{sig}, msg.Memo))
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeSignature builds a StdSignature given keybase, key name, passphrase, and a StdSignMsg.
|
|
||||||
func makeSignature(keybase crkeys.Keybase, name, passphrase string,
|
|
||||||
msg authtypes.StdSignMsg) (sig authtypes.StdSignature, err error) {
|
|
||||||
if keybase == nil {
|
|
||||||
// * This is overridden to allow ethermint keys, but not used because keybase is set
|
|
||||||
keybase, err = emintkeys.NewKeyBaseFromHomeFlag()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EthereumTxMsg always returns the data in the 0th index so it is safe to do this
|
|
||||||
var ethTx *evmtypes.EthereumTxMsg
|
|
||||||
ethTx, ok := msg.Msgs[0].(*evmtypes.EthereumTxMsg)
|
|
||||||
if !ok {
|
|
||||||
return sig, fmt.Errorf("Transaction message not an Ethereum Tx")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Move this logic to after tx is rlp decoded in keybase Sign function
|
|
||||||
// parse the chainID from a string to a base-10 integer
|
|
||||||
chainID, ok := new(big.Int).SetString(msg.ChainID, 10)
|
|
||||||
if !ok {
|
|
||||||
return sig, emint.ErrInvalidChainID(fmt.Sprintf("invalid chainID: %s", msg.ChainID))
|
|
||||||
}
|
|
||||||
|
|
||||||
privKey, err := keybase.ExportPrivateKeyObject(name, passphrase)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
emintKey, ok := privKey.(emintcrypto.PrivKeySecp256k1)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("invalid private key type: %T", privKey))
|
|
||||||
}
|
|
||||||
|
|
||||||
ethTx.Sign(chainID, emintKey.ToECDSA())
|
|
||||||
|
|
||||||
// * This is needed to be overridden to get bytes to sign (RLPSignBytes) with the chainID
|
|
||||||
sigBytes, pubkey, err := keybase.Sign(name, passphrase, ethTx.RLPSignBytes(chainID).Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return authtypes.StdSignature{
|
|
||||||
PubKey: pubkey,
|
|
||||||
Signature: sigBytes,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// signEthTx populates the V, R, and S fields of an EthereumTxMsg using an ethermint key
|
|
||||||
func signEthTx(keybase crkeys.Keybase, name, passphrase string,
|
|
||||||
ethTx *evmtypes.EthereumTxMsg, chainID string) (_ *evmtypes.EthereumTxMsg, err error) {
|
|
||||||
if keybase == nil {
|
|
||||||
keybase, err = emintkeys.NewKeyBaseFromHomeFlag()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the chainID from a string to a base-10 integer
|
|
||||||
intChainID, ok := new(big.Int).SetString(chainID, 10)
|
|
||||||
if !ok {
|
|
||||||
return ethTx, emint.ErrInvalidChainID(fmt.Sprintf("invalid chainID: %s", chainID))
|
|
||||||
}
|
|
||||||
|
|
||||||
privKey, err := keybase.ExportPrivateKeyObject(name, passphrase)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key must be a ethermint key to be able to be converted into an ECDSA private key to sign
|
|
||||||
emintKey, ok := privKey.(emintcrypto.PrivKeySecp256k1)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("invalid private key type: %T", privKey))
|
|
||||||
}
|
|
||||||
|
|
||||||
ethTx.Sign(intChainID, emintKey.ToECDSA())
|
|
||||||
|
|
||||||
return ethTx, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// * This context is needed because the previous GetFromFields function would initialize a
|
|
||||||
// * default keybase to lookup the address or name. The new one overrides the keybase with the
|
|
||||||
// * ethereum compatible one
|
|
||||||
|
|
||||||
// NewCLIContextWithFrom returns a new initialized CLIContext with parameters from the
|
|
||||||
// command line using Viper. It takes a key name or address and populates the FromName and
|
|
||||||
// FromAddress field accordingly.
|
|
||||||
func NewETHCLIContext() context.CLIContext {
|
|
||||||
var nodeURI string
|
|
||||||
var rpc rpcclient.Client
|
|
||||||
|
|
||||||
from := viper.GetString(flags.FlagFrom)
|
|
||||||
|
|
||||||
genOnly := viper.GetBool(flags.FlagGenerateOnly)
|
|
||||||
|
|
||||||
// * This function is needed only to override this call to access correct keybase
|
|
||||||
fromAddress, fromName, err := getFromFields(from, genOnly)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("failed to get from fields: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !genOnly {
|
|
||||||
nodeURI = viper.GetString(flags.FlagNode)
|
|
||||||
if nodeURI != "" {
|
|
||||||
rpc = rpcclient.NewHTTP(nodeURI, "/websocket")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.CLIContext{
|
|
||||||
Client: rpc,
|
|
||||||
Output: os.Stdout,
|
|
||||||
NodeURI: nodeURI,
|
|
||||||
From: viper.GetString(flags.FlagFrom),
|
|
||||||
OutputFormat: viper.GetString(cli.OutputFlag),
|
|
||||||
Height: viper.GetInt64(flags.FlagHeight),
|
|
||||||
TrustNode: viper.GetBool(flags.FlagTrustNode),
|
|
||||||
UseLedger: viper.GetBool(flags.FlagUseLedger),
|
|
||||||
BroadcastMode: viper.GetString(flags.FlagBroadcastMode),
|
|
||||||
// Verifier: verifier,
|
|
||||||
Simulate: viper.GetBool(flags.FlagDryRun),
|
|
||||||
GenerateOnly: genOnly,
|
|
||||||
FromAddress: fromAddress,
|
|
||||||
FromName: fromName,
|
|
||||||
Indent: viper.GetBool(flags.FlagIndentResponse),
|
|
||||||
SkipConfirm: viper.GetBool(flags.FlagSkipConfirmation),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFromFields returns a from account address and Keybase name given either
|
|
||||||
// an address or key name. If genOnly is true, only a valid Bech32 cosmos
|
|
||||||
// address is returned.
|
|
||||||
func getFromFields(from string, genOnly bool) (sdk.AccAddress, string, error) {
|
|
||||||
if from == "" {
|
|
||||||
return nil, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if genOnly {
|
|
||||||
addr, err := sdk.AccAddressFromBech32(from)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", errors.Wrap(err, "must provide a valid Bech32 address for generate-only")
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// * This is the line that needed to be overridden, change could be to pass in optional keybase?
|
|
||||||
keybase, err := emintkeys.NewKeyBaseFromHomeFlag()
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var info crkeys.Info
|
|
||||||
if addr, err := sdk.AccAddressFromBech32(from); err == nil {
|
|
||||||
info, err = keybase.GetByAddress(addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
info, err = keybase.Get(from)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return info.GetAddress(), info.GetName(), nil
|
|
||||||
}
|
|
@ -2,7 +2,6 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/ethermint/crypto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ModuleCdc defines the codec to be used by evm module
|
// ModuleCdc defines the codec to be used by evm module
|
||||||
@ -21,5 +20,4 @@ func init() {
|
|||||||
func RegisterCodec(cdc *codec.Codec) {
|
func RegisterCodec(cdc *codec.Codec) {
|
||||||
cdc.RegisterConcrete(&EthereumTxMsg{}, "ethermint/MsgEthereumTx", nil)
|
cdc.RegisterConcrete(&EthereumTxMsg{}, "ethermint/MsgEthereumTx", nil)
|
||||||
cdc.RegisterConcrete(&EmintMsg{}, "ethermint/MsgEmint", nil)
|
cdc.RegisterConcrete(&EmintMsg{}, "ethermint/MsgEmint", nil)
|
||||||
crypto.RegisterCodec(cdc)
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user