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"
|
||||
"os"
|
||||
|
||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||
"github.com/cosmos/ethermint/x/evm"
|
||||
|
||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
cryptokeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
@ -76,8 +78,10 @@ func MakeCodec() *codec.Codec {
|
||||
var cdc = codec.New()
|
||||
|
||||
ModuleBasics.RegisterCodec(cdc)
|
||||
cryptokeys.RegisterCodec(cdc) // temporary
|
||||
sdk.RegisterCodec(cdc)
|
||||
codec.RegisterCrypto(cdc)
|
||||
emintcrypto.RegisterCodec(cdc)
|
||||
eminttypes.RegisterCodec(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"
|
||||
"path"
|
||||
|
||||
emintapp "github.com/cosmos/ethermint/app"
|
||||
"github.com/cosmos/ethermint/rpc"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
sdkrpc "github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
cryptokeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
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"
|
||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||
|
||||
emintapp "github.com/cosmos/ethermint/app"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
@ -27,7 +28,8 @@ func main() {
|
||||
|
||||
cdc := emintapp.MakeCodec()
|
||||
|
||||
authtypes.ModuleCdc = cdc
|
||||
cryptokeys.CryptoCdc = cdc
|
||||
clientkeys.KeysCdc = cdc
|
||||
|
||||
// Read in the configuration file for the sdk
|
||||
config := sdk.GetConfig()
|
||||
@ -56,7 +58,7 @@ func main() {
|
||||
// TODO: Set up rest routes (if included, different from web3 api)
|
||||
rpc.Web3RpcCmd(cdc),
|
||||
client.LineBreak,
|
||||
emintkeys.Commands(),
|
||||
keyCommands(),
|
||||
client.LineBreak,
|
||||
)
|
||||
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -16,7 +17,6 @@ import (
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
"github.com/cosmos/ethermint/keys"
|
||||
|
||||
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/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/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
genutil "github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
|
||||
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
@ -36,9 +37,10 @@ func main() {
|
||||
|
||||
cdc := emintapp.MakeCodec()
|
||||
|
||||
cryptokeys.CryptoCdc = cdc
|
||||
genutil.ModuleCdc = cdc
|
||||
genutiltypes.ModuleCdc = cdc
|
||||
authtypes.ModuleCdc = cdc
|
||||
clientkeys.KeysCdc = cdc
|
||||
|
||||
config := sdk.GetConfig()
|
||||
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
|
||||
@ -57,7 +59,7 @@ func main() {
|
||||
rootCmd.AddCommand(
|
||||
withChainIDValidation(genutilcli.InitCmd(ctx, cdc, emintapp.ModuleBasics, 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,
|
||||
),
|
||||
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"
|
||||
ethsecp256k1 "github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
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
|
||||
|
||||
|
13
go.mod
13
go.mod
@ -8,7 +8,7 @@ require (
|
||||
github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8 // indirect
|
||||
github.com/cespare/cp v1.1.1 // indirect
|
||||
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/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 // indirect
|
||||
github.com/elastic/gosigar v0.10.3 // indirect
|
||||
@ -35,8 +35,7 @@ require (
|
||||
github.com/rjeczalik/notify v0.9.2 // indirect
|
||||
github.com/spf13/afero v1.2.2 // indirect
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.4.0
|
||||
github.com/spf13/viper v1.5.0
|
||||
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/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect
|
||||
@ -54,8 +53,10 @@ require (
|
||||
google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // 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/yaml.v2 v2.2.4
|
||||
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
|
||||
)
|
||||
|
||||
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/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||
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/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
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-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/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/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
|
||||
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.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
||||
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/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
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.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.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/spf13/viper v1.5.0 h1:GpsTwfsQ27oS/Aha/6d1oD7tpKIqWnOA6tgOX9HHkt4=
|
||||
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/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
||||
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/stumble/gorocksdb v0.0.3 h1:9UU+QA1pqFYJuf9+5p7z1IqdE5k0mma4UAeu2wmX8kA=
|
||||
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/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
||||
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/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.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/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw=
|
||||
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/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/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/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
|
||||
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-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-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/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.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw=
|
||||
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.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
|
||||
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/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
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/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/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.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
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"
|
||||
|
||||
"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/codec"
|
||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||
emintkeys "github.com/cosmos/ethermint/keys"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -8,8 +8,8 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||
emintkeys "github.com/cosmos/ethermint/keys"
|
||||
params "github.com/cosmos/ethermint/rpc/args"
|
||||
emint "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()
|
||||
|
||||
addresses := make([]common.Address, 0) // return [] instead of nil if empty
|
||||
keybase, err := emintkeys.NewKeyBaseFromHomeFlag()
|
||||
keybase, err := keys.NewKeyBaseFromHomeFlag()
|
||||
if err != nil {
|
||||
return addresses, err
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
@ -23,6 +24,10 @@ const (
|
||||
// Main Ethermint account
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
func init() {
|
||||
authtypes.RegisterAccountTypeCodec(Account{}, EthermintAccountName)
|
||||
}
|
||||
|
||||
// Account implements the auth.Account interface and embeds an
|
||||
// auth.BaseAccount type. It is compatible with the auth.AccountMapper.
|
||||
type Account struct {
|
||||
|
@ -10,8 +10,13 @@ func init() {
|
||||
RegisterCodec(typesCodec)
|
||||
}
|
||||
|
||||
const (
|
||||
// Amino encoding name
|
||||
EthermintAccountName = "emint/Account"
|
||||
)
|
||||
|
||||
// RegisterCodec registers all the necessary types with amino for the given
|
||||
// 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/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
||||
emintkeys "github.com/cosmos/ethermint/keys"
|
||||
emintTypes "github.com/cosmos/ethermint/types"
|
||||
emintUtils "github.com/cosmos/ethermint/x/evm/client/utils"
|
||||
"github.com/cosmos/ethermint/x/evm/types"
|
||||
|
||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||
@ -30,9 +30,8 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
|
||||
}
|
||||
|
||||
evmTxCmd.AddCommand(client.PostCommands(
|
||||
// TODO: Add back generating cosmos tx for Ethereum tx message
|
||||
// GetCmdGenTx(cdc),
|
||||
GetCmdGenETHTx(cdc),
|
||||
// TODO: Add back generating cosmos tx for Ethereum tx message
|
||||
// GetCmdGenTx(cdc),
|
||||
)...)
|
||||
|
||||
return evmTxCmd
|
||||
@ -46,11 +45,11 @@ func GetCmdGenTx(cdc *codec.Codec) *cobra.Command {
|
||||
Args: cobra.ExactArgs(5),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// 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))
|
||||
|
||||
kb, err := emintkeys.NewKeyBaseFromHomeFlag()
|
||||
kb, err := keys.NewKeyBaseFromHomeFlag()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -80,63 +79,7 @@ func GetCmdGenTx(cdc *codec.Codec) *cobra.Command {
|
||||
}
|
||||
|
||||
// TODO: possibly overwrite gas values in txBldr
|
||||
return emintUtils.GenerateOrBroadcastETHMsgs(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)
|
||||
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr.WithKeybase(kb), []sdk.Msg{msg})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -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 (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/ethermint/crypto"
|
||||
)
|
||||
|
||||
// ModuleCdc defines the codec to be used by evm module
|
||||
@ -21,5 +20,4 @@ func init() {
|
||||
func RegisterCodec(cdc *codec.Codec) {
|
||||
cdc.RegisterConcrete(&EthereumTxMsg{}, "ethermint/MsgEthereumTx", nil)
|
||||
cdc.RegisterConcrete(&EmintMsg{}, "ethermint/MsgEmint", nil)
|
||||
crypto.RegisterCodec(cdc)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user