refactor!: Keyring migration (#9695)
<!-- The default pull request template is for types feat, fix, or refactor. For other templates, add one of the following parameters to the url: - template=docs.md - template=other.md --> ## Description The draft PR #9222 Closes: #7108 <!-- Add a description of the changes that this PR introduces and the files that are the most critical to review. --> - implement proto definition for `Record` - rename `Info.go` to `legacyInfo.go` within `keyring` package - implement CLI `migrate` command that migrates all keys from legacyInfo to proto according to @robert-zaremba migration [algorithm](https://github.com/cosmos/cosmos-sdk/pull/9222/#discussion_r624683839) - remove legacy keybase entirely. - add `Migrate` and `MigrateAll` functions in `keyring.go` for single key and all keys migration - add tests - fix tests --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [x] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [x] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable)
This commit is contained in:
parent
a0ecfe54ea
commit
6cbbd6da75
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -48,6 +48,23 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||
|
||||
### API Breaking Changes
|
||||
|
||||
* [\#9695](https://github.com/cosmos/cosmos-sdk/pull/9695) Migrate keys from `Info` -> `Record`
|
||||
* Add new `codec.Codec` argument in:
|
||||
* `keyring.NewInMemory`
|
||||
* `keyring.New`
|
||||
* Rename:
|
||||
* `SavePubKey` to `SaveOfflineKey`.
|
||||
* `NewMultiInfo`, `NewLedgerInfo` to `NewLegacyMultiInfo`, `newLegacyLedgerInfo` respectively. Move them into `legacy_info.go`.
|
||||
* `NewOfflineInfo` to `newLegacyOfflineInfo` and move it to `migration_test.go`.
|
||||
* Return:
|
||||
*`keyring.Record, error` in `SaveOfflineKey`, `SaveLedgerKey`, `SaveMultiSig`, `Key` and `KeyByAddress`.
|
||||
*`keyring.Record` instead of `Info` in `NewMnemonic` and `List`.
|
||||
* Remove `algo` argument from :
|
||||
* `SaveOfflineKey`
|
||||
* Take `keyring.Record` instead of `Info` as first argument in:
|
||||
* `MkConsKeyOutput`
|
||||
* `MkValKeyOutput`
|
||||
* `MkAccKeyOutput`
|
||||
* [\#10077](https://github.com/cosmos/cosmos-sdk/pull/10077) Remove telemetry on `GasKV` and `CacheKV` store Get/Set operations, significantly improving their performance.
|
||||
* [\#10022](https://github.com/cosmos/cosmos-sdk/pull/10022) `AuthKeeper` interface in `x/auth` now includes a function `HasAccount`.
|
||||
* [\#9759](https://github.com/cosmos/cosmos-sdk/pull/9759) `NewAccountKeeeper` in `x/auth` now takes an additional `bech32Prefix` argument that represents `sdk.Bech32MainPrefix`.
|
||||
|
@ -83,6 +100,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||
|
||||
### CLI Breaking Changes
|
||||
|
||||
* [\#9695](https://github.com/cosmos/cosmos-sdk/pull/9695) `<app> keys migrate` CLI command now takes no arguments
|
||||
* [\#9246](https://github.com/cosmos/cosmos-sdk/pull/9246) Removed the CLI flag `--setup-config-only` from the `testnet` command and added the subcommand `init-files`.
|
||||
|
||||
### Improvements
|
||||
|
|
|
@ -323,27 +323,32 @@ func GetFromFields(kr keyring.Keyring, from string, genOnly bool) (sdk.AccAddres
|
|||
return nil, "", 0, nil
|
||||
}
|
||||
|
||||
var info keyring.Info
|
||||
var k *keyring.Record
|
||||
if addr, err := sdk.AccAddressFromBech32(from); err == nil {
|
||||
info, err = kr.KeyByAddress(addr)
|
||||
k, err = kr.KeyByAddress(addr)
|
||||
if err != nil {
|
||||
return nil, "", 0, err
|
||||
}
|
||||
} else {
|
||||
info, err = kr.Key(from)
|
||||
k, err = kr.Key(from)
|
||||
if err != nil {
|
||||
return nil, "", 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return info.GetAddress(), info.GetName(), info.GetType(), nil
|
||||
addr, err := k.GetAddress()
|
||||
if err != nil {
|
||||
return nil, "", 0, err
|
||||
}
|
||||
|
||||
return addr, k.Name, k.GetType(), nil
|
||||
}
|
||||
|
||||
// NewKeyringFromBackend gets a Keyring object from a backend
|
||||
func NewKeyringFromBackend(ctx Context, backend string) (keyring.Keyring, error) {
|
||||
if ctx.GenerateOnly || ctx.Simulate {
|
||||
return keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, ctx.KeyringDir, ctx.Input, ctx.KeyringOptions...)
|
||||
backend = keyring.BackendMemory
|
||||
}
|
||||
|
||||
return keyring.New(sdk.KeyringServiceName(), backend, ctx.KeyringDir, ctx.Input, ctx.KeyringOptions...)
|
||||
return keyring.New(sdk.KeyringServiceName(), backend, ctx.KeyringDir, ctx.Input, ctx.Codec, ctx.KeyringOptions...)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"fmt"
|
||||
"sort"
|
||||
|
||||
bip39 "github.com/cosmos/go-bip39"
|
||||
"github.com/cosmos/go-bip39"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
|
@ -119,7 +119,7 @@ func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
|||
|
||||
if dryRun, _ := cmd.Flags().GetBool(flags.FlagDryRun); dryRun {
|
||||
// use in memory keybase
|
||||
kb = keyring.NewInMemory()
|
||||
kb = keyring.NewInMemory(ctx.Codec)
|
||||
} else {
|
||||
_, err = kb.Key(name)
|
||||
if err == nil {
|
||||
|
@ -153,7 +153,11 @@ func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
|||
return err
|
||||
}
|
||||
|
||||
pks[i] = k.GetPubKey()
|
||||
key, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pks[i] = key
|
||||
}
|
||||
|
||||
if noSort, _ := cmd.Flags().GetBool(flagNoSort); !noSort {
|
||||
|
@ -163,29 +167,28 @@ func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
|||
}
|
||||
|
||||
pk := multisig.NewLegacyAminoPubKey(multisigThreshold, pks)
|
||||
info, err := kb.SaveMultisig(name, pk)
|
||||
k, err := kb.SaveMultisig(name, pk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return printCreate(cmd, info, false, "", outputFormat)
|
||||
return printCreate(cmd, k, false, "", outputFormat)
|
||||
}
|
||||
}
|
||||
|
||||
pubKey, _ := cmd.Flags().GetString(FlagPublicKey)
|
||||
if pubKey != "" {
|
||||
var pk cryptotypes.PubKey
|
||||
err = ctx.Codec.UnmarshalInterfaceJSON([]byte(pubKey), &pk)
|
||||
if err = ctx.Codec.UnmarshalInterfaceJSON([]byte(pubKey), &pk); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k, err := kb.SaveOfflineKey(name, pk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := kb.SavePubKey(name, pk, algo.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return printCreate(cmd, info, false, "", outputFormat)
|
||||
return printCreate(cmd, k, false, "", outputFormat)
|
||||
}
|
||||
|
||||
coinType, _ := cmd.Flags().GetUint32(flagCoinType)
|
||||
|
@ -203,13 +206,12 @@ func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
|||
// If we're using ledger, only thing we need is the path and the bech32 prefix.
|
||||
if useLedger {
|
||||
bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix()
|
||||
|
||||
info, err := kb.SaveLedgerKey(name, algo, bech32PrefixAccAddr, coinType, account, index)
|
||||
k, err := kb.SaveLedgerKey(name, hd.Secp256k1, bech32PrefixAccAddr, coinType, account, index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return printCreate(cmd, info, false, "", outputFormat)
|
||||
return printCreate(cmd, k, false, "", outputFormat)
|
||||
}
|
||||
|
||||
// Get bip39 mnemonic
|
||||
|
@ -271,7 +273,7 @@ func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
|||
}
|
||||
}
|
||||
|
||||
info, err := kb.NewAccount(name, mnemonic, bip39Passphrase, hdPath, algo)
|
||||
k, err := kb.NewAccount(name, mnemonic, bip39Passphrase, hdPath, algo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -283,14 +285,14 @@ func runAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
|||
mnemonic = ""
|
||||
}
|
||||
|
||||
return printCreate(cmd, info, showMnemonic, mnemonic, outputFormat)
|
||||
return printCreate(cmd, k, showMnemonic, mnemonic, outputFormat)
|
||||
}
|
||||
|
||||
func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemonic string, outputFormat string) error {
|
||||
func printCreate(cmd *cobra.Command, k *keyring.Record, showMnemonic bool, mnemonic, outputFormat string) error {
|
||||
switch outputFormat {
|
||||
case OutputFormatText:
|
||||
cmd.PrintErrln()
|
||||
printKeyInfo(cmd.OutOrStdout(), info, keyring.MkAccKeyOutput, outputFormat)
|
||||
printKeyringRecord(cmd.OutOrStdout(), k, keyring.MkAccKeyOutput, outputFormat)
|
||||
|
||||
// print mnemonic unless requested not to.
|
||||
if showMnemonic {
|
||||
|
@ -300,7 +302,7 @@ func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemo
|
|||
fmt.Fprintln(cmd.ErrOrStderr(), mnemonic)
|
||||
}
|
||||
case OutputFormatJSON:
|
||||
out, err := keyring.MkAccKeyOutput(info)
|
||||
out, err := keyring.MkAccKeyOutput(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
@ -42,7 +43,8 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) {
|
|||
// Prepare a keybase
|
||||
kbHome := t.TempDir()
|
||||
|
||||
clientCtx := client.Context{}.WithKeyringDir(kbHome)
|
||||
cdc := simapp.MakeTestEncodingConfig().Codec
|
||||
clientCtx := client.Context{}.WithKeyringDir(kbHome).WithCodec(cdc)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
||||
cmd.SetArgs([]string{
|
||||
|
@ -61,7 +63,7 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) {
|
|||
require.NoError(t, cmd.ExecuteContext(ctx))
|
||||
|
||||
// Now check that it has been stored properly
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn)
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn, cdc)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, kb)
|
||||
t.Cleanup(func() {
|
||||
|
@ -72,11 +74,13 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NotNil(t, key1)
|
||||
|
||||
require.Equal(t, "keyname1", key1.GetName())
|
||||
require.Equal(t, "keyname1", key1.Name)
|
||||
require.Equal(t, keyring.TypeLedger, key1.GetType())
|
||||
pub, err := key1.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t,
|
||||
"PubKeySecp256k1{03028F0D5A9FD41600191CDEFDEA05E77A68DFBCE286241C0190805B9346667D07}",
|
||||
key1.GetPubKey().String())
|
||||
pub.String())
|
||||
|
||||
config.SetPurpose(44)
|
||||
config.SetCoinType(118)
|
||||
|
@ -91,8 +95,9 @@ func Test_runAddCmdLedger(t *testing.T) {
|
|||
|
||||
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
|
||||
kbHome := t.TempDir()
|
||||
encCfg := simapp.MakeTestEncodingConfig()
|
||||
|
||||
clientCtx := client.Context{}.WithKeyringDir(kbHome)
|
||||
clientCtx := client.Context{}.WithKeyringDir(kbHome).WithCodec(encCfg.Codec)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
||||
cmd.SetArgs([]string{
|
||||
|
@ -108,8 +113,10 @@ func Test_runAddCmdLedger(t *testing.T) {
|
|||
require.NoError(t, cmd.ExecuteContext(ctx))
|
||||
|
||||
// Now check that it has been stored properly
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn)
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn, encCfg.Codec)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Now check that it has been stored properly
|
||||
require.NotNil(t, kb)
|
||||
t.Cleanup(func() {
|
||||
_ = kb.Delete("keyname1")
|
||||
|
@ -120,14 +127,16 @@ func Test_runAddCmdLedger(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NotNil(t, key1)
|
||||
|
||||
require.Equal(t, "keyname1", key1.GetName())
|
||||
require.Equal(t, keyring.TypeLedger, key1.GetType())
|
||||
require.Equal(t, "keyname1", key1.Name)
|
||||
pub, err := key1.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t,
|
||||
"PubKeySecp256k1{034FEF9CD7C4C63588D3B03FEB5281B9D232CBA34D6F3D71AEE59211FFBFE1FE87}",
|
||||
key1.GetPubKey().String())
|
||||
pub.String())
|
||||
}
|
||||
|
||||
func Test_runAddCmdLedgerDryRun(t *testing.T) {
|
||||
cdc := simapp.MakeTestEncodingConfig().Codec
|
||||
testData := []struct {
|
||||
name string
|
||||
args []string
|
||||
|
@ -152,6 +161,7 @@ func Test_runAddCmdLedgerDryRun(t *testing.T) {
|
|||
added: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testData {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -160,14 +170,14 @@ func Test_runAddCmdLedgerDryRun(t *testing.T) {
|
|||
|
||||
kbHome := t.TempDir()
|
||||
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn)
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
clientCtx := client.Context{}.
|
||||
WithKeyringDir(kbHome).
|
||||
WithKeyring(kb)
|
||||
WithKeyring(kb).
|
||||
WithCodec(cdc)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
||||
b := bytes.NewBufferString("")
|
||||
cmd.SetOut(b)
|
||||
|
||||
|
@ -184,7 +194,7 @@ func Test_runAddCmdLedgerDryRun(t *testing.T) {
|
|||
} else {
|
||||
_, err = kb.Key("testkey")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "testkey.info: key not found", err.Error())
|
||||
require.Equal(t, "testkey: key not found", err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -28,10 +28,12 @@ func Test_runAddCmdBasic(t *testing.T) {
|
|||
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
|
||||
kbHome := t.TempDir()
|
||||
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn)
|
||||
cdc := simapp.MakeTestEncodingConfig().Codec
|
||||
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
clientCtx := client.Context{}.WithKeyringDir(kbHome).WithInput(mockIn)
|
||||
clientCtx := client.Context{}.WithKeyringDir(kbHome).WithInput(mockIn).WithCodec(cdc)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
||||
t.Cleanup(func() {
|
||||
|
@ -122,6 +124,7 @@ func Test_runAddCmdBasic(t *testing.T) {
|
|||
func Test_runAddCmdDryRun(t *testing.T) {
|
||||
pubkey1 := `{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AtObiFVE4s+9+RX5SP8TN9r2mxpoaT4eGj9CJfK7VRzN"}`
|
||||
pubkey2 := `{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A/se1vkqgdQ7VJQCM4mxN+L+ciGhnnJ4XYsQCRBMrdRi"}`
|
||||
cdc := simapp.MakeTestEncodingConfig().Codec
|
||||
|
||||
testData := []struct {
|
||||
name string
|
||||
|
@ -189,12 +192,12 @@ func Test_runAddCmdDryRun(t *testing.T) {
|
|||
|
||||
kbHome := t.TempDir()
|
||||
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn)
|
||||
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
appCodec := simapp.MakeTestEncodingConfig().Codec
|
||||
clientCtx := client.Context{}.
|
||||
WithCodec(appCodec).
|
||||
WithCodec(cdc).
|
||||
WithKeyringDir(kbHome).
|
||||
WithKeyring(kb)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
@ -214,7 +217,7 @@ func Test_runAddCmdDryRun(t *testing.T) {
|
|||
require.NoError(t, cmd.ExecuteContext(ctx))
|
||||
|
||||
if tt.added {
|
||||
_, err = kb.Key("testkey")
|
||||
_, err := kb.Key("testkey")
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := ioutil.ReadAll(b)
|
||||
|
@ -223,7 +226,7 @@ func Test_runAddCmdDryRun(t *testing.T) {
|
|||
} else {
|
||||
_, err = kb.Key("testkey")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "testkey.info: key not found", err.Error())
|
||||
require.Equal(t, "testkey: key not found", err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -232,11 +235,12 @@ func Test_runAddCmdDryRun(t *testing.T) {
|
|||
func TestAddRecoverFileBackend(t *testing.T) {
|
||||
cmd := AddKeyCommand()
|
||||
cmd.Flags().AddFlagSet(Commands("home").PersistentFlags())
|
||||
cdc := simapp.MakeTestEncodingConfig().Codec
|
||||
|
||||
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
|
||||
kbHome := t.TempDir()
|
||||
|
||||
clientCtx := client.Context{}.WithKeyringDir(kbHome).WithInput(mockIn)
|
||||
clientCtx := client.Context{}.WithKeyringDir(kbHome).WithInput(mockIn).WithCodec(cdc)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
||||
cmd.SetArgs([]string{
|
||||
|
@ -259,7 +263,7 @@ func TestAddRecoverFileBackend(t *testing.T) {
|
|||
mockIn.Reset(fmt.Sprintf("%s\n%s\n%s\n", mnemonic, keyringPassword, keyringPassword))
|
||||
require.NoError(t, cmd.ExecuteContext(ctx))
|
||||
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendFile, kbHome, mockIn)
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendFile, kbHome, mockIn, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
|
@ -268,7 +272,7 @@ func TestAddRecoverFileBackend(t *testing.T) {
|
|||
})
|
||||
|
||||
mockIn.Reset(fmt.Sprintf("%s\n%s\n", keyringPassword, keyringPassword))
|
||||
info, err := kb.Key("keyname1")
|
||||
k, err := kb.Key("keyname1")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "keyname1", info.GetName())
|
||||
require.Equal(t, "keyname1", k.Name)
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ private keys stored in a ledger device cannot be deleted with the CLI.
|
|||
}
|
||||
|
||||
for _, name := range args {
|
||||
info, err := clientCtx.Keyring.Key(name)
|
||||
k, err := clientCtx.Keyring.Key(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ private keys stored in a ledger device cannot be deleted with the CLI.
|
|||
return err
|
||||
}
|
||||
|
||||
if info.GetType() == keyring.TypeLedger || info.GetType() == keyring.TypeOffline {
|
||||
if k.GetType() == keyring.TypeLedger || k.GetType() == keyring.TypeOffline {
|
||||
cmd.PrintErrln("Public key reference deleted")
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
@ -32,9 +33,10 @@ func Test_runDeleteCmd(t *testing.T) {
|
|||
fakeKeyName2 := "runDeleteCmd_Key2"
|
||||
|
||||
path := sdk.GetConfig().GetFullBIP44Path()
|
||||
cdc := simapp.MakeTestEncodingConfig().Codec
|
||||
|
||||
cmd.SetArgs([]string{"blah", fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome)})
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn)
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = kb.NewAccount(fakeKeyName1, testutil.TestMnemonic, "", path, hd.Secp256k1)
|
||||
|
@ -45,13 +47,13 @@ func Test_runDeleteCmd(t *testing.T) {
|
|||
|
||||
clientCtx := client.Context{}.
|
||||
WithKeyringDir(kbHome).
|
||||
WithKeyring(kb)
|
||||
WithCodec(cdc)
|
||||
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
||||
err = cmd.ExecuteContext(ctx)
|
||||
require.Error(t, err)
|
||||
require.EqualError(t, err, "blah.info: key not found")
|
||||
require.EqualError(t, err, "blah: key not found")
|
||||
|
||||
// User confirmation missing
|
||||
cmd.SetArgs([]string{
|
||||
|
|
|
@ -14,10 +14,12 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func Test_runExportCmd(t *testing.T) {
|
||||
cdc := simapp.MakeTestEncodingConfig().Codec
|
||||
testCases := []struct {
|
||||
name string
|
||||
keyringBackend string
|
||||
|
@ -84,7 +86,7 @@ func Test_runExportCmd(t *testing.T) {
|
|||
mockInBuf := bufio.NewReader(mockIn)
|
||||
|
||||
// create a key
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), tc.keyringBackend, kbHome, bufio.NewReader(mockInBuf))
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), tc.keyringBackend, kbHome, bufio.NewReader(mockInBuf), cdc)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
kb.Delete("keyname1") // nolint:errcheck
|
||||
|
@ -97,7 +99,8 @@ func Test_runExportCmd(t *testing.T) {
|
|||
clientCtx := client.Context{}.
|
||||
WithKeyringDir(kbHome).
|
||||
WithKeyring(kb).
|
||||
WithInput(mockInBuf)
|
||||
WithInput(mockInBuf).
|
||||
WithCodec(cdc)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
||||
err = cmd.ExecuteContext(ctx)
|
||||
|
|
|
@ -13,11 +13,13 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func Test_runImportCmd(t *testing.T) {
|
||||
cdc := simapp.MakeTestEncodingConfig().Codec
|
||||
testCases := []struct {
|
||||
name string
|
||||
keyringBackend string
|
||||
|
@ -80,15 +82,16 @@ HbP+c6JmeJy9JXe2rbbF1QtCX1gLqGcDQPBXiCtFvP7/8wTZtVOPj8vREzhZ9ElO
|
|||
|
||||
// Now add a temporary keybase
|
||||
kbHome := t.TempDir()
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), tc.keyringBackend, kbHome, nil)
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), tc.keyringBackend, kbHome, nil, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
clientCtx := client.Context{}.
|
||||
WithKeyringDir(kbHome).
|
||||
WithKeyring(kb).
|
||||
WithInput(mockIn)
|
||||
WithInput(mockIn).
|
||||
WithCodec(cdc)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
kb.Delete("keyname1") // nolint:errcheck
|
||||
})
|
||||
|
|
|
@ -28,18 +28,18 @@ func runListCmd(cmd *cobra.Command, _ []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
infos, err := clientCtx.Keyring.List()
|
||||
records, err := clientCtx.Keyring.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ok, _ := cmd.Flags().GetBool(flagListNames); !ok {
|
||||
printInfos(cmd.OutOrStdout(), infos, clientCtx.OutputFormat)
|
||||
printKeyringRecords(cmd.OutOrStdout(), records, clientCtx.OutputFormat)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, info := range infos {
|
||||
cmd.Println(info.GetName())
|
||||
for _, k := range records {
|
||||
cmd.Println(k.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
@ -24,7 +25,8 @@ func Test_runListCmd(t *testing.T) {
|
|||
kbHome2 := t.TempDir()
|
||||
|
||||
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome2, mockIn)
|
||||
encCfg := simapp.MakeTestEncodingConfig()
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome2, mockIn, encCfg.Codec)
|
||||
require.NoError(t, err)
|
||||
|
||||
clientCtx := client.Context{}.WithKeyring(kb)
|
||||
|
|
|
@ -1,147 +1,43 @@
|
|||
package keys
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/input"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
)
|
||||
|
||||
// migratePassphrase is used as a no-op migration key passphrase as a passphrase
|
||||
// is not needed for importing into the Keyring keystore.
|
||||
const migratePassphrase = "NOOP_PASSPHRASE"
|
||||
|
||||
// MigrateCommand migrates key information from legacy keybase to OS secret store.
|
||||
func MigrateCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "migrate <old_home_dir>",
|
||||
Short: "Migrate keys from the legacy (db-based) Keybase",
|
||||
Long: `Migrate key information from the legacy (db-based) Keybase to the new keyring-based Keyring.
|
||||
The legacy Keybase used to persist keys in a LevelDB database stored in a 'keys' sub-directory of
|
||||
the old client application's home directory, e.g. $HOME/.gaiacli/keys/.
|
||||
For each key material entry, the command will prompt if the key should be skipped or not. If the key
|
||||
is not to be skipped, the passphrase must be entered. The key will only be migrated if the passphrase
|
||||
is correct. Otherwise, the command will exit and migration must be repeated.
|
||||
Use: "migrate",
|
||||
Short: "Migrate keys from amino to proto serialization format",
|
||||
Long: `Migrate keys from Amino to Protocol Buffers records.
|
||||
For each key material entry, the command will check if the key can be deserialized using proto.
|
||||
If this is the case, the key is already migrated. Therefore, we skip it and continue with a next one.
|
||||
Otherwise, we try to deserialize it using Amino into LegacyInfo. If this attempt is successful, we serialize
|
||||
LegacyInfo to Protobuf serialization format and overwrite the keyring entry. If any error occurred, it will be
|
||||
outputted in CLI and migration will be continued until all keys in the keyring DB are exhausted.
|
||||
See https://github.com/cosmos/cosmos-sdk/pull/9695 for more details.
|
||||
|
||||
It is recommended to run in 'dry-run' mode first to verify all key migration material.
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Args: cobra.NoArgs,
|
||||
RunE: runMigrateCmd,
|
||||
}
|
||||
|
||||
cmd.Flags().Bool(flags.FlagDryRun, false, "Run migration without actually persisting any changes to the new Keybase")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runMigrateCmd(cmd *cobra.Command, args []string) error {
|
||||
rootDir, _ := cmd.Flags().GetString(flags.FlagHome)
|
||||
|
||||
// instantiate legacy keybase
|
||||
var legacyKb keyring.LegacyKeybase
|
||||
legacyKb, err := NewLegacyKeyBaseFromDir(args[0])
|
||||
func runMigrateCmd(cmd *cobra.Command, _ []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() { _ = legacyKb.Close() }()
|
||||
|
||||
// fetch list of keys from legacy keybase
|
||||
oldKeys, err := legacyKb.List()
|
||||
if err != nil {
|
||||
if _, err = clientCtx.Keyring.MigrateAll(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := bufio.NewReader(cmd.InOrStdin())
|
||||
keyringServiceName := sdk.KeyringServiceName()
|
||||
|
||||
var (
|
||||
tmpDir string
|
||||
migrator keyring.Importer
|
||||
)
|
||||
|
||||
if dryRun, _ := cmd.Flags().GetBool(flags.FlagDryRun); dryRun {
|
||||
tmpDir, err = ioutil.TempDir("", "migrator-migrate-dryrun")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create temporary directory for dryrun migration")
|
||||
}
|
||||
|
||||
defer func() { _ = os.RemoveAll(tmpDir) }()
|
||||
|
||||
migrator, err = keyring.New(keyringServiceName, keyring.BackendTest, tmpDir, buf)
|
||||
} else {
|
||||
backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
|
||||
migrator, err = keyring.New(keyringServiceName, backend, rootDir, buf)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf(
|
||||
"failed to initialize keybase for service %s at directory %s",
|
||||
keyringServiceName, rootDir,
|
||||
))
|
||||
}
|
||||
|
||||
if len(oldKeys) == 0 {
|
||||
cmd.PrintErrln("Migration Aborted: no keys to migrate")
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, oldInfo := range oldKeys {
|
||||
keyName := oldInfo.GetName()
|
||||
keyType := oldInfo.GetType()
|
||||
|
||||
cmd.PrintErrf("Migrating key: '%s (%s)' ...\n", keyName, keyType)
|
||||
|
||||
// allow user to skip migrating specific keys
|
||||
ok, err := input.GetConfirmation("Skip key migration?", buf, cmd.ErrOrStderr())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// TypeLocal needs an additional step to ask password.
|
||||
// The other keyring types are handled by ImportInfo.
|
||||
if keyType != keyring.TypeLocal {
|
||||
infoImporter, ok := migrator.(keyring.LegacyInfoImporter)
|
||||
if !ok {
|
||||
return fmt.Errorf("the Keyring implementation does not support import operations of Info types")
|
||||
}
|
||||
|
||||
if err = infoImporter.ImportInfo(oldInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
password, err := input.GetPassword("Enter passphrase to decrypt key:", buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// NOTE: A passphrase is not actually needed here as when the key information
|
||||
// is imported into the Keyring-based Keybase it only needs the password
|
||||
// (see: writeLocalKey).
|
||||
armoredPriv, err := legacyKb.ExportPrivKey(keyName, password, migratePassphrase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migrator.ImportPrivKey(keyName, armoredPriv, migratePassphrase); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
cmd.PrintErrln("Migration complete.")
|
||||
|
||||
return err
|
||||
cmd.Println("Keys migration has been successfully executed")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,40 +3,152 @@ package keys
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
design99keyring "github.com/99designs/keyring"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/otiai10/copy"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
)
|
||||
|
||||
func Test_runMigrateCmd(t *testing.T) {
|
||||
kbHome := t.TempDir()
|
||||
clientCtx := client.Context{}.WithKeyringDir(kbHome)
|
||||
type setter interface {
|
||||
SetItem(item design99keyring.Item) error
|
||||
}
|
||||
|
||||
type MigrateTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
dir string
|
||||
appName string
|
||||
cdc codec.Codec
|
||||
priv cryptotypes.PrivKey
|
||||
pub cryptotypes.PubKey
|
||||
}
|
||||
|
||||
func (s *MigrateTestSuite) SetupSuite() {
|
||||
s.dir = s.T().TempDir()
|
||||
s.cdc = simapp.MakeTestEncodingConfig().Codec
|
||||
s.appName = "cosmos"
|
||||
s.priv = cryptotypes.PrivKey(secp256k1.GenPrivKey())
|
||||
s.pub = s.priv.PubKey()
|
||||
}
|
||||
|
||||
func (s *MigrateTestSuite) Test_runListAndShowCmd() {
|
||||
|
||||
// adding LegacyInfo item into keyring
|
||||
multi := multisig.NewLegacyAminoPubKey(
|
||||
1, []cryptotypes.PubKey{
|
||||
s.pub,
|
||||
},
|
||||
)
|
||||
legacyMultiInfo, err := keyring.NewLegacyMultiInfo(s.appName, multi)
|
||||
s.Require().NoError(err)
|
||||
serializedLegacyMultiInfo := keyring.MarshalInfo(legacyMultiInfo)
|
||||
|
||||
item := design99keyring.Item{
|
||||
Key: s.appName,
|
||||
Data: serializedLegacyMultiInfo,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
//run test simd keys list - to see that the migrated key is there
|
||||
cmd := ListKeysCmd()
|
||||
cmd.Flags().AddFlagSet(Commands("home").PersistentFlags())
|
||||
|
||||
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
|
||||
kb, err := keyring.New(s.appName, keyring.BackendTest, s.dir, mockIn, s.cdc)
|
||||
s.Require().NoError(err)
|
||||
|
||||
setter, ok := kb.(setter)
|
||||
s.Require().True(ok)
|
||||
s.Require().NoError(setter.SetItem(item))
|
||||
|
||||
clientCtx := client.Context{}.WithKeyring(kb)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
||||
require.NoError(t, copy.Copy("testdata", kbHome))
|
||||
|
||||
cmd := MigrateCommand()
|
||||
cmd.Flags().AddFlagSet(Commands("home").PersistentFlags())
|
||||
//mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
|
||||
mockIn, mockOut := testutil.ApplyMockIO(cmd)
|
||||
|
||||
cmd.SetArgs([]string{
|
||||
kbHome,
|
||||
//fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
|
||||
fmt.Sprintf("--%s=true", flags.FlagDryRun),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagHome, s.dir),
|
||||
fmt.Sprintf("--%s=false", flagListNames),
|
||||
})
|
||||
|
||||
mockIn.Reset("\n12345678\n\n\n\n\n")
|
||||
t.Log(mockOut.String())
|
||||
assert.NoError(t, cmd.ExecuteContext(ctx))
|
||||
s.Require().NoError(cmd.ExecuteContext(ctx))
|
||||
|
||||
// simd show n1 - to see that the migration worked
|
||||
cmd = ShowKeysCmd()
|
||||
cmd.SetArgs([]string{s.appName})
|
||||
clientCtx = clientCtx.WithCodec(s.cdc)
|
||||
ctx = context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
s.Require().NoError(cmd.ExecuteContext(ctx))
|
||||
}
|
||||
|
||||
func (s *MigrateTestSuite) Test_runMigrateCmdRecord() {
|
||||
k, err := keyring.NewLocalRecord("test record", s.priv, s.pub)
|
||||
s.Require().NoError(err)
|
||||
serializedRecord, err := s.cdc.Marshal(k)
|
||||
s.Require().NoError(err)
|
||||
|
||||
item := design99keyring.Item{
|
||||
Key: s.appName,
|
||||
Data: serializedRecord,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
cmd := MigrateCommand()
|
||||
mockIn := strings.NewReader("")
|
||||
kb, err := keyring.New(s.appName, keyring.BackendTest, s.dir, mockIn, s.cdc)
|
||||
s.Require().NoError(err)
|
||||
|
||||
setter, ok := kb.(setter)
|
||||
s.Require().True(ok)
|
||||
s.Require().NoError(setter.SetItem(item))
|
||||
|
||||
clientCtx := client.Context{}.WithKeyring(kb)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
s.Require().NoError(cmd.ExecuteContext(ctx))
|
||||
}
|
||||
|
||||
func (s *MigrateTestSuite) Test_runMigrateCmdLegacyMultiInfo() {
|
||||
// adding LegacyInfo item into keyring
|
||||
multi := multisig.NewLegacyAminoPubKey(
|
||||
1, []cryptotypes.PubKey{
|
||||
s.pub,
|
||||
},
|
||||
)
|
||||
|
||||
legacyMultiInfo, err := keyring.NewLegacyMultiInfo(s.appName, multi)
|
||||
s.Require().NoError(err)
|
||||
serializedLegacyMultiInfo := keyring.MarshalInfo(legacyMultiInfo)
|
||||
|
||||
item := design99keyring.Item{
|
||||
Key: s.appName,
|
||||
Data: serializedLegacyMultiInfo,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
cmd := MigrateCommand()
|
||||
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
|
||||
|
||||
kb, err := keyring.New(s.appName, keyring.BackendTest, s.dir, mockIn, s.cdc)
|
||||
s.Require().NoError(err)
|
||||
|
||||
setter, ok := kb.(setter)
|
||||
s.Require().True(ok)
|
||||
s.Require().NoError(setter.SetItem(item))
|
||||
|
||||
clientCtx := client.Context{}.WithKeyring(kb)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
s.Require().NoError(cmd.ExecuteContext(ctx))
|
||||
}
|
||||
|
||||
func TestMigrateTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(MigrateTestSuite))
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"crypto/sha256"
|
||||
"fmt"
|
||||
|
||||
bip39 "github.com/cosmos/go-bip39"
|
||||
"github.com/cosmos/go-bip39"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/input"
|
||||
|
|
|
@ -31,7 +31,7 @@ private keys stored in a ledger device cannot be renamed with the CLI.
|
|||
|
||||
oldName, newName := args[0], args[1]
|
||||
|
||||
info, err := clientCtx.Keyring.Key(oldName)
|
||||
k, err := clientCtx.Keyring.Key(oldName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ private keys stored in a ledger device cannot be renamed with the CLI.
|
|||
return err
|
||||
}
|
||||
|
||||
if info.GetType() == keyring.TypeLedger || info.GetType() == keyring.TypeOffline {
|
||||
if k.GetType() == keyring.TypeLedger || k.GetType() == keyring.TypeOffline {
|
||||
cmd.PrintErrln("Public key reference renamed")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
@ -30,7 +31,8 @@ func Test_runRenameCmd(t *testing.T) {
|
|||
|
||||
path := sdk.GetConfig().GetFullBIP44Path()
|
||||
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn)
|
||||
cdc := simapp.MakeTestEncodingConfig().Codec
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
// put fakeKeyName1 in keyring
|
||||
|
@ -39,7 +41,7 @@ func Test_runRenameCmd(t *testing.T) {
|
|||
|
||||
clientCtx := client.Context{}.
|
||||
WithKeyringDir(kbHome).
|
||||
WithKeyring(kb)
|
||||
WithCodec(cdc)
|
||||
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
||||
|
@ -47,7 +49,7 @@ func Test_runRenameCmd(t *testing.T) {
|
|||
cmd.SetArgs([]string{"blah", "blaah", fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome)})
|
||||
err = cmd.ExecuteContext(ctx)
|
||||
require.Error(t, err)
|
||||
require.EqualError(t, err, "blah.info: key not found")
|
||||
require.EqualError(t, err, "blah: key not found")
|
||||
|
||||
// User confirmation missing
|
||||
cmd.SetArgs([]string{
|
||||
|
@ -80,11 +82,18 @@ func Test_runRenameCmd(t *testing.T) {
|
|||
// key2 exists now
|
||||
renamedKey, err := kb.Key(fakeKeyName2)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, oldKey.GetPubKey(), renamedKey.GetPubKey())
|
||||
oldPk, err := oldKey.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
renamedPk, err := renamedKey.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, oldPk, renamedPk)
|
||||
require.Equal(t, oldKey.GetType(), renamedKey.GetType())
|
||||
require.Equal(t, oldKey.GetAddress(), renamedKey.GetAddress())
|
||||
require.Equal(t, oldKey.GetAlgo(), renamedKey.GetAlgo())
|
||||
|
||||
oldAddr, err := oldKey.GetAddress()
|
||||
require.NoError(t, err)
|
||||
renamedAddr, err := renamedKey.GetAddress()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, oldAddr, renamedAddr)
|
||||
|
||||
// try to rename key1 but it doesnt exist anymore so error
|
||||
cmd.SetArgs([]string{
|
||||
|
|
|
@ -27,8 +27,6 @@ const (
|
|||
FlagDevice = "device"
|
||||
|
||||
flagMultiSigThreshold = "multisig-threshold"
|
||||
|
||||
defaultMultiSigKeyName = "multi"
|
||||
)
|
||||
|
||||
// ShowKeysCmd shows key information for a given key name.
|
||||
|
@ -53,36 +51,40 @@ consisting of all the keys provided by name and multisig threshold.`,
|
|||
}
|
||||
|
||||
func runShowCmd(cmd *cobra.Command, args []string) (err error) {
|
||||
var info keyring.Info
|
||||
k := new(keyring.Record)
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
outputFormat := clientCtx.OutputFormat
|
||||
|
||||
if len(args) == 1 {
|
||||
info, err = fetchKey(clientCtx.Keyring, args[0])
|
||||
k, err = fetchKey(clientCtx.Keyring, args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s is not a valid name or address: %v", args[0], err)
|
||||
}
|
||||
} else {
|
||||
pks := make([]cryptotypes.PubKey, len(args))
|
||||
for i, keyref := range args {
|
||||
info, err := fetchKey(clientCtx.Keyring, keyref)
|
||||
k, err := fetchKey(clientCtx.Keyring, keyref)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s is not a valid name or address: %v", keyref, err)
|
||||
}
|
||||
|
||||
pks[i] = info.GetPubKey()
|
||||
key, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pks[i] = key
|
||||
}
|
||||
|
||||
multisigThreshold, _ := cmd.Flags().GetInt(flagMultiSigThreshold)
|
||||
err = validateMultisigThreshold(multisigThreshold, len(args))
|
||||
if err != nil {
|
||||
|
||||
if err := validateMultisigThreshold(multisigThreshold, len(args)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
multikey := multisig.NewLegacyAminoPubKey(multisigThreshold, pks)
|
||||
info, err = keyring.NewMultiInfo(defaultMultiSigKeyName, multikey)
|
||||
k, err = keyring.NewMultiRecord(k.Name, multikey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -118,7 +120,7 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) {
|
|||
|
||||
switch {
|
||||
case isShowAddr, isShowPubKey:
|
||||
ko, err := bechKeyOut(info)
|
||||
ko, err := bechKeyOut(k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -128,7 +130,7 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) {
|
|||
}
|
||||
fmt.Fprintln(cmd.OutOrStdout(), out)
|
||||
default:
|
||||
printKeyInfo(cmd.OutOrStdout(), info, bechKeyOut, clientCtx.OutputFormat)
|
||||
printKeyringRecord(cmd.OutOrStdout(), k, bechKeyOut, outputFormat)
|
||||
}
|
||||
|
||||
if isShowDevice {
|
||||
|
@ -140,36 +142,43 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) {
|
|||
}
|
||||
|
||||
// Override and show in the device
|
||||
if info.GetType() != keyring.TypeLedger {
|
||||
if k.GetType() != keyring.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
|
||||
ledgerItem := k.GetLedger()
|
||||
if ledgerItem == nil {
|
||||
return errors.New("unable to get ledger item")
|
||||
}
|
||||
|
||||
return ledger.ShowAddress(*hdpath, info.GetPubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix())
|
||||
pk, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ledger.ShowAddress(*ledgerItem.Path, pk, sdk.GetConfig().GetBech32AccountAddrPrefix())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchKey(kb keyring.Keyring, keyref string) (keyring.Info, error) {
|
||||
func fetchKey(kb keyring.Keyring, keyref string) (*keyring.Record, error) {
|
||||
// firstly check if the keyref is a key name of a key registered in a keyring.
|
||||
info, err := kb.Key(keyref)
|
||||
k, err := kb.Key(keyref)
|
||||
// if the key is not there or if we have a problem with a keyring itself then we move to a
|
||||
// fallback: searching for key by address.
|
||||
|
||||
if err == nil || !sdkerr.IsOf(err, sdkerr.ErrIO, sdkerr.ErrKeyNotFound) {
|
||||
return info, err
|
||||
}
|
||||
accAddr, err := sdk.AccAddressFromBech32(keyref)
|
||||
if err != nil {
|
||||
return info, err
|
||||
return k, err
|
||||
}
|
||||
|
||||
info, err = kb.KeyByAddress(accAddr)
|
||||
return info, sdkerr.Wrap(err, "Invalid key")
|
||||
accAddr, err := sdk.AccAddressFromBech32(keyref)
|
||||
if err != nil {
|
||||
return k, err
|
||||
}
|
||||
|
||||
k, err = kb.KeyByAddress(accAddr)
|
||||
return k, sdkerr.Wrap(err, "Invalid key")
|
||||
}
|
||||
|
||||
func validateMultisigThreshold(k, nKeys int) error {
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
@ -24,12 +25,18 @@ func Test_multiSigKey_Properties(t *testing.T) {
|
|||
1,
|
||||
[]cryptotypes.PubKey{tmpKey1.PubKey()},
|
||||
)
|
||||
tmp, err := keyring.NewMultiInfo("myMultisig", pk)
|
||||
k, err := keyring.NewMultiRecord("myMultisig", pk)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "myMultisig", tmp.GetName())
|
||||
require.Equal(t, keyring.TypeMulti, tmp.GetType())
|
||||
require.Equal(t, "D3923267FA8A3DD367BB768FA8BDC8FF7F89DA3F", tmp.GetPubKey().Address().String())
|
||||
require.Equal(t, "cosmos16wfryel63g7axeamw68630wglalcnk3l0zuadc", sdk.MustBech32ifyAddressBytes("cosmos", tmp.GetAddress()))
|
||||
require.Equal(t, "myMultisig", k.Name)
|
||||
require.Equal(t, keyring.TypeMulti, k.GetType())
|
||||
|
||||
pub, err := k.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "D3923267FA8A3DD367BB768FA8BDC8FF7F89DA3F", pub.Address().String())
|
||||
|
||||
addr, err := k.GetAddress()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "cosmos16wfryel63g7axeamw68630wglalcnk3l0zuadc", sdk.MustBech32ifyAddressBytes("cosmos", addr))
|
||||
}
|
||||
|
||||
func Test_showKeysCmd(t *testing.T) {
|
||||
|
@ -45,12 +52,13 @@ func Test_runShowCmd(t *testing.T) {
|
|||
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
|
||||
|
||||
kbHome := t.TempDir()
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn)
|
||||
cdc := simapp.MakeTestEncodingConfig().Codec
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
clientCtx := client.Context{}.
|
||||
WithKeyringDir(kbHome).
|
||||
WithKeyring(kb)
|
||||
WithCodec(cdc)
|
||||
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
|
||||
|
||||
cmd.SetArgs([]string{"invalid"})
|
||||
|
@ -79,49 +87,51 @@ func Test_runShowCmd(t *testing.T) {
|
|||
cmd.SetArgs([]string{
|
||||
fakeKeyName1,
|
||||
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
fmt.Sprintf("--%s=", FlagBechPrefix),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
})
|
||||
require.EqualError(t, cmd.ExecuteContext(ctx), "invalid Bech32 prefix encoding provided: ")
|
||||
|
||||
cmd.SetArgs([]string{
|
||||
fakeKeyName1,
|
||||
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
fmt.Sprintf("--%s=%s", FlagBechPrefix, sdk.PrefixAccount),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
})
|
||||
|
||||
// try fetch by name
|
||||
require.NoError(t, cmd.ExecuteContext(ctx))
|
||||
|
||||
// try fetch by addr
|
||||
info, err := kb.Key(fakeKeyName1)
|
||||
k, err := kb.Key(fakeKeyName1)
|
||||
require.NoError(t, err)
|
||||
addr, err := k.GetAddress()
|
||||
require.NoError(t, err)
|
||||
cmd.SetArgs([]string{
|
||||
info.GetAddress().String(),
|
||||
addr.String(),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
fmt.Sprintf("--%s=%s", FlagBechPrefix, sdk.PrefixAccount),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, cmd.ExecuteContext(ctx))
|
||||
|
||||
// Now try multisig key - set bech to acc
|
||||
cmd.SetArgs([]string{
|
||||
fakeKeyName1, fakeKeyName2,
|
||||
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
fmt.Sprintf("--%s=%s", FlagBechPrefix, sdk.PrefixAccount),
|
||||
fmt.Sprintf("--%s=0", flagMultiSigThreshold),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
})
|
||||
require.EqualError(t, cmd.ExecuteContext(ctx), "threshold must be a positive integer")
|
||||
|
||||
cmd.SetArgs([]string{
|
||||
fakeKeyName1, fakeKeyName2,
|
||||
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
fmt.Sprintf("--%s=%s", FlagBechPrefix, sdk.PrefixAccount),
|
||||
fmt.Sprintf("--%s=2", flagMultiSigThreshold),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
})
|
||||
require.NoError(t, cmd.ExecuteContext(ctx))
|
||||
|
||||
|
@ -129,31 +139,31 @@ func Test_runShowCmd(t *testing.T) {
|
|||
cmd.SetArgs([]string{
|
||||
fakeKeyName1, fakeKeyName2,
|
||||
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
fmt.Sprintf("--%s=acc", FlagBechPrefix),
|
||||
fmt.Sprintf("--%s=true", FlagDevice),
|
||||
fmt.Sprintf("--%s=2", flagMultiSigThreshold),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
})
|
||||
require.EqualError(t, cmd.ExecuteContext(ctx), "the device flag (-d) can only be used for accounts stored in devices")
|
||||
|
||||
cmd.SetArgs([]string{
|
||||
fakeKeyName1, fakeKeyName2,
|
||||
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
fmt.Sprintf("--%s=val", FlagBechPrefix),
|
||||
fmt.Sprintf("--%s=true", FlagDevice),
|
||||
fmt.Sprintf("--%s=2", flagMultiSigThreshold),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
})
|
||||
require.EqualError(t, cmd.ExecuteContext(ctx), "the device flag (-d) can only be used for accounts")
|
||||
|
||||
cmd.SetArgs([]string{
|
||||
fakeKeyName1, fakeKeyName2,
|
||||
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
fmt.Sprintf("--%s=val", FlagBechPrefix),
|
||||
fmt.Sprintf("--%s=true", FlagDevice),
|
||||
fmt.Sprintf("--%s=2", flagMultiSigThreshold),
|
||||
fmt.Sprintf("--%s=true", FlagPublicKey),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
|
||||
})
|
||||
require.EqualError(t, cmd.ExecuteContext(ctx), "the device flag (-d) can only be used for addresses not pubkeys")
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package keys
|
||||
|
||||
// used for outputting keyring.Info over REST
|
||||
// used for outputting keyring.LegacyInfo over REST
|
||||
|
||||
// AddNewKey request a new key
|
||||
type AddNewKey struct {
|
||||
|
|
|
@ -3,7 +3,6 @@ package keys
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
|
@ -14,32 +13,19 @@ import (
|
|||
const (
|
||||
OutputFormatText = "text"
|
||||
OutputFormatJSON = "json"
|
||||
|
||||
// defaultKeyDBName is the client's subdirectory where keys are stored.
|
||||
defaultKeyDBName = "keys"
|
||||
)
|
||||
|
||||
type bechKeyOutFn func(keyInfo cryptokeyring.Info) (cryptokeyring.KeyOutput, error)
|
||||
type bechKeyOutFn func(k *cryptokeyring.Record) (cryptokeyring.KeyOutput, error)
|
||||
|
||||
// NewLegacyKeyBaseFromDir initializes a legacy keybase at the rootDir directory. Keybase
|
||||
// options can be applied when generating this new Keybase.
|
||||
func NewLegacyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.LegacyKeybase, error) {
|
||||
return getLegacyKeyBaseFromDir(rootDir, opts...)
|
||||
}
|
||||
|
||||
func getLegacyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.LegacyKeybase, error) {
|
||||
return cryptokeyring.NewLegacy(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...)
|
||||
}
|
||||
|
||||
func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn, output string) {
|
||||
ko, err := bechKeyOut(keyInfo)
|
||||
func printKeyringRecord(w io.Writer, k *cryptokeyring.Record, bechKeyOut bechKeyOutFn, output string) {
|
||||
ko, err := bechKeyOut(k)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch output {
|
||||
case OutputFormatText:
|
||||
printTextInfos(w, []cryptokeyring.KeyOutput{ko})
|
||||
printTextRecords(w, []cryptokeyring.KeyOutput{ko})
|
||||
|
||||
case OutputFormatJSON:
|
||||
out, err := KeysCdc.MarshalJSON(ko)
|
||||
|
@ -51,17 +37,19 @@ func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOut
|
|||
}
|
||||
}
|
||||
|
||||
func printInfos(w io.Writer, infos []cryptokeyring.Info, output string) {
|
||||
kos, err := cryptokeyring.MkAccKeysOutput(infos)
|
||||
func printKeyringRecords(w io.Writer, records []*cryptokeyring.Record, output string) {
|
||||
kos, err := cryptokeyring.MkAccKeysOutput(records)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch output {
|
||||
case OutputFormatText:
|
||||
printTextInfos(w, kos)
|
||||
printTextRecords(w, kos)
|
||||
|
||||
case OutputFormatJSON:
|
||||
// TODO https://github.com/cosmos/cosmos-sdk/issues/8046
|
||||
// Replace AminoCdc with Proto JSON
|
||||
out, err := KeysCdc.MarshalJSON(kos)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -71,10 +59,11 @@ func printInfos(w io.Writer, infos []cryptokeyring.Info, output string) {
|
|||
}
|
||||
}
|
||||
|
||||
func printTextInfos(w io.Writer, kos []cryptokeyring.KeyOutput) {
|
||||
func printTextRecords(w io.Writer, kos []cryptokeyring.KeyOutput) {
|
||||
out, err := yaml.Marshal(&kos)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Fprintln(w, string(out))
|
||||
}
|
||||
|
|
|
@ -197,12 +197,16 @@ func Sign(txf Factory, name string, txBuilder client.TxBuilder, overwriteSig boo
|
|||
return err
|
||||
}
|
||||
|
||||
key, err := txf.keybase.Key(name)
|
||||
k, err := txf.keybase.Key(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pubKey, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pubKey := key.GetPubKey()
|
||||
pubkeys, err := txBuilder.GetTx().GetPubKeys()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -134,24 +134,27 @@ func TestBuildUnsignedTx(t *testing.T) {
|
|||
func TestSign(t *testing.T) {
|
||||
requireT := require.New(t)
|
||||
path := hd.CreateHDPath(118, 0, 0).String()
|
||||
kr, err := keyring.New(t.Name(), "test", t.TempDir(), nil)
|
||||
encCfg := simapp.MakeTestEncodingConfig()
|
||||
kb, err := keyring.New(t.Name(), "test", t.TempDir(), nil, encCfg.Codec)
|
||||
requireT.NoError(err)
|
||||
|
||||
var from1 = "test_key1"
|
||||
var from2 = "test_key2"
|
||||
|
||||
// create a new key using a mnemonic generator and test if we can reuse seed to recreate that account
|
||||
_, seed, err := kr.NewMnemonic(from1, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
_, seed, err := kb.NewMnemonic(from1, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
requireT.NoError(err)
|
||||
requireT.NoError(kr.Delete(from1))
|
||||
info1, _, err := kr.NewMnemonic(from1, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
requireT.NoError(kb.Delete(from1))
|
||||
k1, _, err := kb.NewMnemonic(from1, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
requireT.NoError(err)
|
||||
|
||||
info2, err := kr.NewAccount(from2, seed, "", path, hd.Secp256k1)
|
||||
k2, err := kb.NewAccount(from2, seed, "", path, hd.Secp256k1)
|
||||
requireT.NoError(err)
|
||||
|
||||
pubKey1 := info1.GetPubKey()
|
||||
pubKey2 := info2.GetPubKey()
|
||||
pubKey1, err := k1.GetPubKey()
|
||||
requireT.NoError(err)
|
||||
pubKey2, err := k2.GetPubKey()
|
||||
requireT.NoError(err)
|
||||
requireT.NotEqual(pubKey1.Bytes(), pubKey2.Bytes())
|
||||
t.Log("Pub keys:", pubKey1, pubKey2)
|
||||
|
||||
|
@ -163,12 +166,16 @@ func TestSign(t *testing.T) {
|
|||
WithMemo("memo").
|
||||
WithChainID("test-chain")
|
||||
txfDirect := txfNoKeybase.
|
||||
WithKeybase(kr).
|
||||
WithKeybase(kb).
|
||||
WithSignMode(signingtypes.SignMode_SIGN_MODE_DIRECT)
|
||||
txfAmino := txfDirect.
|
||||
WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
||||
msg1 := banktypes.NewMsgSend(info1.GetAddress(), sdk.AccAddress("to"), nil)
|
||||
msg2 := banktypes.NewMsgSend(info2.GetAddress(), sdk.AccAddress("to"), nil)
|
||||
addr1, err := k1.GetAddress()
|
||||
requireT.NoError(err)
|
||||
addr2, err := k2.GetAddress()
|
||||
requireT.NoError(err)
|
||||
msg1 := banktypes.NewMsgSend(addr1, sdk.AccAddress("to"), nil)
|
||||
msg2 := banktypes.NewMsgSend(addr2, sdk.AccAddress("to"), nil)
|
||||
txb, err := txfNoKeybase.BuildUnsignedTx(msg1, msg2)
|
||||
requireT.NoError(err)
|
||||
txb2, err := txfNoKeybase.BuildUnsignedTx(msg1, msg2)
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
|
@ -70,26 +71,29 @@ func TestArmorUnarmorPrivKey(t *testing.T) {
|
|||
|
||||
func TestArmorUnarmorPubKey(t *testing.T) {
|
||||
// Select the encryption and storage for your cryptostore
|
||||
cstore := keyring.NewInMemory()
|
||||
encCfg := simapp.MakeTestEncodingConfig()
|
||||
cstore := keyring.NewInMemory(encCfg.Codec)
|
||||
|
||||
// Add keys and see they return in alphabetical order
|
||||
info, _, err := cstore.NewMnemonic("Bob", keyring.English, types.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
k, _, err := cstore.NewMnemonic("Bob", keyring.English, types.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
require.NoError(t, err)
|
||||
armored := crypto.ArmorPubKeyBytes(legacy.Cdc.Amino.MustMarshalBinaryBare(info.GetPubKey()), "")
|
||||
key, err := k.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
armored := crypto.ArmorPubKeyBytes(legacy.Cdc.Amino.MustMarshalBinaryBare(key), "")
|
||||
pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armored)
|
||||
require.NoError(t, err)
|
||||
pub, err := legacy.PubKeyFromBytes(pubBytes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, string(hd.Secp256k1Type), algo)
|
||||
require.True(t, pub.Equals(info.GetPubKey()))
|
||||
require.True(t, pub.Equals(key))
|
||||
|
||||
armored = crypto.ArmorPubKeyBytes(legacy.Cdc.Amino.MustMarshalBinaryBare(info.GetPubKey()), "unknown")
|
||||
armored = crypto.ArmorPubKeyBytes(legacy.Cdc.Amino.MustMarshalBinaryBare(key), "unknown")
|
||||
pubBytes, algo, err = crypto.UnarmorPubKeyBytes(armored)
|
||||
require.NoError(t, err)
|
||||
pub, err = legacy.PubKeyFromBytes(pubBytes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "unknown", algo)
|
||||
require.True(t, pub.Equals(info.GetPubKey()))
|
||||
require.True(t, pub.Equals(key))
|
||||
|
||||
armored, err = cstore.ExportPrivKeyArmor("Bob", "passphrase")
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -16,5 +16,10 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
|||
registry.RegisterImplementations(pk, &ed25519.PubKey{})
|
||||
registry.RegisterImplementations(pk, &secp256k1.PubKey{})
|
||||
registry.RegisterImplementations(pk, &multisig.LegacyAminoPubKey{})
|
||||
|
||||
var priv *cryptotypes.PrivKey
|
||||
registry.RegisterInterface("cosmos.crypto.PrivKey", priv)
|
||||
registry.RegisterImplementations(priv, &secp256k1.PrivKey{})
|
||||
registry.RegisterImplementations(priv, &ed25519.PrivKey{}) //nolint
|
||||
secp256r1.RegisterInterfaces(registry)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package hd
|
||||
|
||||
import (
|
||||
bip39 "github.com/cosmos/go-bip39"
|
||||
"github.com/cosmos/go-bip39"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
bip39 "github.com/cosmos/go-bip39"
|
||||
"github.com/cosmos/go-bip39"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
|
|
|
@ -0,0 +1,422 @@
|
|||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: cosmos/crypto/hd/v1/hd.proto
|
||||
|
||||
package hd
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
_ "github.com/gogo/protobuf/gogoproto"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// BIP44Params is used as path field in ledger item in Record.
|
||||
type BIP44Params struct {
|
||||
// purpose is a constant set to 44' (or 0x8000002C) following the BIP43 recommendation
|
||||
Purpose uint32 `protobuf:"varint,1,opt,name=purpose,proto3" json:"purpose,omitempty"`
|
||||
// coin_type is a constant that improves privacy
|
||||
CoinType uint32 `protobuf:"varint,2,opt,name=coin_type,json=coinType,proto3" json:"coin_type,omitempty"`
|
||||
// account splits the key space into independent user identities
|
||||
Account uint32 `protobuf:"varint,3,opt,name=account,proto3" json:"account,omitempty"`
|
||||
// change is a constant used for public derivation. Constant 0 is used for external chain and constant 1 for internal chain.
|
||||
Change bool `protobuf:"varint,4,opt,name=change,proto3" json:"change,omitempty"`
|
||||
// address_index is used as child index in BIP32 derivation
|
||||
AddressIndex uint32 `protobuf:"varint,5,opt,name=address_index,json=addressIndex,proto3" json:"address_index,omitempty"`
|
||||
}
|
||||
|
||||
func (m *BIP44Params) Reset() { *m = BIP44Params{} }
|
||||
func (*BIP44Params) ProtoMessage() {}
|
||||
func (*BIP44Params) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_cf10f1fb5e778a8d, []int{0}
|
||||
}
|
||||
func (m *BIP44Params) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *BIP44Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_BIP44Params.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *BIP44Params) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_BIP44Params.Merge(m, src)
|
||||
}
|
||||
func (m *BIP44Params) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *BIP44Params) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_BIP44Params.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_BIP44Params proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*BIP44Params)(nil), "cosmos.crypto.hd.v1.BIP44Params")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("cosmos/crypto/hd/v1/hd.proto", fileDescriptor_cf10f1fb5e778a8d) }
|
||||
|
||||
var fileDescriptor_cf10f1fb5e778a8d = []byte{
|
||||
// 266 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x49, 0xce, 0x2f, 0xce,
|
||||
0xcd, 0x2f, 0xd6, 0x4f, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0xcf, 0x48, 0xd1, 0x2f, 0x33, 0xd4,
|
||||
0xcf, 0x48, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x86, 0xc8, 0xea, 0x41, 0x64, 0xf5,
|
||||
0x32, 0x52, 0xf4, 0xca, 0x0c, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0xf2, 0xfa, 0x20, 0x16,
|
||||
0x44, 0xa9, 0xd2, 0x42, 0x46, 0x2e, 0x6e, 0x27, 0xcf, 0x00, 0x13, 0x93, 0x80, 0xc4, 0xa2, 0xc4,
|
||||
0xdc, 0x62, 0x21, 0x09, 0x2e, 0xf6, 0x82, 0xd2, 0xa2, 0x82, 0xfc, 0xe2, 0x54, 0x09, 0x46, 0x05,
|
||||
0x46, 0x0d, 0xde, 0x20, 0x18, 0x57, 0x48, 0x9a, 0x8b, 0x33, 0x39, 0x3f, 0x33, 0x2f, 0xbe, 0xa4,
|
||||
0xb2, 0x20, 0x55, 0x82, 0x09, 0x2c, 0xc7, 0x01, 0x12, 0x08, 0xa9, 0x2c, 0x48, 0x05, 0x69, 0x4b,
|
||||
0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0x91, 0x60, 0x86, 0x68, 0x83, 0x72, 0x85, 0xc4, 0xb8, 0xd8,
|
||||
0x92, 0x33, 0x12, 0xf3, 0xd2, 0x53, 0x25, 0x58, 0x14, 0x18, 0x35, 0x38, 0x82, 0xa0, 0x3c, 0x21,
|
||||
0x65, 0x2e, 0xde, 0xc4, 0x94, 0x94, 0xa2, 0xd4, 0xe2, 0xe2, 0xf8, 0xcc, 0xbc, 0x94, 0xd4, 0x0a,
|
||||
0x09, 0x56, 0xb0, 0x3e, 0x1e, 0xa8, 0xa0, 0x27, 0x48, 0xcc, 0x8a, 0x65, 0xc6, 0x02, 0x79, 0x06,
|
||||
0x27, 0x97, 0x13, 0x0f, 0xe5, 0x18, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1,
|
||||
0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21,
|
||||
0x4a, 0x2d, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x1f, 0x16, 0x2a, 0x60,
|
||||
0x4a, 0xb7, 0x38, 0x25, 0x1b, 0x11, 0x40, 0x49, 0x6c, 0x60, 0x0f, 0x1b, 0x03, 0x02, 0x00, 0x00,
|
||||
0xff, 0xff, 0x31, 0xf6, 0x77, 0xe8, 0x3b, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *BIP44Params) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *BIP44Params) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *BIP44Params) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.AddressIndex != 0 {
|
||||
i = encodeVarintHd(dAtA, i, uint64(m.AddressIndex))
|
||||
i--
|
||||
dAtA[i] = 0x28
|
||||
}
|
||||
if m.Change {
|
||||
i--
|
||||
if m.Change {
|
||||
dAtA[i] = 1
|
||||
} else {
|
||||
dAtA[i] = 0
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x20
|
||||
}
|
||||
if m.Account != 0 {
|
||||
i = encodeVarintHd(dAtA, i, uint64(m.Account))
|
||||
i--
|
||||
dAtA[i] = 0x18
|
||||
}
|
||||
if m.CoinType != 0 {
|
||||
i = encodeVarintHd(dAtA, i, uint64(m.CoinType))
|
||||
i--
|
||||
dAtA[i] = 0x10
|
||||
}
|
||||
if m.Purpose != 0 {
|
||||
i = encodeVarintHd(dAtA, i, uint64(m.Purpose))
|
||||
i--
|
||||
dAtA[i] = 0x8
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintHd(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovHd(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *BIP44Params) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.Purpose != 0 {
|
||||
n += 1 + sovHd(uint64(m.Purpose))
|
||||
}
|
||||
if m.CoinType != 0 {
|
||||
n += 1 + sovHd(uint64(m.CoinType))
|
||||
}
|
||||
if m.Account != 0 {
|
||||
n += 1 + sovHd(uint64(m.Account))
|
||||
}
|
||||
if m.Change {
|
||||
n += 2
|
||||
}
|
||||
if m.AddressIndex != 0 {
|
||||
n += 1 + sovHd(uint64(m.AddressIndex))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovHd(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozHd(x uint64) (n int) {
|
||||
return sovHd(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *BIP44Params) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHd
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: BIP44Params: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: BIP44Params: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Purpose", wireType)
|
||||
}
|
||||
m.Purpose = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHd
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Purpose |= uint32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType)
|
||||
}
|
||||
m.CoinType = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHd
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.CoinType |= uint32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Account", wireType)
|
||||
}
|
||||
m.Account = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHd
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Account |= uint32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 4:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Change", wireType)
|
||||
}
|
||||
var v int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHd
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
v |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.Change = bool(v != 0)
|
||||
case 5:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field AddressIndex", wireType)
|
||||
}
|
||||
m.AddressIndex = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowHd
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.AddressIndex |= uint32(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipHd(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthHd
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipHd(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowHd
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowHd
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowHd
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthHd
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupHd
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthHd
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthHd = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowHd = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupHd = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
|
@ -13,18 +13,6 @@ import (
|
|||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
// BIP44Params wraps BIP 44 params (5 level BIP 32 path).
|
||||
// To receive a canonical string representation ala
|
||||
// m / purpose' / coinType' / account' / change / addressIndex
|
||||
// call String() on a BIP44Params instance.
|
||||
type BIP44Params struct {
|
||||
Purpose uint32 `json:"purpose"`
|
||||
CoinType uint32 `json:"coinType"`
|
||||
Account uint32 `json:"account"`
|
||||
Change bool `json:"change"`
|
||||
AddressIndex uint32 `json:"addressIndex"`
|
||||
}
|
||||
|
||||
// NewParams creates a BIP 44 parameter object from the params:
|
||||
// m / purpose' / coinType' / account' / change / addressIndex
|
||||
func NewParams(purpose, coinType, account uint32, change bool, addressIdx uint32) *BIP44Params {
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
bip39 "github.com/cosmos/go-bip39"
|
||||
"github.com/cosmos/go-bip39"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
|
@ -12,10 +12,10 @@ func init() {
|
|||
|
||||
// RegisterLegacyAminoCodec registers concrete types and interfaces on the given codec.
|
||||
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
|
||||
cdc.RegisterInterface((*Info)(nil), nil)
|
||||
cdc.RegisterInterface((*LegacyInfo)(nil), nil)
|
||||
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.RegisterConcrete(legacyLocalInfo{}, "crypto/keys/localInfo", nil)
|
||||
cdc.RegisterConcrete(legacyLedgerInfo{}, "crypto/keys/ledgerInfo", nil)
|
||||
cdc.RegisterConcrete(legacyOfflineInfo{}, "crypto/keys/offlineInfo", nil)
|
||||
cdc.RegisterConcrete(LegacyMultiInfo{}, "crypto/keys/multiInfo", nil)
|
||||
}
|
||||
|
|
|
@ -12,13 +12,13 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/99designs/keyring"
|
||||
bip39 "github.com/cosmos/go-bip39"
|
||||
"github.com/cosmos/go-bip39"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tendermint/crypto/bcrypt"
|
||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/input"
|
||||
"github.com/cosmos/cosmos-sdk/codec/legacy"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/ledger"
|
||||
|
@ -54,14 +54,14 @@ var (
|
|||
// Keyring exposes operations over a backend supported by github.com/99designs/keyring.
|
||||
type Keyring interface {
|
||||
// List all keys.
|
||||
List() ([]Info, error)
|
||||
List() ([]*Record, error)
|
||||
|
||||
// Supported signing algorithms for Keyring and Ledger respectively.
|
||||
SupportedAlgorithms() (SigningAlgoList, SigningAlgoList)
|
||||
|
||||
// Key and KeyByAddress return keys by uid and address respectively.
|
||||
Key(uid string) (Info, error)
|
||||
KeyByAddress(address sdk.Address) (Info, error)
|
||||
Key(uid string) (*Record, error)
|
||||
KeyByAddress(address sdk.Address) (*Record, error)
|
||||
|
||||
// Delete and DeleteByAddress remove keys from the keyring.
|
||||
Delete(uid string) error
|
||||
|
@ -76,25 +76,27 @@ type Keyring interface {
|
|||
// another key is already stored under the same name or address.
|
||||
//
|
||||
// A passphrase set to the empty string will set the passphrase to the DefaultBIP39Passphrase value.
|
||||
NewMnemonic(uid string, language Language, hdPath, bip39Passphrase string, algo SignatureAlgo) (Info, string, error)
|
||||
NewMnemonic(uid string, language Language, hdPath, bip39Passphrase string, algo SignatureAlgo) (*Record, string, error)
|
||||
|
||||
// NewAccount converts a mnemonic to a private key and BIP-39 HD Path and persists it.
|
||||
// It fails if there is an existing key Info with the same address.
|
||||
NewAccount(uid, mnemonic, bip39Passphrase, hdPath string, algo SignatureAlgo) (Info, error)
|
||||
NewAccount(uid, mnemonic, bip39Passphrase, hdPath string, algo SignatureAlgo) (*Record, error)
|
||||
|
||||
// SaveLedgerKey retrieves a public key reference from a Ledger device and persists it.
|
||||
SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coinType, account, index uint32) (Info, error)
|
||||
SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coinType, account, index uint32) (*Record, error)
|
||||
|
||||
// SavePubKey stores a public key and returns the persisted Info structure.
|
||||
SavePubKey(uid string, pubkey types.PubKey, algo hd.PubKeyType) (Info, error)
|
||||
// SaveOfflineKey stores a public key and returns the persisted Info structure.
|
||||
SaveOfflineKey(uid string, pubkey types.PubKey) (*Record, error)
|
||||
|
||||
// SaveMultisig stores and returns a new multsig (offline) key reference.
|
||||
SaveMultisig(uid string, pubkey types.PubKey) (Info, error)
|
||||
SaveMultisig(uid string, pubkey types.PubKey) (*Record, error)
|
||||
|
||||
Signer
|
||||
|
||||
Importer
|
||||
Exporter
|
||||
|
||||
Migrator
|
||||
}
|
||||
|
||||
// UnsafeKeyring exposes unsafe operations such as unsafe unarmored export in
|
||||
|
@ -122,11 +124,9 @@ type Importer interface {
|
|||
ImportPubKey(uid string, armor string) error
|
||||
}
|
||||
|
||||
// LegacyInfoImporter is implemented by key stores that support import of Info types.
|
||||
type LegacyInfoImporter interface {
|
||||
// ImportInfo import a keyring.Info into the current keyring.
|
||||
// It is used to migrate multisig, ledger, and public key Info structure.
|
||||
ImportInfo(oldInfo Info) error
|
||||
// Migrator is implemented by key stores and enables migration of keys from amino to proto
|
||||
type Migrator interface {
|
||||
MigrateAll() (bool, error)
|
||||
}
|
||||
|
||||
// Exporter is implemented by key stores that support export of public and private keys.
|
||||
|
@ -162,15 +162,15 @@ type Options struct {
|
|||
// NewInMemory creates a transient keyring useful for testing
|
||||
// purposes and on-the-fly key generation.
|
||||
// Keybase options can be applied when generating this new Keybase.
|
||||
func NewInMemory(opts ...Option) Keyring {
|
||||
return newKeystore(keyring.NewArrayKeyring(nil), opts...)
|
||||
func NewInMemory(cdc codec.Codec, opts ...Option) Keyring {
|
||||
return newKeystore(keyring.NewArrayKeyring(nil), cdc, opts...)
|
||||
}
|
||||
|
||||
// New creates a new instance of a keyring.
|
||||
// Keyring ptions can be applied when generating the new instance.
|
||||
// Available backends are "os", "file", "kwallet", "memory", "pass", "test".
|
||||
func New(
|
||||
appName, backend, rootDir string, userInput io.Reader, opts ...Option,
|
||||
appName, backend, rootDir string, userInput io.Reader, cdc codec.Codec, opts ...Option,
|
||||
) (Keyring, error) {
|
||||
var (
|
||||
db keyring.Keyring
|
||||
|
@ -179,7 +179,7 @@ func New(
|
|||
|
||||
switch backend {
|
||||
case BackendMemory:
|
||||
return NewInMemory(opts...), err
|
||||
return NewInMemory(cdc, opts...), err
|
||||
case BackendTest:
|
||||
db, err = keyring.Open(newTestBackendKeyringConfig(appName, rootDir))
|
||||
case BackendFile:
|
||||
|
@ -198,15 +198,16 @@ func New(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return newKeystore(db, opts...), nil
|
||||
return newKeystore(db, cdc, opts...), nil
|
||||
}
|
||||
|
||||
type keystore struct {
|
||||
db keyring.Keyring
|
||||
cdc codec.Codec
|
||||
options Options
|
||||
}
|
||||
|
||||
func newKeystore(kr keyring.Keyring, opts ...Option) keystore {
|
||||
func newKeystore(kr keyring.Keyring, cdc codec.Codec, opts ...Option) keystore {
|
||||
// Default options for keybase
|
||||
options := Options{
|
||||
SupportedAlgos: SigningAlgoList{hd.Secp256k1},
|
||||
|
@ -217,95 +218,84 @@ func newKeystore(kr keyring.Keyring, opts ...Option) keystore {
|
|||
optionFn(&options)
|
||||
}
|
||||
|
||||
return keystore{kr, options}
|
||||
return keystore{kr, cdc, options}
|
||||
}
|
||||
|
||||
func (ks keystore) ExportPubKeyArmor(uid string) (string, error) {
|
||||
bz, err := ks.Key(uid)
|
||||
k, err := ks.Key(uid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if bz == nil {
|
||||
return "", fmt.Errorf("no key to export with name: %s", uid)
|
||||
key, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return crypto.ArmorPubKeyBytes(legacy.Cdc.MustMarshal(bz.GetPubKey()), string(bz.GetAlgo())), nil
|
||||
bz, err := ks.cdc.MarshalInterface(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return crypto.ArmorPubKeyBytes(bz, key.Type()), nil
|
||||
}
|
||||
|
||||
func (ks keystore) ExportPubKeyArmorByAddress(address sdk.Address) (string, error) {
|
||||
info, err := ks.KeyByAddress(address)
|
||||
k, err := ks.KeyByAddress(address)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ks.ExportPubKeyArmor(info.GetName())
|
||||
return ks.ExportPubKeyArmor(k.Name)
|
||||
}
|
||||
|
||||
// ExportPrivKeyArmor exports encrypted privKey
|
||||
func (ks keystore) ExportPrivKeyArmor(uid, encryptPassphrase string) (armor string, err error) {
|
||||
priv, err := ks.ExportPrivateKeyObject(uid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
info, err := ks.Key(uid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return crypto.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil
|
||||
return crypto.EncryptArmorPrivKey(priv, encryptPassphrase, priv.Type()), nil
|
||||
}
|
||||
|
||||
// ExportPrivateKeyObject exports an armored private key object.
|
||||
func (ks keystore) ExportPrivateKeyObject(uid string) (types.PrivKey, error) {
|
||||
info, err := ks.Key(uid)
|
||||
k, err := ks.Key(uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var priv types.PrivKey
|
||||
|
||||
switch linfo := info.(type) {
|
||||
case localInfo:
|
||||
if linfo.PrivKeyArmor == "" {
|
||||
err = fmt.Errorf("private key not available")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
priv, err = legacy.PrivKeyFromBytes([]byte(linfo.PrivKeyArmor))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case ledgerInfo, offlineInfo, multiInfo:
|
||||
return nil, errors.New("only works on local private keys")
|
||||
priv, err := extractPrivKeyFromRecord(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return priv, nil
|
||||
return priv, err
|
||||
}
|
||||
|
||||
func (ks keystore) ExportPrivKeyArmorByAddress(address sdk.Address, encryptPassphrase string) (armor string, err error) {
|
||||
byAddress, err := ks.KeyByAddress(address)
|
||||
k, err := ks.KeyByAddress(address)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ks.ExportPrivKeyArmor(byAddress.GetName(), encryptPassphrase)
|
||||
return ks.ExportPrivKeyArmor(k.Name, encryptPassphrase)
|
||||
}
|
||||
|
||||
func (ks keystore) ImportPrivKey(uid, armor, passphrase string) error {
|
||||
if k, err := ks.Key(uid); err == nil {
|
||||
if uid == k.GetName() {
|
||||
if uid == k.Name {
|
||||
return fmt.Errorf("cannot overwrite key: %s", uid)
|
||||
}
|
||||
}
|
||||
|
||||
privKey, algo, err := crypto.UnarmorDecryptPrivKey(armor, passphrase)
|
||||
privKey, _, err := crypto.UnarmorDecryptPrivKey(armor, passphrase)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to decrypt private key")
|
||||
}
|
||||
|
||||
_, err = ks.writeLocalKey(uid, privKey, hd.PubKeyType(algo))
|
||||
_, err = ks.writeLocalKey(uid, privKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -318,17 +308,17 @@ func (ks keystore) ImportPubKey(uid string, armor string) error {
|
|||
return fmt.Errorf("cannot overwrite key: %s", uid)
|
||||
}
|
||||
|
||||
pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armor)
|
||||
pubBytes, _, err := crypto.UnarmorPubKeyBytes(armor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pubKey, err := legacy.PubKeyFromBytes(pubBytes)
|
||||
if err != nil {
|
||||
var pubKey types.PubKey
|
||||
if err := ks.cdc.UnmarshalInterface(pubBytes, &pubKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = ks.writeOfflineKey(uid, pubKey, hd.PubKeyType(algo))
|
||||
_, err = ks.writeOfflineKey(uid, pubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -336,59 +326,51 @@ func (ks keystore) ImportPubKey(uid string, armor string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ImportInfo implements Importer.MigrateInfo.
|
||||
func (ks keystore) ImportInfo(oldInfo Info) error {
|
||||
if _, err := ks.Key(oldInfo.GetName()); err == nil {
|
||||
return fmt.Errorf("cannot overwrite key: %s", oldInfo.GetName())
|
||||
}
|
||||
|
||||
return ks.writeInfo(oldInfo)
|
||||
}
|
||||
|
||||
func (ks keystore) Sign(uid string, msg []byte) ([]byte, types.PubKey, error) {
|
||||
info, err := ks.Key(uid)
|
||||
k, err := ks.Key(uid)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var priv types.PrivKey
|
||||
|
||||
switch i := info.(type) {
|
||||
case localInfo:
|
||||
if i.PrivKeyArmor == "" {
|
||||
return nil, nil, fmt.Errorf("private key not available")
|
||||
}
|
||||
|
||||
priv, err = legacy.PrivKeyFromBytes([]byte(i.PrivKeyArmor))
|
||||
switch {
|
||||
case k.GetLocal() != nil:
|
||||
priv, err := extractPrivKeyFromLocal(k.GetLocal())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
case ledgerInfo:
|
||||
return SignWithLedger(info, msg)
|
||||
sig, err := priv.Sign(msg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
case offlineInfo, multiInfo:
|
||||
return nil, info.GetPubKey(), errors.New("cannot sign with offline keys")
|
||||
return sig, priv.PubKey(), nil
|
||||
|
||||
case k.GetLedger() != nil:
|
||||
return SignWithLedger(k, msg)
|
||||
|
||||
// multi or offline record
|
||||
default:
|
||||
pub, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return nil, pub, errors.New("cannot sign with offline keys")
|
||||
}
|
||||
|
||||
sig, err := priv.Sign(msg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return sig, priv.PubKey(), nil
|
||||
}
|
||||
|
||||
func (ks keystore) SignByAddress(address sdk.Address, msg []byte) ([]byte, types.PubKey, error) {
|
||||
key, err := ks.KeyByAddress(address)
|
||||
k, err := ks.KeyByAddress(address)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return ks.Sign(key.GetName(), msg)
|
||||
return ks.Sign(k.Name, msg)
|
||||
}
|
||||
|
||||
func (ks keystore) SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coinType, account, index uint32) (Info, error) {
|
||||
func (ks keystore) SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coinType, account, index uint32) (*Record, error) {
|
||||
|
||||
if !ks.options.SupportedAlgosLedger.Contains(algo) {
|
||||
return nil, fmt.Errorf(
|
||||
"%w: signature algo %s is not defined in the keyring options",
|
||||
|
@ -403,33 +385,33 @@ func (ks keystore) SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coi
|
|||
return nil, fmt.Errorf("failed to generate ledger key: %w", err)
|
||||
}
|
||||
|
||||
return ks.writeLedgerKey(uid, priv.PubKey(), *hdPath, algo.Name())
|
||||
return ks.writeLedgerKey(uid, priv.PubKey(), hdPath)
|
||||
}
|
||||
|
||||
func (ks keystore) writeLedgerKey(name string, pub types.PubKey, path hd.BIP44Params, algo hd.PubKeyType) (Info, error) {
|
||||
info := newLedgerInfo(name, pub, path, algo)
|
||||
if err := ks.writeInfo(info); err != nil {
|
||||
func (ks keystore) writeLedgerKey(name string, pk types.PubKey, path *hd.BIP44Params) (*Record, error) {
|
||||
k, err := NewLedgerRecord(name, pk, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
return k, ks.writeRecord(k)
|
||||
}
|
||||
|
||||
func (ks keystore) SaveMultisig(uid string, pubkey types.PubKey) (Info, error) {
|
||||
func (ks keystore) SaveMultisig(uid string, pubkey types.PubKey) (*Record, error) {
|
||||
return ks.writeMultisigKey(uid, pubkey)
|
||||
}
|
||||
|
||||
func (ks keystore) SavePubKey(uid string, pubkey types.PubKey, algo hd.PubKeyType) (Info, error) {
|
||||
return ks.writeOfflineKey(uid, pubkey, algo)
|
||||
func (ks keystore) SaveOfflineKey(uid string, pubkey types.PubKey) (*Record, error) {
|
||||
return ks.writeOfflineKey(uid, pubkey)
|
||||
}
|
||||
|
||||
func (ks keystore) DeleteByAddress(address sdk.Address) error {
|
||||
info, err := ks.KeyByAddress(address)
|
||||
k, err := ks.KeyByAddress(address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ks.Delete(info.GetName())
|
||||
err = ks.Delete(k.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -448,13 +430,11 @@ func (ks keystore) Rename(oldName, newName string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
err = ks.ImportPrivKey(newName, armor, passPhrase)
|
||||
if err != nil {
|
||||
if err := ks.Delete(oldName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ks.Delete(oldName)
|
||||
if err != nil {
|
||||
if err := ks.ImportPrivKey(newName, armor, passPhrase); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -462,17 +442,22 @@ func (ks keystore) Rename(oldName, newName string) error {
|
|||
}
|
||||
|
||||
func (ks keystore) Delete(uid string) error {
|
||||
info, err := ks.Key(uid)
|
||||
k, err := ks.Key(uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ks.db.Remove(addrHexKeyAsString(info.GetAddress()))
|
||||
addr, err := k.GetAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ks.db.Remove(infoKey(uid))
|
||||
err = ks.db.Remove(addrHexKeyAsString(addr))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ks.db.Remove(uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -480,7 +465,7 @@ func (ks keystore) Delete(uid string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ks keystore) KeyByAddress(address sdk.Address) (Info, error) {
|
||||
func (ks keystore) KeyByAddress(address sdk.Address) (*Record, error) {
|
||||
ik, err := ks.db.Get(addrHexKeyAsString(address))
|
||||
if err != nil {
|
||||
return nil, wrapKeyNotFound(err, fmt.Sprint("key with address", address, "not found"))
|
||||
|
@ -489,7 +474,8 @@ func (ks keystore) KeyByAddress(address sdk.Address) (Info, error) {
|
|||
if len(ik.Data) == 0 {
|
||||
return nil, wrapKeyNotFound(err, fmt.Sprint("key with address", address, "not found"))
|
||||
}
|
||||
return ks.key(string(ik.Data))
|
||||
|
||||
return ks.Key(string(ik.Data))
|
||||
}
|
||||
|
||||
func wrapKeyNotFound(err error, msg string) error {
|
||||
|
@ -499,40 +485,44 @@ func wrapKeyNotFound(err error, msg string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (ks keystore) List() ([]Info, error) {
|
||||
var res []Info
|
||||
func (ks keystore) List() ([]*Record, error) {
|
||||
if _, err := ks.MigrateAll(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keys, err := ks.db.Keys()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res []*Record
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
if strings.HasSuffix(key, infoSuffix) {
|
||||
rawInfo, err := ks.db.Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(rawInfo.Data) == 0 {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, key)
|
||||
}
|
||||
|
||||
info, err := unmarshalInfo(rawInfo.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res = append(res, info)
|
||||
if strings.Contains(key, addressSuffix) {
|
||||
continue
|
||||
}
|
||||
|
||||
item, err := ks.db.Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(item.Data) == 0 {
|
||||
return nil, sdkerrors.ErrKeyNotFound.Wrap(key)
|
||||
}
|
||||
|
||||
k, err := ks.protoUnmarshalRecord(item.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res = append(res, k)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (ks keystore) NewMnemonic(uid string, language Language, hdPath, bip39Passphrase string, algo SignatureAlgo) (Info, string, error) {
|
||||
func (ks keystore) NewMnemonic(uid string, language Language, hdPath, bip39Passphrase string, algo SignatureAlgo) (*Record, string, error) {
|
||||
if language != English {
|
||||
return nil, "", ErrUnsupportedLanguage
|
||||
}
|
||||
|
@ -557,15 +547,15 @@ func (ks keystore) NewMnemonic(uid string, language Language, hdPath, bip39Passp
|
|||
bip39Passphrase = DefaultBIP39Passphrase
|
||||
}
|
||||
|
||||
info, err := ks.NewAccount(uid, mnemonic, bip39Passphrase, hdPath, algo)
|
||||
k, err := ks.NewAccount(uid, mnemonic, bip39Passphrase, hdPath, algo)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return info, mnemonic, nil
|
||||
return k, mnemonic, nil
|
||||
}
|
||||
|
||||
func (ks keystore) NewAccount(name string, mnemonic string, bip39Passphrase string, hdPath string, algo SignatureAlgo) (Info, error) {
|
||||
func (ks keystore) NewAccount(name string, mnemonic string, bip39Passphrase string, hdPath string, algo SignatureAlgo) (*Record, error) {
|
||||
if !ks.isSupportedSigningAlgo(algo) {
|
||||
return nil, ErrUnsupportedSigningAlgo
|
||||
}
|
||||
|
@ -582,29 +572,23 @@ func (ks keystore) NewAccount(name string, mnemonic string, bip39Passphrase stri
|
|||
// if found
|
||||
address := sdk.AccAddress(privKey.PubKey().Address())
|
||||
if _, err := ks.KeyByAddress(address); err == nil {
|
||||
return nil, fmt.Errorf("account with address %s already exists in keyring, delete the key first if you want to recreate it", address)
|
||||
return nil, errors.New("duplicated address created")
|
||||
}
|
||||
|
||||
return ks.writeLocalKey(name, privKey, algo.Name())
|
||||
return ks.writeLocalKey(name, privKey)
|
||||
}
|
||||
|
||||
func (ks keystore) isSupportedSigningAlgo(algo SignatureAlgo) bool {
|
||||
return ks.options.SupportedAlgos.Contains(algo)
|
||||
}
|
||||
|
||||
func (ks keystore) key(infoKey string) (Info, error) {
|
||||
bs, err := ks.db.Get(infoKey)
|
||||
func (ks keystore) Key(uid string) (*Record, error) {
|
||||
k, _, err := ks.migrate(uid)
|
||||
if err != nil {
|
||||
return nil, wrapKeyNotFound(err, infoKey)
|
||||
return nil, err
|
||||
}
|
||||
if len(bs.Data) == 0 {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, infoKey)
|
||||
}
|
||||
return unmarshalInfo(bs.Data)
|
||||
}
|
||||
|
||||
func (ks keystore) Key(uid string) (Info, error) {
|
||||
return ks.key(infoKey(uid))
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// SupportedAlgorithms returns the keystore Options' supported signing algorithm.
|
||||
|
@ -616,17 +600,13 @@ func (ks keystore) SupportedAlgorithms() (SigningAlgoList, SigningAlgoList) {
|
|||
// SignWithLedger signs a binary message with the ledger device referenced by an Info object
|
||||
// and returns the signed bytes and the public key. It returns an error if the device could
|
||||
// not be queried or it returned an error.
|
||||
func SignWithLedger(info Info, msg []byte) (sig []byte, pub types.PubKey, err error) {
|
||||
switch info.(type) {
|
||||
case *ledgerInfo, ledgerInfo:
|
||||
default:
|
||||
func SignWithLedger(k *Record, msg []byte) (sig []byte, pub types.PubKey, err error) {
|
||||
ledgerInfo := k.GetLedger()
|
||||
if ledgerInfo == nil {
|
||||
return nil, nil, errors.New("not a ledger object")
|
||||
}
|
||||
|
||||
path, err := info.GetPath()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
path := ledgerInfo.GetPath()
|
||||
|
||||
priv, err := ledger.NewPrivKeySecp256k1Unsafe(*path)
|
||||
if err != nil {
|
||||
|
@ -775,65 +755,70 @@ func newRealPrompt(dir string, buf io.Reader) func(string) (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (ks keystore) writeLocalKey(name string, priv types.PrivKey, algo hd.PubKeyType) (Info, error) {
|
||||
// encrypt private key using keyring
|
||||
pub := priv.PubKey()
|
||||
info := newLocalInfo(name, pub, string(legacy.Cdc.MustMarshal(priv)), algo)
|
||||
if err := ks.writeInfo(info); err != nil {
|
||||
func (ks keystore) writeLocalKey(name string, privKey types.PrivKey) (*Record, error) {
|
||||
k, err := NewLocalRecord(name, privKey, privKey.PubKey())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
return k, ks.writeRecord(k)
|
||||
}
|
||||
|
||||
func (ks keystore) writeInfo(info Info) error {
|
||||
key := infoKeyBz(info.GetName())
|
||||
serializedInfo := marshalInfo(info)
|
||||
// writeRecord persists a keyring item in keystore if it does not exist there
|
||||
func (ks keystore) writeRecord(k *Record) error {
|
||||
addr, err := k.GetAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := ks.existsInDb(info)
|
||||
key := k.Name
|
||||
|
||||
exists, err := ks.existsInDb(addr, key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return errors.New("public key already exists in keybase")
|
||||
return fmt.Errorf("public key %s already exists in keybase", key)
|
||||
}
|
||||
|
||||
err = ks.db.Set(keyring.Item{
|
||||
Key: string(key),
|
||||
Data: serializedInfo,
|
||||
})
|
||||
serializedRecord, err := ks.cdc.Marshal(k)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to serialize record, err - %s", err)
|
||||
}
|
||||
|
||||
item := keyring.Item{
|
||||
Key: key,
|
||||
Data: serializedRecord,
|
||||
}
|
||||
|
||||
if err := ks.SetItem(item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ks.db.Set(keyring.Item{
|
||||
Key: addrHexKeyAsString(info.GetAddress()),
|
||||
Data: key,
|
||||
})
|
||||
if err != nil {
|
||||
item = keyring.Item{
|
||||
Key: addrHexKeyAsString(addr),
|
||||
Data: []byte(key),
|
||||
}
|
||||
|
||||
if err := ks.SetItem(item); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// existsInDb returns true if key is in DB. Error is returned only when we have error
|
||||
// different than ErrKeyNotFound
|
||||
func (ks keystore) existsInDb(info Info) (bool, error) {
|
||||
if item, err := ks.db.Get(addrHexKeyAsString(info.GetAddress())); err == nil {
|
||||
if item.Key == info.GetName() {
|
||||
return true, nil // address lookup succeeds - info exists
|
||||
}
|
||||
return false, nil
|
||||
// existsInDb returns (true, nil) if either addr or name exist is in keystore DB.
|
||||
// On the other hand, it returns (false, error) if Get method returns error different from keyring.ErrKeyNotFound
|
||||
func (ks keystore) existsInDb(addr sdk.Address, name string) (bool, error) {
|
||||
|
||||
if _, err := ks.db.Get(addrHexKeyAsString(addr)); err == nil {
|
||||
return true, nil // address lookup succeeds - info exists
|
||||
} else if err != keyring.ErrKeyNotFound {
|
||||
return false, err // received unexpected error - returns error
|
||||
}
|
||||
|
||||
if item, err := ks.db.Get(infoKey(info.GetName())); err == nil {
|
||||
if item.Key == info.GetName() {
|
||||
return true, nil // uid lookup succeeds - info exists
|
||||
}
|
||||
return false, nil
|
||||
if _, err := ks.db.Get(name); err == nil {
|
||||
return true, nil // uid lookup succeeds - info exists
|
||||
} else if err != keyring.ErrKeyNotFound {
|
||||
return false, err // received unexpected error - returns
|
||||
}
|
||||
|
@ -842,26 +827,145 @@ func (ks keystore) existsInDb(info Info) (bool, error) {
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func (ks keystore) writeOfflineKey(name string, pub types.PubKey, algo hd.PubKeyType) (Info, error) {
|
||||
info := newOfflineInfo(name, pub, algo)
|
||||
err := ks.writeInfo(info)
|
||||
func (ks keystore) writeOfflineKey(name string, pk types.PubKey) (*Record, error) {
|
||||
k, err := NewOfflineRecord(name, pk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
return k, ks.writeRecord(k)
|
||||
}
|
||||
|
||||
func (ks keystore) writeMultisigKey(name string, pub types.PubKey) (Info, error) {
|
||||
info, err := NewMultiInfo(name, pub)
|
||||
// writeMultisigKey investigate where thisf function is called maybe remove it
|
||||
func (ks keystore) writeMultisigKey(name string, pk types.PubKey) (*Record, error) {
|
||||
k, err := NewMultiRecord(name, pk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = ks.writeInfo(info); err != nil {
|
||||
|
||||
return k, ks.writeRecord(k)
|
||||
}
|
||||
|
||||
func (ks keystore) MigrateAll() (bool, error) {
|
||||
keys, err := ks.db.Keys()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(keys) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var migrated bool
|
||||
for _, key := range keys {
|
||||
if strings.Contains(key, addressSuffix) {
|
||||
continue
|
||||
}
|
||||
|
||||
_, migrated2, err := ks.migrate(key)
|
||||
if err != nil {
|
||||
fmt.Printf("migrate err: %q", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if migrated2 {
|
||||
migrated = true
|
||||
}
|
||||
}
|
||||
|
||||
return migrated, nil
|
||||
}
|
||||
|
||||
// migrate converts keyring.Item from amino to proto serialization format.
|
||||
func (ks keystore) migrate(key string) (*Record, bool, error) {
|
||||
item, err := ks.db.Get(key)
|
||||
if err != nil {
|
||||
return nil, false, wrapKeyNotFound(err, key)
|
||||
}
|
||||
|
||||
if len(item.Data) == 0 {
|
||||
return nil, false, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, key)
|
||||
}
|
||||
|
||||
// 2.try to deserialize using proto, if good then continue, otherwise try to deserialize using amino
|
||||
k, err := ks.protoUnmarshalRecord(item.Data)
|
||||
if err == nil {
|
||||
return k, false, nil
|
||||
}
|
||||
|
||||
LegacyInfo, err := unMarshalLegacyInfo(item.Data)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("unable to unmarshal item.Data, err: %w", err)
|
||||
}
|
||||
|
||||
// 4.serialize info using proto
|
||||
k, err = ks.convertFromLegacyInfo(LegacyInfo)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("convertFromLegacyInfo, err: %w", err)
|
||||
}
|
||||
|
||||
serializedRecord, err := ks.cdc.Marshal(k)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("unable to serialize record, err: %w", err)
|
||||
}
|
||||
|
||||
item = keyring.Item{
|
||||
Key: key,
|
||||
Data: serializedRecord,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
// 5.overwrite the keyring entry with
|
||||
if err := ks.SetItem(item); err != nil {
|
||||
return nil, false, fmt.Errorf("unable to set keyring.Item, err: %w", err)
|
||||
}
|
||||
|
||||
return k, true, nil
|
||||
}
|
||||
|
||||
func (ks keystore) protoUnmarshalRecord(bz []byte) (*Record, error) {
|
||||
k := new(Record)
|
||||
if err := ks.cdc.Unmarshal(bz, k); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func (ks keystore) SetItem(item keyring.Item) error {
|
||||
return ks.db.Set(item)
|
||||
}
|
||||
|
||||
func (ks keystore) convertFromLegacyInfo(info LegacyInfo) (*Record, error) {
|
||||
if info == nil {
|
||||
return nil, errors.New("unable to convert LegacyInfo to Record cause info is nil")
|
||||
}
|
||||
|
||||
name := info.GetName()
|
||||
pk := info.GetPubKey()
|
||||
|
||||
switch info.GetType() {
|
||||
case TypeLocal:
|
||||
priv, err := privKeyFromLegacyInfo(info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewLocalRecord(name, priv, pk)
|
||||
case TypeOffline:
|
||||
return NewOfflineRecord(name, pk)
|
||||
case TypeMulti:
|
||||
return NewMultiRecord(name, pk)
|
||||
case TypeLedger:
|
||||
path, err := info.GetPath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewLedgerRecord(name, pk, path)
|
||||
default:
|
||||
return nil, errors.New("unknown LegacyInfo type")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
type unsafeKeystore struct {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
//+build ledger test_ledger_mock
|
||||
//go:build ledger || test_ledger_mock
|
||||
// +build ledger test_ledger_mock
|
||||
|
||||
package keyring
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -13,34 +15,37 @@ import (
|
|||
)
|
||||
|
||||
func TestInMemoryCreateLedger(t *testing.T) {
|
||||
kb := NewInMemory()
|
||||
cdc := getCodec()
|
||||
kb := NewInMemory(cdc)
|
||||
|
||||
ledger, err := kb.SaveLedgerKey("some_account", hd.Secp256k1, "cosmos", 118, 3, 1)
|
||||
k, err := kb.SaveLedgerKey("some_account", hd.Secp256k1, "cosmos", 118, 3, 1)
|
||||
|
||||
if err != nil {
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error())
|
||||
require.Nil(t, ledger)
|
||||
require.Nil(t, k)
|
||||
t.Skip("ledger nano S: support for ledger devices is not available in this executable")
|
||||
return
|
||||
}
|
||||
|
||||
// The mock is available, check that the address is correct
|
||||
pubKey := ledger.GetPubKey()
|
||||
pubKey, err := k.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
expectedPkStr := "PubKeySecp256k1{03602C0CB4D8C0081FEE794BDE96E7B95FA16F2B5283B764AC070584327B2C7202}"
|
||||
require.Equal(t, expectedPkStr, pubKey.String())
|
||||
|
||||
// Check that restoring the key gets the same results
|
||||
restoredKey, err := kb.Key("some_account")
|
||||
restoredRecord, err := kb.Key("some_account")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, restoredRecord)
|
||||
require.Equal(t, "some_account", restoredRecord.Name)
|
||||
pubKey, err = restoredRecord.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, restoredKey)
|
||||
require.Equal(t, "some_account", restoredKey.GetName())
|
||||
require.Equal(t, TypeLedger, restoredKey.GetType())
|
||||
pubKey = restoredKey.GetPubKey()
|
||||
require.Equal(t, expectedPkStr, pubKey.String())
|
||||
|
||||
path, err := restoredKey.GetPath()
|
||||
require.NoError(t, err)
|
||||
ledgerInfo := restoredRecord.GetLedger()
|
||||
require.NotNil(t, ledgerInfo)
|
||||
path := ledgerInfo.GetPath()
|
||||
require.Equal(t, "m/44'/118'/3'/0/1", path.String())
|
||||
}
|
||||
|
||||
|
@ -48,53 +53,58 @@ func TestInMemoryCreateLedger(t *testing.T) {
|
|||
// signatures
|
||||
func TestSignVerifyKeyRingWithLedger(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
cdc := getCodec()
|
||||
|
||||
kb, err := New("keybasename", "test", dir, nil)
|
||||
kb, err := New("keybasename", "test", dir, nil, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
i1, err := kb.SaveLedgerKey("key", hd.Secp256k1, "cosmos", 118, 0, 0)
|
||||
k, err := kb.SaveLedgerKey("key", hd.Secp256k1, "cosmos", 118, 0, 0)
|
||||
if err != nil {
|
||||
require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error())
|
||||
t.Skip("ledger nano S: support for ledger devices is not available in this executable")
|
||||
return
|
||||
}
|
||||
require.Equal(t, "key", i1.GetName())
|
||||
require.Equal(t, "key", k.Name)
|
||||
|
||||
d1 := []byte("my first message")
|
||||
s1, pub1, err := kb.Sign("key", d1)
|
||||
require.NoError(t, err)
|
||||
|
||||
s2, pub2, err := SignWithLedger(i1, d1)
|
||||
s2, pub2, err := SignWithLedger(k, d1)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, pub1.Equals(pub2))
|
||||
require.True(t, bytes.Equal(s1, s2))
|
||||
|
||||
require.Equal(t, i1.GetPubKey(), pub1)
|
||||
require.Equal(t, i1.GetPubKey(), pub2)
|
||||
key1, err := k.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, key1, pub1)
|
||||
require.Equal(t, key1, pub2)
|
||||
require.True(t, pub1.VerifySignature(d1, s1))
|
||||
require.True(t, i1.GetPubKey().VerifySignature(d1, s1))
|
||||
require.True(t, key1.VerifySignature(d1, s1))
|
||||
require.True(t, bytes.Equal(s1, s2))
|
||||
|
||||
localInfo, _, err := kb.NewMnemonic("test", English, types.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
k, _, err = kb.NewMnemonic("test", English, types.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
require.NoError(t, err)
|
||||
_, _, err = SignWithLedger(localInfo, d1)
|
||||
_, _, err = SignWithLedger(k, d1)
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "not a ledger object", err.Error())
|
||||
}
|
||||
|
||||
func TestAltKeyring_SaveLedgerKey(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
cdc := getCodec()
|
||||
|
||||
keyring, err := New(t.Name(), BackendTest, dir, nil)
|
||||
kr, err := New(t.Name(), BackendTest, dir, nil, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test unsupported Algo
|
||||
_, err = keyring.SaveLedgerKey("key", notSupportedAlgo{}, "cosmos", 118, 0, 0)
|
||||
_, err = kr.SaveLedgerKey("key", notSupportedAlgo{}, "cosmos", 118, 0, 0)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), ErrUnsupportedSigningAlgo.Error())
|
||||
require.True(t, strings.Contains(err.Error(), ErrUnsupportedSigningAlgo.Error()))
|
||||
|
||||
ledger, err := keyring.SaveLedgerKey("some_account", hd.Secp256k1, "cosmos", 118, 3, 1)
|
||||
k, err := kr.SaveLedgerKey("some_account", hd.Secp256k1, "cosmos", 118, 3, 1)
|
||||
if err != nil {
|
||||
require.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error())
|
||||
t.Skip("ledger nano S: support for ledger devices is not available in this executable")
|
||||
|
@ -102,21 +112,25 @@ func TestAltKeyring_SaveLedgerKey(t *testing.T) {
|
|||
}
|
||||
|
||||
// The mock is available, check that the address is correct
|
||||
require.Equal(t, "some_account", ledger.GetName())
|
||||
pubKey := ledger.GetPubKey()
|
||||
require.Equal(t, "some_account", k.Name)
|
||||
pubKey, err := k.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
expectedPkStr := "PubKeySecp256k1{03602C0CB4D8C0081FEE794BDE96E7B95FA16F2B5283B764AC070584327B2C7202}"
|
||||
require.Equal(t, expectedPkStr, pubKey.String())
|
||||
|
||||
// Check that restoring the key gets the same results
|
||||
restoredKey, err := keyring.Key("some_account")
|
||||
restoredRecord, err := kr.Key("some_account")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, restoredRecord)
|
||||
require.Equal(t, "some_account", restoredRecord.Name)
|
||||
// require.Equal(t, TypeLedger, restoredRecord.GetType())
|
||||
pubKey, err = restoredRecord.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, restoredKey)
|
||||
require.Equal(t, "some_account", restoredKey.GetName())
|
||||
require.Equal(t, TypeLedger, restoredKey.GetType())
|
||||
pubKey = restoredKey.GetPubKey()
|
||||
require.Equal(t, expectedPkStr, pubKey.String())
|
||||
|
||||
path, err := restoredKey.GetPath()
|
||||
require.NoError(t, err)
|
||||
ledgerInfo := k.GetLedger()
|
||||
require.NotNil(t, ledgerInfo)
|
||||
|
||||
path := ledgerInfo.GetPath()
|
||||
require.Equal(t, "m/44'/118'/3'/0/1", path.String())
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,192 +0,0 @@
|
|||
package keyring
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// LegacyKeybase is implemented by the legacy keybase implementation.
|
||||
type LegacyKeybase interface {
|
||||
List() ([]Info, error)
|
||||
Export(name string) (armor string, err error)
|
||||
ExportPrivKey(name, decryptPassphrase, encryptPassphrase string) (armor string, err error)
|
||||
ExportPubKey(name string) (armor string, err error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
// NewLegacy creates a new instance of a legacy keybase.
|
||||
func NewLegacy(name, dir string, opts ...KeybaseOption) (LegacyKeybase, error) {
|
||||
if err := tmos.EnsureDir(dir, 0700); err != nil {
|
||||
return nil, fmt.Errorf("failed to create Keybase directory: %s", err)
|
||||
}
|
||||
|
||||
db, err := sdk.NewLevelDB(name, dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newDBKeybase(db), nil
|
||||
}
|
||||
|
||||
var _ LegacyKeybase = dbKeybase{}
|
||||
|
||||
// dbKeybase combines encryption and storage implementation to provide a
|
||||
// full-featured key manager.
|
||||
//
|
||||
// Deprecated: dbKeybase will be removed in favor of keyringKeybase.
|
||||
type dbKeybase struct {
|
||||
db dbm.DB
|
||||
}
|
||||
|
||||
// newDBKeybase creates a new dbKeybase instance using the provided DB for
|
||||
// reading and writing keys.
|
||||
func newDBKeybase(db dbm.DB) dbKeybase {
|
||||
return dbKeybase{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns the keys from storage in alphabetical order.
|
||||
func (kb dbKeybase) List() ([]Info, error) {
|
||||
var res []Info
|
||||
|
||||
iter, err := kb.db.Iterator(nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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 := unmarshalInfo(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) (Info, error) {
|
||||
bs, err := kb.db.Get(infoKeyBz(name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(bs) == 0 {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, name)
|
||||
}
|
||||
|
||||
return unmarshalInfo(bs)
|
||||
}
|
||||
|
||||
// ExportPrivateKeyObject returns a PrivKey object given the key name and
|
||||
// passphrase. An error is returned if the key does not exist or if the Info for
|
||||
// the key is invalid.
|
||||
func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (types.PrivKey, error) {
|
||||
info, err := kb.Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var priv types.PrivKey
|
||||
|
||||
switch i := info.(type) {
|
||||
case localInfo:
|
||||
linfo := i
|
||||
if linfo.PrivKeyArmor == "" {
|
||||
err = fmt.Errorf("private key not available")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
priv, _, err = crypto.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case ledgerInfo, offlineInfo, multiInfo:
|
||||
return nil, errors.New("only works on local private keys")
|
||||
}
|
||||
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
func (kb dbKeybase) Export(name string) (armor string, err error) {
|
||||
bz, err := kb.db.Get(infoKeyBz(name))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if bz == nil {
|
||||
return "", fmt.Errorf("no key to export with name %s", name)
|
||||
}
|
||||
|
||||
return crypto.ArmorInfoBytes(bz), nil
|
||||
}
|
||||
|
||||
// ExportPubKey returns public keys in ASCII armored format. It retrieves 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, err := kb.db.Get(infoKeyBz(name))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if bz == nil {
|
||||
return "", fmt.Errorf("no key to export with name %s", name)
|
||||
}
|
||||
|
||||
info, err := unmarshalInfo(bz)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return crypto.ArmorPubKeyBytes(info.GetPubKey().Bytes(), string(info.GetAlgo())), 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
|
||||
}
|
||||
|
||||
info, err := kb.Get(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return crypto.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil
|
||||
}
|
||||
|
||||
// Close the underlying storage.
|
||||
func (kb dbKeybase) Close() error { return kb.db.Close() }
|
||||
|
||||
func infoKey(name string) string { return fmt.Sprintf("%s.%s", name, infoSuffix) }
|
||||
func infoKeyBz(name string) []byte { return []byte(infoKey(name)) }
|
||||
|
||||
// KeybaseOption overrides options for the db.
|
||||
type KeybaseOption func(*kbOptions)
|
||||
|
||||
type kbOptions struct {
|
||||
}
|
|
@ -8,11 +8,11 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Info is the publicly exposed information about a keypair
|
||||
type Info interface {
|
||||
// Deprecated: LegacyInfo is the publicly exposed information about a keypair
|
||||
type LegacyInfo interface {
|
||||
// Human-readable type for key listing
|
||||
GetType() KeyType
|
||||
// Name of the key
|
||||
|
@ -20,7 +20,7 @@ type Info interface {
|
|||
// Public key
|
||||
GetPubKey() cryptotypes.PubKey
|
||||
// Address
|
||||
GetAddress() types.AccAddress
|
||||
GetAddress() sdk.AccAddress
|
||||
// Bip44 Path
|
||||
GetPath() (*hd.BIP44Params, error)
|
||||
// Algo
|
||||
|
@ -28,152 +28,131 @@ type Info interface {
|
|||
}
|
||||
|
||||
var (
|
||||
_ Info = &localInfo{}
|
||||
_ Info = &ledgerInfo{}
|
||||
_ Info = &offlineInfo{}
|
||||
_ Info = &multiInfo{}
|
||||
_ LegacyInfo = &legacyLocalInfo{}
|
||||
_ LegacyInfo = &legacyLedgerInfo{}
|
||||
_ LegacyInfo = &legacyOfflineInfo{}
|
||||
_ LegacyInfo = &LegacyMultiInfo{}
|
||||
)
|
||||
|
||||
// localInfo is the public information about a locally stored key
|
||||
// legacyLocalInfo is the public information about a locally stored key
|
||||
// Note: Algo must be last field in struct for backwards amino compatibility
|
||||
type localInfo struct {
|
||||
type legacyLocalInfo struct {
|
||||
Name string `json:"name"`
|
||||
PubKey cryptotypes.PubKey `json:"pubkey"`
|
||||
PrivKeyArmor string `json:"privkey.armor"`
|
||||
Algo hd.PubKeyType `json:"algo"`
|
||||
}
|
||||
|
||||
func newLocalInfo(name string, pub cryptotypes.PubKey, privArmor string, algo hd.PubKeyType) Info {
|
||||
return &localInfo{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
PrivKeyArmor: privArmor,
|
||||
Algo: algo,
|
||||
}
|
||||
}
|
||||
|
||||
// GetType implements Info interface
|
||||
func (i localInfo) GetType() KeyType {
|
||||
func (i legacyLocalInfo) GetType() KeyType {
|
||||
return TypeLocal
|
||||
}
|
||||
|
||||
// GetType implements Info interface
|
||||
func (i localInfo) GetName() string {
|
||||
func (i legacyLocalInfo) GetName() string {
|
||||
return i.Name
|
||||
}
|
||||
|
||||
// GetType implements Info interface
|
||||
func (i localInfo) GetPubKey() cryptotypes.PubKey {
|
||||
func (i legacyLocalInfo) GetPubKey() cryptotypes.PubKey {
|
||||
return i.PubKey
|
||||
}
|
||||
|
||||
// GetType implements Info interface
|
||||
func (i localInfo) GetAddress() types.AccAddress {
|
||||
func (i legacyLocalInfo) GetAddress() sdk.AccAddress {
|
||||
return i.PubKey.Address().Bytes()
|
||||
}
|
||||
|
||||
// GetPrivKeyArmor
|
||||
func (i legacyLocalInfo) GetPrivKeyArmor() string {
|
||||
return i.PrivKeyArmor
|
||||
}
|
||||
|
||||
// GetType implements Info interface
|
||||
func (i localInfo) GetAlgo() hd.PubKeyType {
|
||||
func (i legacyLocalInfo) GetAlgo() hd.PubKeyType {
|
||||
return i.Algo
|
||||
}
|
||||
|
||||
// GetType implements Info interface
|
||||
func (i localInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
func (i legacyLocalInfo) 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
|
||||
// legacyLedgerInfo is the public information about a Ledger key
|
||||
// Note: Algo must be last field in struct for backwards amino compatibility
|
||||
type ledgerInfo struct {
|
||||
type legacyLedgerInfo struct {
|
||||
Name string `json:"name"`
|
||||
PubKey cryptotypes.PubKey `json:"pubkey"`
|
||||
Path hd.BIP44Params `json:"path"`
|
||||
Algo hd.PubKeyType `json:"algo"`
|
||||
}
|
||||
|
||||
func newLedgerInfo(name string, pub cryptotypes.PubKey, path hd.BIP44Params, algo hd.PubKeyType) Info {
|
||||
return &ledgerInfo{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
Path: path,
|
||||
Algo: algo,
|
||||
}
|
||||
}
|
||||
|
||||
// GetType implements Info interface
|
||||
func (i ledgerInfo) GetType() KeyType {
|
||||
func (i legacyLedgerInfo) GetType() KeyType {
|
||||
return TypeLedger
|
||||
}
|
||||
|
||||
// GetName implements Info interface
|
||||
func (i ledgerInfo) GetName() string {
|
||||
func (i legacyLedgerInfo) GetName() string {
|
||||
return i.Name
|
||||
}
|
||||
|
||||
// GetPubKey implements Info interface
|
||||
func (i ledgerInfo) GetPubKey() cryptotypes.PubKey {
|
||||
func (i legacyLedgerInfo) GetPubKey() cryptotypes.PubKey {
|
||||
return i.PubKey
|
||||
}
|
||||
|
||||
// GetAddress implements Info interface
|
||||
func (i ledgerInfo) GetAddress() types.AccAddress {
|
||||
func (i legacyLedgerInfo) GetAddress() sdk.AccAddress {
|
||||
return i.PubKey.Address().Bytes()
|
||||
}
|
||||
|
||||
// GetPath implements Info interface
|
||||
func (i ledgerInfo) GetAlgo() hd.PubKeyType {
|
||||
func (i legacyLedgerInfo) GetAlgo() hd.PubKeyType {
|
||||
return i.Algo
|
||||
}
|
||||
|
||||
// GetPath implements Info interface
|
||||
func (i ledgerInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
func (i legacyLedgerInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
tmp := i.Path
|
||||
return &tmp, nil
|
||||
}
|
||||
|
||||
// offlineInfo is the public information about an offline key
|
||||
// legacyOfflineInfo is the public information about an offline key
|
||||
// Note: Algo must be last field in struct for backwards amino compatibility
|
||||
type offlineInfo struct {
|
||||
type legacyOfflineInfo struct {
|
||||
Name string `json:"name"`
|
||||
PubKey cryptotypes.PubKey `json:"pubkey"`
|
||||
Algo hd.PubKeyType `json:"algo"`
|
||||
}
|
||||
|
||||
func newOfflineInfo(name string, pub cryptotypes.PubKey, algo hd.PubKeyType) Info {
|
||||
return &offlineInfo{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
Algo: algo,
|
||||
}
|
||||
}
|
||||
|
||||
// GetType implements Info interface
|
||||
func (i offlineInfo) GetType() KeyType {
|
||||
func (i legacyOfflineInfo) GetType() KeyType {
|
||||
return TypeOffline
|
||||
}
|
||||
|
||||
// GetName implements Info interface
|
||||
func (i offlineInfo) GetName() string {
|
||||
func (i legacyOfflineInfo) GetName() string {
|
||||
return i.Name
|
||||
}
|
||||
|
||||
// GetPubKey implements Info interface
|
||||
func (i offlineInfo) GetPubKey() cryptotypes.PubKey {
|
||||
func (i legacyOfflineInfo) GetPubKey() cryptotypes.PubKey {
|
||||
return i.PubKey
|
||||
}
|
||||
|
||||
// GetAlgo returns the signing algorithm for the key
|
||||
func (i offlineInfo) GetAlgo() hd.PubKeyType {
|
||||
func (i legacyOfflineInfo) GetAlgo() hd.PubKeyType {
|
||||
return i.Algo
|
||||
}
|
||||
|
||||
// GetAddress implements Info interface
|
||||
func (i offlineInfo) GetAddress() types.AccAddress {
|
||||
func (i legacyOfflineInfo) GetAddress() sdk.AccAddress {
|
||||
return i.PubKey.Address().Bytes()
|
||||
}
|
||||
|
||||
// GetPath implements Info interface
|
||||
func (i offlineInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
func (i legacyOfflineInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
|
||||
}
|
||||
|
||||
|
@ -187,68 +166,68 @@ type multisigPubKeyInfo struct {
|
|||
}
|
||||
|
||||
// multiInfo is the public information about a multisig key
|
||||
type multiInfo struct {
|
||||
type LegacyMultiInfo struct {
|
||||
Name string `json:"name"`
|
||||
PubKey cryptotypes.PubKey `json:"pubkey"`
|
||||
Threshold uint `json:"threshold"`
|
||||
PubKeys []multisigPubKeyInfo `json:"pubkeys"`
|
||||
}
|
||||
|
||||
// NewMultiInfo creates a new multiInfo instance
|
||||
func NewMultiInfo(name string, pub cryptotypes.PubKey) (Info, error) {
|
||||
// NewLegacyMultiInfo creates a new legacyMultiInfo instance
|
||||
func NewLegacyMultiInfo(name string, pub cryptotypes.PubKey) (LegacyInfo, error) {
|
||||
if _, ok := pub.(*multisig.LegacyAminoPubKey); !ok {
|
||||
return nil, fmt.Errorf("MultiInfo supports only multisig.LegacyAminoPubKey, got %T", pub)
|
||||
}
|
||||
return &multiInfo{
|
||||
return &LegacyMultiInfo{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetType implements Info interface
|
||||
func (i multiInfo) GetType() KeyType {
|
||||
func (i LegacyMultiInfo) GetType() KeyType {
|
||||
return TypeMulti
|
||||
}
|
||||
|
||||
// GetName implements Info interface
|
||||
func (i multiInfo) GetName() string {
|
||||
func (i LegacyMultiInfo) GetName() string {
|
||||
return i.Name
|
||||
}
|
||||
|
||||
// GetPubKey implements Info interface
|
||||
func (i multiInfo) GetPubKey() cryptotypes.PubKey {
|
||||
func (i LegacyMultiInfo) GetPubKey() cryptotypes.PubKey {
|
||||
return i.PubKey
|
||||
}
|
||||
|
||||
// GetAddress implements Info interface
|
||||
func (i multiInfo) GetAddress() types.AccAddress {
|
||||
func (i LegacyMultiInfo) GetAddress() sdk.AccAddress {
|
||||
return i.PubKey.Address().Bytes()
|
||||
}
|
||||
|
||||
// GetPath implements Info interface
|
||||
func (i multiInfo) GetAlgo() hd.PubKeyType {
|
||||
func (i LegacyMultiInfo) GetAlgo() hd.PubKeyType {
|
||||
return hd.MultiType
|
||||
}
|
||||
|
||||
// GetPath implements Info interface
|
||||
func (i multiInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
func (i LegacyMultiInfo) GetPath() (*hd.BIP44Params, error) {
|
||||
return nil, fmt.Errorf("BIP44 Paths are not available for this type")
|
||||
}
|
||||
|
||||
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
|
||||
func (i multiInfo) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
|
||||
func (i LegacyMultiInfo) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
|
||||
multiPK := i.PubKey.(*multisig.LegacyAminoPubKey)
|
||||
|
||||
return codectypes.UnpackInterfaces(multiPK, unpacker)
|
||||
}
|
||||
|
||||
// encoding info
|
||||
func marshalInfo(i Info) []byte {
|
||||
func MarshalInfo(i LegacyInfo) []byte {
|
||||
return legacy.Cdc.MustMarshalLengthPrefixed(i)
|
||||
}
|
||||
|
||||
// decoding info
|
||||
func unmarshalInfo(bz []byte) (info Info, err error) {
|
||||
func unMarshalLegacyInfo(bz []byte) (info LegacyInfo, err error) {
|
||||
err = legacy.Cdc.UnmarshalLengthPrefixed(bz, &info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -261,9 +240,9 @@ func unmarshalInfo(bz []byte) (info Info, err error) {
|
|||
//
|
||||
// This is a workaround, as go cannot check that an interface (Info)
|
||||
// implements another interface (UnpackInterfacesMessage).
|
||||
_, ok := info.(multiInfo)
|
||||
_, ok := info.(LegacyMultiInfo)
|
||||
if ok {
|
||||
var multi multiInfo
|
||||
var multi LegacyMultiInfo
|
||||
err = legacy.Cdc.UnmarshalLengthPrefixed(bz, &multi)
|
||||
|
||||
return multi, err
|
||||
|
@ -271,3 +250,23 @@ func unmarshalInfo(bz []byte) (info Info, err error) {
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
// privKeyFromLegacyInfo exports a private key from LegacyInfo
|
||||
func privKeyFromLegacyInfo(info LegacyInfo) (cryptotypes.PrivKey, error) {
|
||||
|
||||
switch linfo := info.(type) {
|
||||
case legacyLocalInfo:
|
||||
if linfo.PrivKeyArmor == "" {
|
||||
return nil, fmt.Errorf("private key not available")
|
||||
}
|
||||
priv, err := legacy.PrivKeyFromBytes([]byte(linfo.PrivKeyArmor))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return priv, nil
|
||||
// case legacyLedgerInfo, legacyOfflineInfo, LegacyMultiInfo:
|
||||
default:
|
||||
return nil, fmt.Errorf("only works on local private keys, provided %s", linfo)
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package keyring_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/otiai10/copy"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
)
|
||||
|
||||
func TestNewLegacyKeyBase(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
kb, err := keyring.NewLegacy("keybasename", dir)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, kb.Close())
|
||||
}
|
||||
|
||||
func TestLegacyKeybase(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
// Backup testdata
|
||||
require.NoError(t, copy.Copy("testdata", dir))
|
||||
|
||||
kb, err := keyring.NewLegacy("keys", filepath.Join(dir, "keys"))
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { kb.Close() })
|
||||
|
||||
keys, err := kb.List()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(keys))
|
||||
|
||||
armor, err := kb.ExportPubKey(keys[0].GetName())
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, armor)
|
||||
|
||||
_, err = kb.ExportPrivKey(keys[0].GetName(), "12345678", "12345678")
|
||||
require.Error(t, err)
|
||||
|
||||
armoredInfo, err := kb.Export(keys[0].GetName())
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, armoredInfo)
|
||||
}
|
|
@ -0,0 +1,273 @@
|
|||
package keyring
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/99designs/keyring"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec/legacy"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
const n1 = "cosmos"
|
||||
|
||||
type MigrationTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
kb Keyring
|
||||
priv cryptotypes.PrivKey
|
||||
pub cryptotypes.PubKey
|
||||
ks keystore
|
||||
}
|
||||
|
||||
func (s *MigrationTestSuite) SetupSuite() {
|
||||
dir := s.T().TempDir()
|
||||
mockIn := strings.NewReader("")
|
||||
cdc := getCodec()
|
||||
|
||||
kb, err := New(n1, BackendTest, dir, mockIn, cdc)
|
||||
s.Require().NoError(err)
|
||||
|
||||
ks, ok := kb.(keystore)
|
||||
s.Require().True(ok)
|
||||
|
||||
s.kb = kb
|
||||
s.ks = ks
|
||||
|
||||
s.priv = cryptotypes.PrivKey(secp256k1.GenPrivKey())
|
||||
s.pub = s.priv.PubKey()
|
||||
}
|
||||
|
||||
func (s *MigrationTestSuite) TestMigrateLegacyLocalKey() {
|
||||
legacyLocalInfo := newLegacyLocalInfo(n1, s.pub, string(legacy.Cdc.MustMarshal(s.priv)), hd.Secp256k1.Name())
|
||||
serializedLegacyLocalInfo := MarshalInfo(legacyLocalInfo)
|
||||
|
||||
item := keyring.Item{
|
||||
Key: n1,
|
||||
Data: serializedLegacyLocalInfo,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.ks.SetItem(item))
|
||||
|
||||
_, migrated, err := s.ks.migrate(n1)
|
||||
s.Require().True(migrated)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (s *MigrationTestSuite) TestMigrateLegacyLedgerKey() {
|
||||
account, coinType, index := uint32(118), uint32(0), uint32(0)
|
||||
hdPath := hd.NewFundraiserParams(account, coinType, index)
|
||||
legacyLedgerInfo := newLegacyLedgerInfo(n1, s.pub, *hdPath, hd.Secp256k1.Name())
|
||||
serializedLegacyLedgerInfo := MarshalInfo(legacyLedgerInfo)
|
||||
|
||||
item := keyring.Item{
|
||||
Key: n1,
|
||||
Data: serializedLegacyLedgerInfo,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.ks.SetItem(item))
|
||||
|
||||
_, migrated, err := s.ks.migrate(n1)
|
||||
s.Require().True(migrated)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (s *MigrationTestSuite) TestMigrateLegacyOfflineKey() {
|
||||
legacyOfflineInfo := newLegacyOfflineInfo(n1, s.pub, hd.Secp256k1.Name())
|
||||
serializedLegacyOfflineInfo := MarshalInfo(legacyOfflineInfo)
|
||||
|
||||
item := keyring.Item{
|
||||
Key: n1,
|
||||
Data: serializedLegacyOfflineInfo,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.ks.SetItem(item))
|
||||
|
||||
_, migrated, err := s.ks.migrate(n1)
|
||||
s.Require().True(migrated)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (s *MigrationTestSuite) TestMigrateLegacyMultiKey() {
|
||||
multi := multisig.NewLegacyAminoPubKey(
|
||||
1, []cryptotypes.PubKey{
|
||||
s.pub,
|
||||
},
|
||||
)
|
||||
|
||||
LegacyMultiInfo, err := NewLegacyMultiInfo(n1, multi)
|
||||
s.Require().NoError(err)
|
||||
serializedLegacyMultiInfo := MarshalInfo(LegacyMultiInfo)
|
||||
|
||||
item := keyring.Item{
|
||||
Key: n1,
|
||||
Data: serializedLegacyMultiInfo,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.ks.SetItem(item))
|
||||
|
||||
_, migrated, err := s.ks.migrate(n1)
|
||||
s.Require().True(migrated)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (s *MigrationTestSuite) TestMigrateLocalRecord() {
|
||||
k1, err := NewLocalRecord("test record", s.priv, s.pub)
|
||||
s.Require().NoError(err)
|
||||
|
||||
serializedRecord, err := s.ks.cdc.Marshal(k1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
item := keyring.Item{
|
||||
Key: n1,
|
||||
Data: serializedRecord,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.ks.SetItem(item))
|
||||
|
||||
k2, migrated, err := s.ks.migrate(n1)
|
||||
s.Require().Equal(k2.Name, k1.Name)
|
||||
|
||||
pub, err := k2.GetPubKey()
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(pub, s.pub)
|
||||
|
||||
priv, err := extractPrivKeyFromRecord(k2)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(priv, s.priv)
|
||||
|
||||
s.Require().False(migrated)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (s *MigrationTestSuite) TestMigrateOneRandomItemError() {
|
||||
randomBytes := []byte("abckd0s03l")
|
||||
errItem := keyring.Item{
|
||||
Key: n1,
|
||||
Data: randomBytes,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.ks.SetItem(errItem))
|
||||
|
||||
_, migrated, err := s.ks.migrate(n1)
|
||||
s.Require().False(migrated)
|
||||
s.Require().Error(err)
|
||||
}
|
||||
|
||||
func (s *MigrationTestSuite) TestMigrateAllLegacyMultiOffline() {
|
||||
multi := multisig.NewLegacyAminoPubKey(
|
||||
1, []cryptotypes.PubKey{
|
||||
s.pub,
|
||||
},
|
||||
)
|
||||
|
||||
LegacyMultiInfo, err := NewLegacyMultiInfo(n1, multi)
|
||||
s.Require().NoError(err)
|
||||
serializedLegacyMultiInfo := MarshalInfo(LegacyMultiInfo)
|
||||
|
||||
item := keyring.Item{
|
||||
Key: n1,
|
||||
Data: serializedLegacyMultiInfo,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.ks.SetItem(item))
|
||||
|
||||
legacyOfflineInfo := newLegacyOfflineInfo(n1, s.pub, hd.Secp256k1.Name())
|
||||
serializedLegacyOfflineInfo := MarshalInfo(legacyOfflineInfo)
|
||||
|
||||
item = keyring.Item{
|
||||
Key: n1,
|
||||
Data: serializedLegacyOfflineInfo,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.ks.SetItem(item))
|
||||
|
||||
migrated, err := s.kb.MigrateAll()
|
||||
s.Require().True(migrated)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (s *MigrationTestSuite) TestMigrateAllNoItem() {
|
||||
migrated, err := s.kb.MigrateAll()
|
||||
s.Require().False(migrated)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (s *MigrationTestSuite) TestMigrateErrUnknownItemKey() {
|
||||
legacyOfflineInfo := newLegacyOfflineInfo(n1, s.pub, hd.Secp256k1.Name())
|
||||
serializedLegacyOfflineInfo := MarshalInfo(legacyOfflineInfo)
|
||||
|
||||
item := keyring.Item{
|
||||
Key: n1,
|
||||
Data: serializedLegacyOfflineInfo,
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.ks.SetItem(item))
|
||||
|
||||
incorrectItemKey := n1 + "1"
|
||||
_, migrated, err := s.ks.migrate(incorrectItemKey)
|
||||
s.Require().False(migrated)
|
||||
s.Require().EqualError(err, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, incorrectItemKey).Error())
|
||||
}
|
||||
|
||||
func (s *MigrationTestSuite) TestMigrateErrEmptyItemData() {
|
||||
item := keyring.Item{
|
||||
Key: n1,
|
||||
Data: []byte{},
|
||||
Description: "SDK kerying version",
|
||||
}
|
||||
|
||||
s.Require().NoError(s.ks.SetItem(item))
|
||||
|
||||
_, migrated, err := s.ks.migrate(n1)
|
||||
s.Require().False(migrated)
|
||||
s.Require().EqualError(err, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, n1).Error())
|
||||
}
|
||||
func TestMigrationTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(MigrationTestSuite))
|
||||
}
|
||||
|
||||
// newLegacyLocalInfo creates a new legacyLocalInfo instance
|
||||
func newLegacyLocalInfo(name string, pub cryptotypes.PubKey, privArmor string, algo hd.PubKeyType) LegacyInfo {
|
||||
return &legacyLocalInfo{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
PrivKeyArmor: privArmor,
|
||||
Algo: algo,
|
||||
}
|
||||
}
|
||||
|
||||
// newLegacyOfflineInfo creates a new legacyLedgerInfo instance
|
||||
func newLegacyLedgerInfo(name string, pub cryptotypes.PubKey, path hd.BIP44Params, algo hd.PubKeyType) LegacyInfo {
|
||||
return &legacyLedgerInfo{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
Path: path,
|
||||
Algo: algo,
|
||||
}
|
||||
}
|
||||
|
||||
// newLegacyOfflineInfo creates a new legacyOfflineInfo instance
|
||||
func newLegacyOfflineInfo(name string, pub cryptotypes.PubKey, algo hd.PubKeyType) LegacyInfo {
|
||||
return &legacyOfflineInfo{
|
||||
Name: name,
|
||||
PubKey: pub,
|
||||
Algo: algo,
|
||||
}
|
||||
}
|
|
@ -39,36 +39,47 @@ func NewKeyOutput(name string, keyType KeyType, a sdk.Address, pk cryptotypes.Pu
|
|||
}
|
||||
|
||||
// MkConsKeyOutput create a KeyOutput in with "cons" Bech32 prefixes.
|
||||
func MkConsKeyOutput(keyInfo Info) (KeyOutput, error) {
|
||||
pk := keyInfo.GetPubKey()
|
||||
func MkConsKeyOutput(k *Record) (KeyOutput, error) {
|
||||
pk, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return KeyOutput{}, err
|
||||
}
|
||||
addr := sdk.ConsAddress(pk.Address())
|
||||
return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType(), addr, pk)
|
||||
return NewKeyOutput(k.Name, k.GetType(), addr, pk)
|
||||
}
|
||||
|
||||
// MkValKeyOutput create a KeyOutput in with "val" Bech32 prefixes.
|
||||
func MkValKeyOutput(keyInfo Info) (KeyOutput, error) {
|
||||
pk := keyInfo.GetPubKey()
|
||||
func MkValKeyOutput(k *Record) (KeyOutput, error) {
|
||||
pk, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return KeyOutput{}, err
|
||||
}
|
||||
|
||||
addr := sdk.ValAddress(pk.Address())
|
||||
return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType(), addr, pk)
|
||||
|
||||
return NewKeyOutput(k.Name, k.GetType(), addr, pk)
|
||||
}
|
||||
|
||||
// MkAccKeyOutput create a KeyOutput in with "acc" Bech32 prefixes. If the
|
||||
// public key is a multisig public key, then the threshold and constituent
|
||||
// public keys will be added.
|
||||
func MkAccKeyOutput(keyInfo Info) (KeyOutput, error) {
|
||||
pk := keyInfo.GetPubKey()
|
||||
func MkAccKeyOutput(k *Record) (KeyOutput, error) {
|
||||
pk, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return KeyOutput{}, err
|
||||
}
|
||||
addr := sdk.AccAddress(pk.Address())
|
||||
return NewKeyOutput(keyInfo.GetName(), keyInfo.GetType(), addr, pk)
|
||||
return NewKeyOutput(k.Name, k.GetType(), addr, pk)
|
||||
}
|
||||
|
||||
// MkAccKeysOutput returns a slice of KeyOutput objects, each with the "acc"
|
||||
// Bech32 prefixes, given a slice of Info objects. It returns an error if any
|
||||
// Bech32 prefixes, given a slice of Record objects. It returns an error if any
|
||||
// call to MkKeyOutput fails.
|
||||
func MkAccKeysOutput(infos []Info) ([]KeyOutput, error) {
|
||||
kos := make([]KeyOutput, len(infos))
|
||||
func MkAccKeysOutput(records []*Record) ([]KeyOutput, error) {
|
||||
kos := make([]KeyOutput, len(records))
|
||||
var err error
|
||||
for i, info := range infos {
|
||||
kos[i], err = MkAccKeyOutput(info)
|
||||
for i, r := range records {
|
||||
kos[i], err = MkAccKeyOutput(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -17,14 +17,17 @@ func TestBech32KeysOutput(t *testing.T) {
|
|||
tmpKey := sk.PubKey()
|
||||
multisigPk := kmultisig.NewLegacyAminoPubKey(1, []types.PubKey{tmpKey})
|
||||
|
||||
info, err := NewMultiInfo("multisig", multisigPk)
|
||||
k, err := NewMultiRecord("multisig", multisigPk)
|
||||
require.NotNil(t, k)
|
||||
require.NoError(t, err)
|
||||
accAddr := sdk.AccAddress(info.GetPubKey().Address())
|
||||
expectedOutput, err := NewKeyOutput(info.GetName(), info.GetType(), accAddr, multisigPk)
|
||||
pubKey, err := k.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
accAddr := sdk.AccAddress(pubKey.Address())
|
||||
expectedOutput, err := NewKeyOutput(k.Name, k.GetType(), accAddr, multisigPk)
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := MkAccKeyOutput(info)
|
||||
out, err := MkAccKeyOutput(k)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedOutput, out)
|
||||
require.Equal(t, `{Name:multisig Type:multi Address:cosmos1nf8lf6n4wa43rzmdzwe6hkrnw5guekhqt595cw PubKey:{"@type":"/cosmos.crypto.multisig.LegacyAminoPubKey","threshold":1,"public_keys":[{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AurroA7jvfPd1AadmmOvWM2rJSwipXfRf8yD6pLbA2DJ"}]} Mnemonic:}`, fmt.Sprintf("%+v", out))
|
||||
require.Equal(t, "{Name:multisig Type:multi Address:cosmos1nf8lf6n4wa43rzmdzwe6hkrnw5guekhqt595cw PubKey:{\"@type\":\"/cosmos.crypto.multisig.LegacyAminoPubKey\",\"threshold\":1,\"public_keys\":[{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\",\"key\":\"AurroA7jvfPd1AadmmOvWM2rJSwipXfRf8yD6pLbA2DJ\"}]} Mnemonic:}", fmt.Sprintf("%+v", out))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
package keyring
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// ErrPrivKeyExtr is used to output an error if extraction of a private key from Local item fails
|
||||
var ErrPrivKeyExtr = errors.New("private key extraction works only for Local")
|
||||
|
||||
func newRecord(name string, pk cryptotypes.PubKey, item isRecord_Item) (*Record, error) {
|
||||
any, err := codectypes.NewAnyWithValue(pk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Record{name, any, item}, nil
|
||||
}
|
||||
|
||||
// NewLocalRecord creates a new Record with local key item
|
||||
func NewLocalRecord(name string, priv cryptotypes.PrivKey, pk cryptotypes.PubKey) (*Record, error) {
|
||||
any, err := codectypes.NewAnyWithValue(priv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
recordLocal := &Record_Local{any, priv.Type()}
|
||||
recordLocalItem := &Record_Local_{recordLocal}
|
||||
|
||||
return newRecord(name, pk, recordLocalItem)
|
||||
}
|
||||
|
||||
// NewLedgerRecord creates a new Record with ledger item
|
||||
func NewLedgerRecord(name string, pk cryptotypes.PubKey, path *hd.BIP44Params) (*Record, error) {
|
||||
recordLedger := &Record_Ledger{path}
|
||||
recordLedgerItem := &Record_Ledger_{recordLedger}
|
||||
return newRecord(name, pk, recordLedgerItem)
|
||||
}
|
||||
|
||||
func (rl *Record_Ledger) GetPath() *hd.BIP44Params {
|
||||
return rl.Path
|
||||
}
|
||||
|
||||
// NewOfflineRecord creates a new Record with offline item
|
||||
func NewOfflineRecord(name string, pk cryptotypes.PubKey) (*Record, error) {
|
||||
recordOffline := &Record_Offline{}
|
||||
recordOfflineItem := &Record_Offline_{recordOffline}
|
||||
return newRecord(name, pk, recordOfflineItem)
|
||||
}
|
||||
|
||||
// NewMultiRecord creates a new Record with multi item
|
||||
func NewMultiRecord(name string, pk cryptotypes.PubKey) (*Record, error) {
|
||||
recordMulti := &Record_Multi{}
|
||||
recordMultiItem := &Record_Multi_{recordMulti}
|
||||
return newRecord(name, pk, recordMultiItem)
|
||||
}
|
||||
|
||||
// GetPubKey fetches a public key of the record
|
||||
func (k *Record) GetPubKey() (cryptotypes.PubKey, error) {
|
||||
pk, ok := k.PubKey.GetCachedValue().(cryptotypes.PubKey)
|
||||
if !ok {
|
||||
return nil, errors.New("unable to cast any to cryptotypes.PubKey")
|
||||
}
|
||||
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// GetAddress fetches an address of the record
|
||||
func (k Record) GetAddress() (types.AccAddress, error) {
|
||||
pk, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pk.Address().Bytes(), nil
|
||||
}
|
||||
|
||||
// GetType fetches type of the record
|
||||
func (k Record) GetType() KeyType {
|
||||
switch {
|
||||
case k.GetLocal() != nil:
|
||||
return TypeLocal
|
||||
case k.GetLedger() != nil:
|
||||
return TypeLedger
|
||||
case k.GetMulti() != nil:
|
||||
return TypeMulti
|
||||
case k.GetOffline() != nil:
|
||||
return TypeOffline
|
||||
default:
|
||||
panic("unrecognized record type")
|
||||
}
|
||||
}
|
||||
|
||||
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
|
||||
func (k *Record) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
|
||||
var pk cryptotypes.PubKey
|
||||
if err := unpacker.UnpackAny(k.PubKey, &pk); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if l := k.GetLocal(); l != nil {
|
||||
var priv cryptotypes.PrivKey
|
||||
return unpacker.UnpackAny(l.PrivKey, &priv)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractPrivKeyFromRecord(k *Record) (cryptotypes.PrivKey, error) {
|
||||
rl := k.GetLocal()
|
||||
if rl == nil {
|
||||
return nil, ErrPrivKeyExtr
|
||||
}
|
||||
|
||||
return extractPrivKeyFromLocal(rl)
|
||||
}
|
||||
|
||||
func extractPrivKeyFromLocal(rl *Record_Local) (cryptotypes.PrivKey, error) {
|
||||
if rl.PrivKey == nil {
|
||||
return nil, errors.New("private key is not available")
|
||||
}
|
||||
|
||||
priv, ok := rl.PrivKey.GetCachedValue().(cryptotypes.PrivKey)
|
||||
if !ok {
|
||||
return nil, errors.New("unable to cast any to cryptotypes.PrivKey")
|
||||
}
|
||||
|
||||
return priv, nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,139 @@
|
|||
package keyring
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
)
|
||||
|
||||
type RecordTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
appName string
|
||||
cdc codec.Codec
|
||||
priv cryptotypes.PrivKey
|
||||
pub cryptotypes.PubKey
|
||||
}
|
||||
|
||||
func (s *RecordTestSuite) SetupSuite() {
|
||||
s.appName = "cosmos"
|
||||
s.cdc = getCodec()
|
||||
s.priv = cryptotypes.PrivKey(ed25519.GenPrivKey())
|
||||
s.pub = s.priv.PubKey()
|
||||
}
|
||||
|
||||
func (s *RecordTestSuite) TestOfflineRecordMarshaling() {
|
||||
k, err := NewOfflineRecord("testrecord", s.pub)
|
||||
s.Require().NoError(err)
|
||||
|
||||
bz, err := s.cdc.Marshal(k)
|
||||
s.Require().NoError(err)
|
||||
|
||||
var k2 Record
|
||||
s.Require().NoError(s.cdc.Unmarshal(bz, &k2))
|
||||
s.Require().Equal(k.Name, k2.Name)
|
||||
s.Require().True(k.PubKey.Equal(k2.PubKey))
|
||||
|
||||
pk2, err := k2.GetPubKey()
|
||||
s.Require().NoError(err)
|
||||
s.Require().True(s.pub.Equals(pk2))
|
||||
}
|
||||
|
||||
func (s *RecordTestSuite) TestLocalRecordMarshaling() {
|
||||
dir := s.T().TempDir()
|
||||
mockIn := strings.NewReader("")
|
||||
|
||||
kb, err := New(s.appName, BackendTest, dir, mockIn, s.cdc)
|
||||
s.Require().NoError(err)
|
||||
|
||||
k, err := NewLocalRecord("testrecord", s.priv, s.pub)
|
||||
s.Require().NoError(err)
|
||||
|
||||
ks, ok := kb.(keystore)
|
||||
s.Require().True(ok)
|
||||
|
||||
bz, err := ks.cdc.Marshal(k)
|
||||
s.Require().NoError(err)
|
||||
|
||||
k2, err := ks.protoUnmarshalRecord(bz)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(k.Name, k2.Name)
|
||||
// not sure if this will work -- we can remove this line, the later check is better.
|
||||
s.Require().True(k.PubKey.Equal(k2.PubKey))
|
||||
|
||||
pub2, err := k2.GetPubKey()
|
||||
s.Require().NoError(err)
|
||||
s.Require().True(s.pub.Equals(pub2))
|
||||
|
||||
localRecord2 := k2.GetLocal()
|
||||
s.Require().NotNil(localRecord2)
|
||||
anyPrivKey, err := codectypes.NewAnyWithValue(s.priv)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(localRecord2.PrivKey, anyPrivKey)
|
||||
s.Require().Equal(localRecord2.PrivKeyType, s.priv.Type())
|
||||
}
|
||||
|
||||
func (s *RecordTestSuite) TestLedgerRecordMarshaling() {
|
||||
dir := s.T().TempDir()
|
||||
mockIn := strings.NewReader("")
|
||||
|
||||
kb, err := New(s.appName, BackendTest, dir, mockIn, s.cdc)
|
||||
s.Require().NoError(err)
|
||||
|
||||
path := hd.NewFundraiserParams(4, 12345, 57)
|
||||
k, err := NewLedgerRecord("testrecord", s.pub, path)
|
||||
s.Require().NoError(err)
|
||||
|
||||
ks, ok := kb.(keystore)
|
||||
s.Require().True(ok)
|
||||
|
||||
bz, err := ks.cdc.Marshal(k)
|
||||
s.Require().NoError(err)
|
||||
|
||||
k2, err := ks.protoUnmarshalRecord(bz)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(k.Name, k2.Name)
|
||||
// not sure if this will work -- we can remove this line, the later check is better.
|
||||
s.Require().True(k.PubKey.Equal(k2.PubKey))
|
||||
|
||||
pub2, err := k2.GetPubKey()
|
||||
s.Require().NoError(err)
|
||||
s.Require().True(s.pub.Equals(pub2))
|
||||
|
||||
ledgerRecord2 := k2.GetLedger()
|
||||
s.Require().NotNil(ledgerRecord2)
|
||||
s.Require().Nil(k2.GetLocal())
|
||||
|
||||
s.Require().Equal(ledgerRecord2.Path.String(), path.String())
|
||||
}
|
||||
|
||||
func (s *RecordTestSuite) TestExtractPrivKeyFromLocalRecord() {
|
||||
// use proto serialize
|
||||
k, err := NewLocalRecord("testrecord", s.priv, s.pub)
|
||||
s.Require().NoError(err)
|
||||
|
||||
privKey2, err := extractPrivKeyFromRecord(k)
|
||||
s.Require().NoError(err)
|
||||
s.Require().True(privKey2.Equals(s.priv))
|
||||
}
|
||||
|
||||
func (s *RecordTestSuite) TestExtractPrivKeyFromOfflineRecord() {
|
||||
k, err := NewOfflineRecord("testrecord", s.pub)
|
||||
s.Require().NoError(err)
|
||||
|
||||
privKey2, err := extractPrivKeyFromRecord(k)
|
||||
s.Require().Error(err)
|
||||
s.Require().Nil(privKey2)
|
||||
}
|
||||
|
||||
func TestRecordTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(RecordTestSuite))
|
||||
}
|
|
@ -37,7 +37,6 @@ const (
|
|||
// bits of entropy to draw when creating a mnemonic
|
||||
defaultEntropySize = 256
|
||||
addressSuffix = "address"
|
||||
infoSuffix = "info"
|
||||
)
|
||||
|
||||
// KeyType reflects a human-readable type for key listing.
|
||||
|
|
|
@ -19,28 +19,41 @@ func Test_writeReadLedgerInfo(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
copy(tmpKey[:], bz)
|
||||
|
||||
lInfo := newLedgerInfo("some_name", &secp256k1.PubKey{Key: tmpKey}, *hd.NewFundraiserParams(5, sdk.CoinType, 1), hd.Secp256k1Type)
|
||||
require.Equal(t, TypeLedger, lInfo.GetType())
|
||||
|
||||
path, err := lInfo.GetPath()
|
||||
pk := &secp256k1.PubKey{Key: tmpKey}
|
||||
path := hd.NewFundraiserParams(5, sdk.CoinType, 1)
|
||||
k, err := NewLedgerRecord("some_name", pk, path)
|
||||
require.NoError(t, err)
|
||||
|
||||
l := k.GetLedger()
|
||||
require.NotNil(t, l)
|
||||
path = l.Path
|
||||
require.Equal(t, "m/44'/118'/5'/0/1", path.String())
|
||||
pubKey, err := k.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t,
|
||||
fmt.Sprintf("PubKeySecp256k1{%s}", hexPK),
|
||||
lInfo.GetPubKey().String())
|
||||
pubKey.String())
|
||||
|
||||
// Serialize and restore
|
||||
serialized := marshalInfo(lInfo)
|
||||
restoredInfo, err := unmarshalInfo(serialized)
|
||||
cdc := getCodec()
|
||||
serialized, err := cdc.Marshal(k)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, restoredInfo)
|
||||
var restoredRecord Record
|
||||
err = cdc.Unmarshal(serialized, &restoredRecord)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, restoredRecord)
|
||||
|
||||
// Check both keys match
|
||||
require.Equal(t, lInfo.GetName(), restoredInfo.GetName())
|
||||
require.Equal(t, lInfo.GetType(), restoredInfo.GetType())
|
||||
require.Equal(t, lInfo.GetPubKey(), restoredInfo.GetPubKey())
|
||||
require.Equal(t, k.Name, restoredRecord.Name)
|
||||
require.Equal(t, k.GetType(), restoredRecord.GetType())
|
||||
|
||||
restoredPath, err := restoredInfo.GetPath()
|
||||
restoredPubKey, err := restoredRecord.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, pubKey, restoredPubKey)
|
||||
|
||||
l = restoredRecord.GetLedger()
|
||||
require.NotNil(t, l)
|
||||
restoredPath := l.GetPath()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, path, restoredPath)
|
||||
}
|
||||
|
|
|
@ -456,10 +456,9 @@ func TestProtoMarshalJSON(t *testing.T) {
|
|||
require.True(pk2.Equals(msig))
|
||||
|
||||
// Test that we can correctly unmarshal key from keyring output
|
||||
|
||||
info, err := keyring.NewMultiInfo("my multisig", msig)
|
||||
k, err := keyring.NewMultiRecord("my multisig", msig)
|
||||
require.NoError(err)
|
||||
ko, err := keyring.MkAccKeyOutput(info)
|
||||
ko, err := keyring.MkAccKeyOutput(k)
|
||||
require.NoError(err)
|
||||
require.Equal(ko.Address, sdk.AccAddress(pk2.Address()).String())
|
||||
require.Equal(ko.PubKey, string(bz))
|
||||
|
|
|
@ -8,11 +8,10 @@ import (
|
|||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/cosmos/go-bip39"
|
||||
secp256k1 "github.com/tendermint/btcd/btcec"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
"github.com/cosmos/go-bip39"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
csecp256k1 "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
|
|
|
@ -140,7 +140,7 @@ func TestPublicKeyHDPath(t *testing.T) {
|
|||
// Check with device
|
||||
for i := 0; i < len(expectedAddrs); i++ {
|
||||
path := *hd.NewFundraiserParams(0, sdk.CoinType, uint32(i))
|
||||
t.Logf("Checking keys at %s\n", path)
|
||||
t.Logf("Checking keys at %s\n", path.String())
|
||||
|
||||
priv, addr, err := NewPrivKeySecp256k1(path, "cosmos")
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -225,6 +225,16 @@
|
|||
- [PrivKey](#cosmos.crypto.ed25519.PrivKey)
|
||||
- [PubKey](#cosmos.crypto.ed25519.PubKey)
|
||||
|
||||
- [cosmos/crypto/hd/v1/hd.proto](#cosmos/crypto/hd/v1/hd.proto)
|
||||
- [BIP44Params](#cosmos.crypto.hd.v1.BIP44Params)
|
||||
|
||||
- [cosmos/crypto/keyring/v1/record.proto](#cosmos/crypto/keyring/v1/record.proto)
|
||||
- [Record](#cosmos.crypto.keyring.v1.Record)
|
||||
- [Record.Ledger](#cosmos.crypto.keyring.v1.Record.Ledger)
|
||||
- [Record.Local](#cosmos.crypto.keyring.v1.Record.Local)
|
||||
- [Record.Multi](#cosmos.crypto.keyring.v1.Record.Multi)
|
||||
- [Record.Offline](#cosmos.crypto.keyring.v1.Record.Offline)
|
||||
|
||||
- [cosmos/crypto/multisig/keys.proto](#cosmos/crypto/multisig/keys.proto)
|
||||
- [LegacyAminoPubKey](#cosmos.crypto.multisig.LegacyAminoPubKey)
|
||||
|
||||
|
@ -3579,6 +3589,129 @@ then you must create a new proto message and follow ADR-28 for Address construct
|
|||
|
||||
|
||||
|
||||
<!-- end messages -->
|
||||
|
||||
<!-- end enums -->
|
||||
|
||||
<!-- end HasExtensions -->
|
||||
|
||||
<!-- end services -->
|
||||
|
||||
|
||||
|
||||
<a name="cosmos/crypto/hd/v1/hd.proto"></a>
|
||||
<p align="right"><a href="#top">Top</a></p>
|
||||
|
||||
## cosmos/crypto/hd/v1/hd.proto
|
||||
|
||||
|
||||
|
||||
<a name="cosmos.crypto.hd.v1.BIP44Params"></a>
|
||||
|
||||
### BIP44Params
|
||||
BIP44Params is used as path field in ledger item in Record.
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| `purpose` | [uint32](#uint32) | | purpose is a constant set to 44' (or 0x8000002C) following the BIP43 recommendation |
|
||||
| `coin_type` | [uint32](#uint32) | | coin_type is a constant that improves privacy |
|
||||
| `account` | [uint32](#uint32) | | account splits the key space into independent user identities |
|
||||
| `change` | [bool](#bool) | | change is a constant used for public derivation. Constant 0 is used for external chain and constant 1 for internal chain. |
|
||||
| `address_index` | [uint32](#uint32) | | address_index is used as child index in BIP32 derivation |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- end messages -->
|
||||
|
||||
<!-- end enums -->
|
||||
|
||||
<!-- end HasExtensions -->
|
||||
|
||||
<!-- end services -->
|
||||
|
||||
|
||||
|
||||
<a name="cosmos/crypto/keyring/v1/record.proto"></a>
|
||||
<p align="right"><a href="#top">Top</a></p>
|
||||
|
||||
## cosmos/crypto/keyring/v1/record.proto
|
||||
|
||||
|
||||
|
||||
<a name="cosmos.crypto.keyring.v1.Record"></a>
|
||||
|
||||
### Record
|
||||
Record is used for representing a key in the keyring.
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| `name` | [string](#string) | | name represents a name of Record |
|
||||
| `pub_key` | [google.protobuf.Any](#google.protobuf.Any) | | pub_key represents a public key in any format |
|
||||
| `local` | [Record.Local](#cosmos.crypto.keyring.v1.Record.Local) | | local stores the public information about a locally stored key |
|
||||
| `ledger` | [Record.Ledger](#cosmos.crypto.keyring.v1.Record.Ledger) | | ledger stores the public information about a Ledger key |
|
||||
| `multi` | [Record.Multi](#cosmos.crypto.keyring.v1.Record.Multi) | | Multi does not store any information. |
|
||||
| `offline` | [Record.Offline](#cosmos.crypto.keyring.v1.Record.Offline) | | Offline does not store any information. |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="cosmos.crypto.keyring.v1.Record.Ledger"></a>
|
||||
|
||||
### Record.Ledger
|
||||
Ledger item
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| `path` | [cosmos.crypto.hd.v1.BIP44Params](#cosmos.crypto.hd.v1.BIP44Params) | | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="cosmos.crypto.keyring.v1.Record.Local"></a>
|
||||
|
||||
### Record.Local
|
||||
Item is a keyring item stored in a keyring backend.
|
||||
Local item
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| `priv_key` | [google.protobuf.Any](#google.protobuf.Any) | | |
|
||||
| `priv_key_type` | [string](#string) | | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="cosmos.crypto.keyring.v1.Record.Multi"></a>
|
||||
|
||||
### Record.Multi
|
||||
Multi item
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="cosmos.crypto.keyring.v1.Record.Offline"></a>
|
||||
|
||||
### Record.Offline
|
||||
Offline item
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- end messages -->
|
||||
|
||||
<!-- end enums -->
|
||||
|
|
2
go.sum
2
go.sum
|
@ -578,12 +578,10 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS
|
|||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ=
|
||||
github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||
github.com/otiai10/mint v1.3.2 h1:VYWnrP5fXmz1MXvjuUvcBrXSjGE6xjON+axB/UrpO3E=
|
||||
github.com/otiai10/mint v1.3.2/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
syntax = "proto3";
|
||||
package cosmos.crypto.hd.v1;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
|
||||
option go_package = "github.com/cosmos/cosmos-sdk/crypto/hd";
|
||||
option (gogoproto.goproto_getters_all) = false;
|
||||
|
||||
// BIP44Params is used as path field in ledger item in Record.
|
||||
message BIP44Params {
|
||||
option (gogoproto.goproto_stringer) = false;
|
||||
// purpose is a constant set to 44' (or 0x8000002C) following the BIP43 recommendation
|
||||
uint32 purpose = 1;
|
||||
// coin_type is a constant that improves privacy
|
||||
uint32 coin_type = 2;
|
||||
// account splits the key space into independent user identities
|
||||
uint32 account = 3;
|
||||
// change is a constant used for public derivation. Constant 0 is used for external chain and constant 1 for internal chain.
|
||||
bool change = 4;
|
||||
// address_index is used as child index in BIP32 derivation
|
||||
uint32 address_index = 5;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
syntax = "proto3";
|
||||
package cosmos.crypto.keyring.v1;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
import "google/protobuf/any.proto";
|
||||
import "cosmos/crypto/hd/v1/hd.proto";
|
||||
|
||||
option go_package = "github.com/cosmos/cosmos-sdk/crypto/keyring";
|
||||
option (gogoproto.goproto_getters_all) = false;
|
||||
|
||||
// Record is used for representing a key in the keyring.
|
||||
message Record {
|
||||
// name represents a name of Record
|
||||
string name = 1;
|
||||
// pub_key represents a public key in any format
|
||||
google.protobuf.Any pub_key = 2;
|
||||
|
||||
// Record contains one of the following items
|
||||
oneof item {
|
||||
// local stores the public information about a locally stored key
|
||||
Local local = 3;
|
||||
// ledger stores the public information about a Ledger key
|
||||
Ledger ledger = 4;
|
||||
// Multi does not store any information.
|
||||
Multi multi = 5;
|
||||
// Offline does not store any information.
|
||||
Offline offline = 6;
|
||||
}
|
||||
|
||||
// Item is a keyring item stored in a keyring backend.
|
||||
// Local item
|
||||
message Local {
|
||||
google.protobuf.Any priv_key = 1;
|
||||
string priv_key_type = 2;
|
||||
}
|
||||
|
||||
// Ledger item
|
||||
message Ledger {
|
||||
hd.v1.BIP44Params path = 1;
|
||||
}
|
||||
|
||||
// Multi item
|
||||
message Multi {}
|
||||
|
||||
// Offline item
|
||||
message Offline {}
|
||||
}
|
|
@ -5,18 +5,23 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// GenerateCoinKey returns the address of a public key, along with the secret
|
||||
// phrase to recover the private key.
|
||||
func GenerateCoinKey(algo keyring.SignatureAlgo) (sdk.AccAddress, string, error) {
|
||||
func GenerateCoinKey(algo keyring.SignatureAlgo, cdc codec.Codec) (sdk.AccAddress, string, error) {
|
||||
// generate a private key, with recovery phrase
|
||||
info, secret, err := keyring.NewInMemory().NewMnemonic("name", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, algo)
|
||||
k, secret, err := keyring.NewInMemory(cdc).NewMnemonic("name", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, algo)
|
||||
if err != nil {
|
||||
return sdk.AccAddress([]byte{}), "", err
|
||||
}
|
||||
return sdk.AccAddress(info.GetPubKey().Address()), secret, nil
|
||||
addr, err := k.GetAddress()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return addr, secret, nil
|
||||
}
|
||||
|
||||
// GenerateSaveCoinKey returns the address of a public key, along with the secret
|
||||
|
@ -43,10 +48,15 @@ func GenerateSaveCoinKey(keybase keyring.Keyring, keyName string, overwrite bool
|
|||
}
|
||||
}
|
||||
|
||||
info, secret, err := keybase.NewMnemonic(keyName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, algo)
|
||||
k, secret, err := keybase.NewMnemonic(keyName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, algo)
|
||||
if err != nil {
|
||||
return sdk.AccAddress([]byte{}), "", err
|
||||
}
|
||||
|
||||
return sdk.AccAddress(info.GetPubKey().Address()), secret, nil
|
||||
addr, err := k.GetAddress()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return addr, secret, nil
|
||||
}
|
||||
|
|
|
@ -8,44 +8,54 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func TestGenerateCoinKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
addr, mnemonic, err := server.GenerateCoinKey(hd.Secp256k1)
|
||||
cdc := simapp.MakeTestEncodingConfig().Codec
|
||||
addr, mnemonic, err := server.GenerateCoinKey(hd.Secp256k1, cdc)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test creation
|
||||
info, err := keyring.NewInMemory().NewAccount("xxx", mnemonic, "", hd.NewFundraiserParams(0, types.GetConfig().GetCoinType(), 0).String(), hd.Secp256k1)
|
||||
k, err := keyring.NewInMemory(cdc).NewAccount("xxx", mnemonic, "", hd.NewFundraiserParams(0, types.GetConfig().GetCoinType(), 0).String(), hd.Secp256k1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, addr, info.GetAddress())
|
||||
addr1, err := k.GetAddress()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, addr, addr1)
|
||||
}
|
||||
|
||||
func TestGenerateSaveCoinKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
kb, err := keyring.New(t.Name(), "test", t.TempDir(), nil)
|
||||
encCfg := simapp.MakeTestEncodingConfig()
|
||||
kb, err := keyring.New(t.Name(), "test", t.TempDir(), nil, encCfg.Codec)
|
||||
require.NoError(t, err)
|
||||
|
||||
addr, mnemonic, err := server.GenerateSaveCoinKey(kb, "keyname", false, hd.Secp256k1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test key was actually saved
|
||||
info, err := kb.Key("keyname")
|
||||
k, err := kb.Key("keyname")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, addr, info.GetAddress())
|
||||
addr1, err := k.GetAddress()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, addr, addr1)
|
||||
|
||||
// Test in-memory recovery
|
||||
info, err = keyring.NewInMemory().NewAccount("xxx", mnemonic, "", hd.NewFundraiserParams(0, types.GetConfig().GetCoinType(), 0).String(), hd.Secp256k1)
|
||||
k, err = keyring.NewInMemory(encCfg.Codec).NewAccount("xxx", mnemonic, "", hd.NewFundraiserParams(0, types.GetConfig().GetCoinType(), 0).String(), hd.Secp256k1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, addr, info.GetAddress())
|
||||
addr1, err = k.GetAddress()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, addr, addr1)
|
||||
}
|
||||
|
||||
func TestGenerateSaveCoinKeyOverwriteFlag(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
kb, err := keyring.New(t.Name(), "test", t.TempDir(), nil)
|
||||
encCfg := simapp.MakeTestEncodingConfig()
|
||||
kb, err := keyring.New(t.Name(), "test", t.TempDir(), nil, encCfg.Codec)
|
||||
require.NoError(t, err)
|
||||
|
||||
keyname := "justakey"
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package errors
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRegisterError(t *testing.T) {
|
||||
|
|
|
@ -50,9 +50,10 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
|
|||
if err != nil {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
|
||||
|
||||
if keyringBackend != "" && clientCtx.Keyring == nil {
|
||||
var err error
|
||||
kr, err = keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf)
|
||||
kr, err = keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf, clientCtx.Codec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -60,11 +61,15 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
|
|||
kr = clientCtx.Keyring
|
||||
}
|
||||
|
||||
info, err := kr.Key(args[0])
|
||||
k, err := kr.Key(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get address from Keyring: %w", err)
|
||||
}
|
||||
addr = info.GetAddress()
|
||||
|
||||
addr, err = k.GetAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
coins, err := sdk.ParseCoinsNormalized(args[1])
|
||||
|
|
|
@ -81,7 +81,7 @@ func TestAddGenesisAccountCmd(t *testing.T) {
|
|||
|
||||
if tc.withKeyring {
|
||||
path := hd.CreateHDPath(118, 0, 0).String()
|
||||
kr, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, home, nil)
|
||||
kr, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, home, nil, appCodec)
|
||||
require.NoError(t, err)
|
||||
_, _, err = kr.NewMnemonic(tc.addr, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
|
||||
"github.com/spf13/cast"
|
||||
"github.com/spf13/cobra"
|
||||
tmcli "github.com/tendermint/tendermint/libs/cli"
|
||||
|
@ -21,6 +20,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
|
||||
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/simapp/params"
|
||||
|
|
|
@ -253,7 +253,7 @@ func initTestnetFiles(
|
|||
memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip)
|
||||
genFiles = append(genFiles, nodeConfig.GenesisFile())
|
||||
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), args.keyringBackend, nodeDir, inBuf)
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), args.keyringBackend, nodeDir, inBuf, clientCtx.Codec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
|
@ -12,9 +16,6 @@ import (
|
|||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil"
|
||||
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
)
|
||||
|
||||
func Test_TestnetCmd(t *testing.T) {
|
||||
|
|
|
@ -4,8 +4,9 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store/types"
|
||||
)
|
||||
|
||||
func TestStoreGetKVStore(t *testing.T) {
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
metrics "github.com/armon/go-metrics"
|
||||
"github.com/armon/go-metrics"
|
||||
metricsprom "github.com/armon/go-metrics/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/expfmt"
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
metrics "github.com/armon/go-metrics"
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/prometheus/common/expfmt"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
|
@ -3,7 +3,7 @@ package telemetry
|
|||
import (
|
||||
"time"
|
||||
|
||||
metrics "github.com/armon/go-metrics"
|
||||
"github.com/armon/go-metrics"
|
||||
)
|
||||
|
||||
// Common metric key constants
|
||||
|
|
|
@ -338,7 +338,7 @@ func New(l Logger, baseDir string, cfg Config) (*Network, error) {
|
|||
nodeIDs[i] = nodeID
|
||||
valPubKeys[i] = pubKey
|
||||
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, cfg.KeyringOptions...)
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, cfg.Codec, cfg.KeyringOptions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ func (s *handlerTestSuite) TestChainAnteDecorators() {
|
|||
mockAnteDecorator2 := mocks.NewMockAnteDecorator(mockCtrl)
|
||||
// NOTE: we can't check that mockAnteDecorator2 is passed as the last argument because
|
||||
// ChainAnteDecorators wraps the decorators into closures, so each decorator is
|
||||
// receving a closure.
|
||||
// receiving a closure.
|
||||
mockAnteDecorator1.EXPECT().AnteHandle(gomock.Eq(ctx), gomock.Eq(tx), true, gomock.Any()).Times(1)
|
||||
mockAnteDecorator2.EXPECT().AnteHandle(gomock.Eq(ctx), gomock.Eq(tx), true, gomock.Any()).Times(1)
|
||||
|
||||
|
|
|
@ -5,9 +5,7 @@ import (
|
|||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -15,6 +13,7 @@ import (
|
|||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/tests/mocks"
|
||||
|
|
|
@ -92,15 +92,24 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
multisigInfo, err := getMultisigInfo(clientCtx, args[1])
|
||||
k, err := getMultisigRecord(clientCtx, args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pubKey, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
multisigPub := multisigInfo.GetPubKey().(*kmultisig.LegacyAminoPubKey)
|
||||
addr, err := k.GetAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
multisigPub := pubKey.(*kmultisig.LegacyAminoPubKey)
|
||||
multisigSig := multisig.NewMultisig(len(multisigPub.PubKeys))
|
||||
if !clientCtx.Offline {
|
||||
accnum, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, multisigInfo.GetAddress())
|
||||
accnum, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -264,7 +273,7 @@ func makeBatchMultisignCmd() func(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
scanner := authclient.NewBatchScanner(txCfg, infile)
|
||||
|
||||
multisigInfo, err := getMultisigInfo(clientCtx, args[1])
|
||||
k, err := getMultisigRecord(clientCtx, args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -279,8 +288,13 @@ func makeBatchMultisignCmd() func(cmd *cobra.Command, args []string) error {
|
|||
signatureBatch = append(signatureBatch, sigs)
|
||||
}
|
||||
|
||||
addr, err := k.GetAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !clientCtx.Offline {
|
||||
accnum, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, multisigInfo.GetAddress())
|
||||
accnum, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -302,8 +316,11 @@ func makeBatchMultisignCmd() func(cmd *cobra.Command, args []string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
multisigPub := multisigInfo.GetPubKey().(*kmultisig.LegacyAminoPubKey)
|
||||
pubKey, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
multisigPub := pubKey.(*kmultisig.LegacyAminoPubKey)
|
||||
multisigSig := multisig.NewMultisig(len(multisigPub.PubKeys))
|
||||
signingData := signing.SignerData{
|
||||
ChainID: txFactory.ChainID(),
|
||||
|
@ -402,15 +419,12 @@ func readSignaturesFromFile(ctx client.Context, filename string) (sigs []signing
|
|||
return sigs, nil
|
||||
}
|
||||
|
||||
func getMultisigInfo(clientCtx client.Context, name string) (keyring.Info, error) {
|
||||
func getMultisigRecord(clientCtx client.Context, name string) (*keyring.Record, error) {
|
||||
kb := clientCtx.Keyring
|
||||
multisigInfo, err := kb.Key(name)
|
||||
multisigRecord, err := kb.Key(name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error getting keybase multisig account")
|
||||
}
|
||||
if multisigInfo.GetType() != keyring.TypeMulti {
|
||||
return nil, fmt.Errorf("%q must be of type %s: %s", name, keyring.TypeMulti, multisigInfo.GetType())
|
||||
}
|
||||
|
||||
return multisigInfo, nil
|
||||
return multisigRecord, nil
|
||||
}
|
||||
|
|
|
@ -62,8 +62,12 @@ func (s *IntegrationTestSuite) SetupSuite() {
|
|||
|
||||
account2, _, err := kb.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
s.Require().NoError(err)
|
||||
pub1, err := account1.GetPubKey()
|
||||
s.Require().NoError(err)
|
||||
pub2, err := account2.GetPubKey()
|
||||
s.Require().NoError(err)
|
||||
|
||||
multi := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{account1.GetPubKey(), account2.GetPubKey()})
|
||||
multi := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{pub1, pub2})
|
||||
_, err = kb.SaveMultisig("multi", multi)
|
||||
s.Require().NoError(err)
|
||||
|
||||
|
@ -113,11 +117,14 @@ func (s *IntegrationTestSuite) TestCLISignGenOnly() {
|
|||
val := s.network.Validators[0]
|
||||
val2 := s.network.Validators[1]
|
||||
|
||||
info, err := val.ClientCtx.Keyring.KeyByAddress(val.Address)
|
||||
k, err := val.ClientCtx.Keyring.KeyByAddress(val.Address)
|
||||
s.Require().NoError(err)
|
||||
keyName := info.GetName()
|
||||
keyName := k.Name
|
||||
|
||||
account, err := val.ClientCtx.AccountRetriever.GetAccount(val.ClientCtx, info.GetAddress())
|
||||
addr, err := k.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
|
||||
account, err := val.ClientCtx.AccountRetriever.GetAccount(val.ClientCtx, addr)
|
||||
s.Require().NoError(err)
|
||||
|
||||
sendTokens := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)))
|
||||
|
@ -288,7 +295,7 @@ func (s *IntegrationTestSuite) TestCLISignAminoJSON() {
|
|||
|
||||
// SIC! validators have same key names and same addresses as those registered in the keyring,
|
||||
// BUT the keys are different!
|
||||
valInfo, err := val1.ClientCtx.Keyring.Key(val1.Moniker)
|
||||
valRecord, err := val1.ClientCtx.Keyring.Key(val1.Moniker)
|
||||
require.NoError(err)
|
||||
|
||||
// query account info
|
||||
|
@ -301,7 +308,9 @@ func (s *IntegrationTestSuite) TestCLISignAminoJSON() {
|
|||
res, err := TxSignExec(val1.ClientCtx, val1.Address, fileUnsigned.Name(), chainFlag,
|
||||
sigOnlyFlag, signModeAminoFlag)
|
||||
require.NoError(err)
|
||||
checkSignatures(require, txCfg, res.Bytes(), valInfo.GetPubKey())
|
||||
pub, err := valRecord.GetPubKey()
|
||||
require.NoError(err)
|
||||
checkSignatures(require, txCfg, res.Bytes(), pub)
|
||||
sigs, err := txCfg.UnmarshalSignatureJSON(res.Bytes())
|
||||
require.NoError(err)
|
||||
require.Equal(1, len(sigs))
|
||||
|
@ -333,7 +342,7 @@ func (s *IntegrationTestSuite) TestCLISignAminoJSON() {
|
|||
res, err = TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag,
|
||||
sigOnlyFlag, signModeAminoFlag)
|
||||
require.NoError(err)
|
||||
checkSignatures(require, txCfg, res.Bytes(), valInfo.GetPubKey(), valInfo.GetPubKey())
|
||||
checkSignatures(require, txCfg, res.Bytes(), pub, pub)
|
||||
|
||||
/**** try to overwrite the previously signed transaction ****/
|
||||
|
||||
|
@ -344,7 +353,7 @@ func (s *IntegrationTestSuite) TestCLISignAminoJSON() {
|
|||
res, err = TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag,
|
||||
sigOnlyFlag, "--overwrite", signModeAminoFlag)
|
||||
require.NoError(err)
|
||||
checkSignatures(require, txCfg, res.Bytes(), valInfo.GetPubKey())
|
||||
checkSignatures(require, txCfg, res.Bytes(), pub)
|
||||
|
||||
/**** test flagAmino ****/
|
||||
res, err = TxSignExec(val1.ClientCtx, val1.Address, filenameSigned, chainFlag,
|
||||
|
@ -355,9 +364,8 @@ func (s *IntegrationTestSuite) TestCLISignAminoJSON() {
|
|||
err = val1.ClientCtx.LegacyAmino.UnmarshalJSON(res.Bytes(), &txAmino)
|
||||
require.NoError(err)
|
||||
require.Len(txAmino.Tx.Signatures, 2)
|
||||
require.Equal(txAmino.Tx.Signatures[0].PubKey, valInfo.GetPubKey())
|
||||
require.Equal(txAmino.Tx.Signatures[1].PubKey, valInfo.GetPubKey())
|
||||
|
||||
require.Equal(txAmino.Tx.Signatures[0].PubKey, pub)
|
||||
require.Equal(txAmino.Tx.Signatures[1].PubKey, pub)
|
||||
}
|
||||
|
||||
func checkSignatures(require *require.Assertions, txCfg client.TxConfig, output []byte, pks ...cryptotypes.PubKey) {
|
||||
|
@ -378,9 +386,12 @@ func (s *IntegrationTestSuite) TestCLIQueryTxCmdByHash() {
|
|||
|
||||
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
|
||||
|
||||
addr, err := account2.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Send coins.
|
||||
out, err := s.createBankMsg(
|
||||
val, account2.GetAddress(),
|
||||
val, addr,
|
||||
sdk.NewCoins(sendTokens),
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
@ -446,9 +457,12 @@ func (s *IntegrationTestSuite) TestCLIQueryTxCmdByEvents() {
|
|||
|
||||
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
|
||||
|
||||
addr2, err := account2.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Send coins.
|
||||
out, err := s.createBankMsg(
|
||||
val, account2.GetAddress(),
|
||||
val, addr2,
|
||||
sdk.NewCoins(sendTokens),
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
@ -560,9 +574,12 @@ func (s *IntegrationTestSuite) TestCLIQueryTxsCmdByEvents() {
|
|||
|
||||
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
|
||||
|
||||
addr2, err := account2.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
// Send coins.
|
||||
out, err := s.createBankMsg(
|
||||
val, account2.GetAddress(),
|
||||
val,
|
||||
addr2,
|
||||
sdk.NewCoins(sendTokens),
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
@ -630,7 +647,9 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
|
|||
|
||||
sendTokens := sdk.NewCoin(s.cfg.BondDenom, sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction))
|
||||
|
||||
normalGeneratedTx, err := s.createBankMsg(val1, account.GetAddress(),
|
||||
addr, err := account.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
normalGeneratedTx, err := s.createBankMsg(val1, addr,
|
||||
sdk.NewCoins(sendTokens), fmt.Sprintf("--%s=true", flags.FlagGenerateOnly))
|
||||
s.Require().NoError(err)
|
||||
|
||||
|
@ -647,7 +666,7 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
|
|||
s.Require().Equal(0, len(sigs))
|
||||
|
||||
// Test generate sendTx with --gas=$amount
|
||||
limitedGasGeneratedTx, err := s.createBankMsg(val1, account.GetAddress(),
|
||||
limitedGasGeneratedTx, err := s.createBankMsg(val1, addr,
|
||||
sdk.NewCoins(sendTokens), fmt.Sprintf("--gas=%d", 100),
|
||||
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
|
||||
)
|
||||
|
@ -672,7 +691,7 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
|
|||
startTokens := balRes.Balances.AmountOf(s.cfg.BondDenom)
|
||||
|
||||
// Test generate sendTx, estimate gas
|
||||
finalGeneratedTx, err := s.createBankMsg(val1, account.GetAddress(),
|
||||
finalGeneratedTx, err := s.createBankMsg(val1, addr,
|
||||
sdk.NewCoins(sendTokens), fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
|
||||
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly))
|
||||
s.Require().NoError(err)
|
||||
|
@ -748,7 +767,7 @@ func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() {
|
|||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
// Ensure destiny account state
|
||||
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, account.GetAddress())
|
||||
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, addr)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
|
||||
|
@ -770,13 +789,15 @@ func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
|
|||
account1, err := val1.ClientCtx.Keyring.Key("newAccount1")
|
||||
s.Require().NoError(err)
|
||||
|
||||
multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
|
||||
multisigRecord, err := val1.ClientCtx.Keyring.Key("multi")
|
||||
s.Require().NoError(err)
|
||||
|
||||
addr, err := multisigRecord.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
// Send coins from validator to multisig.
|
||||
_, err = s.createBankMsg(
|
||||
val1,
|
||||
multisigInfo.GetAddress(),
|
||||
addr,
|
||||
sdk.NewCoins(
|
||||
sdk.NewInt64Coin(s.cfg.BondDenom, 10),
|
||||
),
|
||||
|
@ -788,7 +809,7 @@ func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
|
|||
// Generate multisig transaction.
|
||||
multiGeneratedTx, err := bankcli.MsgSendExec(
|
||||
val1.ClientCtx,
|
||||
multisigInfo.GetAddress(),
|
||||
addr,
|
||||
val1.Address,
|
||||
sdk.NewCoins(
|
||||
sdk.NewInt64Coin(s.cfg.BondDenom, 5),
|
||||
|
@ -805,12 +826,14 @@ func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() {
|
|||
|
||||
// Multisign, sign with one signature
|
||||
val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
|
||||
account1Signature, err := TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
||||
addr1, err := account1.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
account1Signature, err := TxSignExec(val1.ClientCtx, addr1, multiGeneratedTxFile.Name(), "--multisig", addr.String())
|
||||
s.Require().NoError(err)
|
||||
|
||||
sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String())
|
||||
|
||||
multiSigWith1Signature, err := TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name())
|
||||
multiSigWith1Signature, err := TxMultiSignExec(val1.ClientCtx, multisigRecord.Name, multiGeneratedTxFile.Name(), sign1File.Name())
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Save tx to file
|
||||
|
@ -861,10 +884,12 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
|
|||
account2, err := val1.ClientCtx.Keyring.Key("newAccount2")
|
||||
s.Require().NoError(err)
|
||||
|
||||
multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
|
||||
multisigRecord, err := val1.ClientCtx.Keyring.Key("multi")
|
||||
s.Require().NoError(err)
|
||||
|
||||
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress())
|
||||
addr, err := multisigRecord.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, addr)
|
||||
s.Require().NoError(err)
|
||||
|
||||
var balRes banktypes.QueryAllBalancesResponse
|
||||
|
@ -876,14 +901,14 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
|
|||
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
|
||||
_, err = s.createBankMsg(
|
||||
val1,
|
||||
multisigInfo.GetAddress(),
|
||||
addr,
|
||||
sdk.NewCoins(sendTokens),
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress())
|
||||
resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, addr)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = val1.ClientCtx.Codec.UnmarshalJSON(resp.Bytes(), &balRes)
|
||||
|
@ -894,7 +919,7 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
|
|||
// Generate multisig transaction.
|
||||
multiGeneratedTx, err := bankcli.MsgSendExec(
|
||||
val1.ClientCtx,
|
||||
multisigInfo.GetAddress(),
|
||||
addr,
|
||||
val1.Address,
|
||||
sdk.NewCoins(
|
||||
sdk.NewInt64Coin(s.cfg.BondDenom, 5),
|
||||
|
@ -910,19 +935,23 @@ func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() {
|
|||
multiGeneratedTxFile := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String())
|
||||
|
||||
// Sign with account1
|
||||
addr1, err := account1.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
|
||||
account1Signature, err := TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
||||
account1Signature, err := TxSignExec(val1.ClientCtx, addr1, multiGeneratedTxFile.Name(), "--multisig", addr.String())
|
||||
s.Require().NoError(err)
|
||||
|
||||
sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String())
|
||||
|
||||
// Sign with account1
|
||||
account2Signature, err := TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
||||
addr2, err := account2.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
account2Signature, err := TxSignExec(val1.ClientCtx, addr2, multiGeneratedTxFile.Name(), "--multisig", addr.String())
|
||||
s.Require().NoError(err)
|
||||
|
||||
sign2File := testutil.WriteToNewTempFile(s.T(), account2Signature.String())
|
||||
|
||||
multiSigWith2Signatures, err := TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
|
||||
multiSigWith2Signatures, err := TxMultiSignExec(val1.ClientCtx, multisigRecord.Name, multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Write the output to disk
|
||||
|
@ -948,19 +977,22 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
|
|||
account2, err := val1.ClientCtx.Keyring.Key("newAccount2")
|
||||
s.Require().NoError(err)
|
||||
|
||||
multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
|
||||
multisigRecord, err := val1.ClientCtx.Keyring.Key("multi")
|
||||
s.Require().NoError(err)
|
||||
|
||||
addr, err := multisigRecord.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Send coins from validator to multisig.
|
||||
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
|
||||
_, err = s.createBankMsg(
|
||||
val1, multisigInfo.GetAddress(),
|
||||
val1, addr,
|
||||
sdk.NewCoins(sendTokens),
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress())
|
||||
resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, addr)
|
||||
s.Require().NoError(err)
|
||||
|
||||
var balRes banktypes.QueryAllBalancesResponse
|
||||
|
@ -971,7 +1003,7 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
|
|||
// Generate multisig transaction.
|
||||
multiGeneratedTx, err := bankcli.MsgSendExec(
|
||||
val1.ClientCtx,
|
||||
multisigInfo.GetAddress(),
|
||||
addr,
|
||||
val1.Address,
|
||||
sdk.NewCoins(
|
||||
sdk.NewInt64Coin(s.cfg.BondDenom, 5),
|
||||
|
@ -986,25 +1018,29 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
|
|||
// Save tx to file
|
||||
multiGeneratedTxFile := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String())
|
||||
|
||||
addr1, err := account1.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
// Sign with account1
|
||||
val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
|
||||
account1Signature, err := TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
||||
account1Signature, err := TxSignExec(val1.ClientCtx, addr1, multiGeneratedTxFile.Name(), "--multisig", addr.String())
|
||||
s.Require().NoError(err)
|
||||
|
||||
sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String())
|
||||
|
||||
// Sign with account2
|
||||
account2Signature, err := TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
||||
addr2, err := account2.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
// Sign with account1
|
||||
account2Signature, err := TxSignExec(val1.ClientCtx, addr2, multiGeneratedTxFile.Name(), "--multisig", addr.String())
|
||||
s.Require().NoError(err)
|
||||
|
||||
sign2File := testutil.WriteToNewTempFile(s.T(), account2Signature.String())
|
||||
|
||||
// Does not work in offline mode.
|
||||
_, err = TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), "--offline", sign1File.Name(), sign2File.Name())
|
||||
s.Require().EqualError(err, fmt.Sprintf("couldn't verify signature for address %s", account1.GetAddress()))
|
||||
_, err = TxMultiSignExec(val1.ClientCtx, multisigRecord.Name, multiGeneratedTxFile.Name(), "--offline", sign1File.Name(), sign2File.Name())
|
||||
s.Require().EqualError(err, fmt.Sprintf("couldn't verify signature for address %s", addr1))
|
||||
|
||||
val1.ClientCtx.Offline = false
|
||||
multiSigWith2Signatures, err := TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
|
||||
multiSigWith2Signatures, err := TxMultiSignExec(val1.ClientCtx, multisigRecord.Name, multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Write the output to disk
|
||||
|
@ -1028,14 +1064,16 @@ func (s *IntegrationTestSuite) TestSignBatchMultisig() {
|
|||
s.Require().NoError(err)
|
||||
account2, err := val.ClientCtx.Keyring.Key("newAccount2")
|
||||
s.Require().NoError(err)
|
||||
multisigInfo, err := val.ClientCtx.Keyring.Key("multi")
|
||||
multisigRecord, err := val.ClientCtx.Keyring.Key("multi")
|
||||
s.Require().NoError(err)
|
||||
|
||||
addr, err := multisigRecord.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
// Send coins from validator to multisig.
|
||||
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
|
||||
_, err = s.createBankMsg(
|
||||
val,
|
||||
multisigInfo.GetAddress(),
|
||||
addr,
|
||||
sdk.NewCoins(sendTokens),
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
@ -1043,7 +1081,7 @@ func (s *IntegrationTestSuite) TestSignBatchMultisig() {
|
|||
|
||||
generatedStd, err := bankcli.MsgSendExec(
|
||||
val.ClientCtx,
|
||||
multisigInfo.GetAddress(),
|
||||
addr,
|
||||
val.Address,
|
||||
sdk.NewCoins(
|
||||
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(1)),
|
||||
|
@ -1059,28 +1097,24 @@ func (s *IntegrationTestSuite) TestSignBatchMultisig() {
|
|||
filename := testutil.WriteToNewTempFile(s.T(), strings.Repeat(generatedStd.String(), 1))
|
||||
val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1)
|
||||
|
||||
addr1, err := account1.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
// sign-batch file
|
||||
res, err := TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String())
|
||||
res, err := TxSignBatchExec(val.ClientCtx, addr1, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
|
||||
// write sigs to file
|
||||
file1 := testutil.WriteToNewTempFile(s.T(), res.String())
|
||||
|
||||
addr2, err := account2.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
// sign-batch file with account2
|
||||
res, err = TxSignBatchExec(val.ClientCtx, account2.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String())
|
||||
res, err = TxSignBatchExec(val.ClientCtx, addr2, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
|
||||
// write sigs to file2
|
||||
file2 := testutil.WriteToNewTempFile(s.T(), res.String())
|
||||
|
||||
// sign-batch file with multisig key name
|
||||
res, err = TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetName())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
|
||||
// write sigs to file3
|
||||
file3 := testutil.WriteToNewTempFile(s.T(), res.String())
|
||||
|
||||
_, err = TxMultiSignExec(val.ClientCtx, multisigInfo.GetName(), filename.Name(), file1.Name(), file2.Name(), file3.Name())
|
||||
_, err = TxMultiSignExec(val.ClientCtx, multisigRecord.Name, filename.Name(), file1.Name(), file2.Name())
|
||||
s.Require().NoError(err)
|
||||
|
||||
}
|
||||
|
@ -1093,14 +1127,16 @@ func (s *IntegrationTestSuite) TestMultisignBatch() {
|
|||
s.Require().NoError(err)
|
||||
account2, err := val.ClientCtx.Keyring.Key("newAccount2")
|
||||
s.Require().NoError(err)
|
||||
multisigInfo, err := val.ClientCtx.Keyring.Key("multi")
|
||||
multisigRecord, err := val.ClientCtx.Keyring.Key("multi")
|
||||
s.Require().NoError(err)
|
||||
|
||||
addr, err := multisigRecord.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
// Send coins from validator to multisig.
|
||||
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 1000)
|
||||
_, err = s.createBankMsg(
|
||||
val,
|
||||
multisigInfo.GetAddress(),
|
||||
addr,
|
||||
sdk.NewCoins(sendTokens),
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
|
@ -1108,7 +1144,7 @@ func (s *IntegrationTestSuite) TestMultisignBatch() {
|
|||
|
||||
generatedStd, err := bankcli.MsgSendExec(
|
||||
val.ClientCtx,
|
||||
multisigInfo.GetAddress(),
|
||||
addr,
|
||||
val.Address,
|
||||
sdk.NewCoins(
|
||||
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(1)),
|
||||
|
@ -1124,34 +1160,30 @@ func (s *IntegrationTestSuite) TestMultisignBatch() {
|
|||
filename := testutil.WriteToNewTempFile(s.T(), strings.Repeat(generatedStd.String(), 3))
|
||||
val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1)
|
||||
|
||||
queryResJSON, err := QueryAccountExec(val.ClientCtx, multisigInfo.GetAddress())
|
||||
queryResJSON, err := QueryAccountExec(val.ClientCtx, addr)
|
||||
s.Require().NoError(err)
|
||||
var account authtypes.AccountI
|
||||
s.Require().NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(queryResJSON.Bytes(), &account))
|
||||
|
||||
// sign-batch file
|
||||
res, err := TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())))
|
||||
addr1, err := account1.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
res, err := TxSignBatchExec(val.ClientCtx, addr1, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())))
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
|
||||
// write sigs to file
|
||||
file1 := testutil.WriteToNewTempFile(s.T(), res.String())
|
||||
|
||||
// sign-batch file with account2
|
||||
res, err = TxSignBatchExec(val.ClientCtx, account2.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())))
|
||||
addr2, err := account2.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
res, err = TxSignBatchExec(val.ClientCtx, addr2, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())))
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
|
||||
|
||||
// multisign the file
|
||||
file2 := testutil.WriteToNewTempFile(s.T(), res.String())
|
||||
|
||||
// sign-batch file with multisig key name
|
||||
res, err = TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetName(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())))
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
|
||||
// write sigs to file
|
||||
file3 := testutil.WriteToNewTempFile(s.T(), res.String())
|
||||
|
||||
res, err = TxMultiSignBatchExec(val.ClientCtx, filename.Name(), multisigInfo.GetName(), file1.Name(), file2.Name(), file3.Name())
|
||||
res, err = TxMultiSignBatchExec(val.ClientCtx, filename.Name(), multisigRecord.Name, file1.Name(), file2.Name())
|
||||
s.Require().NoError(err)
|
||||
signedTxs := strings.Split(strings.Trim(res.String(), "\n"), "\n")
|
||||
|
||||
|
|
|
@ -34,18 +34,22 @@ func (gr GasEstimateResponse) String() string {
|
|||
// The new signature is appended to the TxBuilder when overwrite=false or overwritten otherwise.
|
||||
// Don't perform online validation or lookups if offline is true.
|
||||
func SignTx(txFactory tx.Factory, clientCtx client.Context, name string, txBuilder client.TxBuilder, offline, overwriteSig bool) error {
|
||||
info, err := txFactory.Keybase().Key(name)
|
||||
k, err := txFactory.Keybase().Key(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ledger and Multisigs only support LEGACY_AMINO_JSON signing.
|
||||
if txFactory.SignMode() == signing.SignMode_SIGN_MODE_UNSPECIFIED &&
|
||||
(info.GetType() == keyring.TypeLedger || info.GetType() == keyring.TypeMulti) {
|
||||
(k.GetType() == keyring.TypeLedger || k.GetType() == keyring.TypeMulti) {
|
||||
txFactory = txFactory.WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
||||
}
|
||||
|
||||
addr := sdk.AccAddress(info.GetPubKey().Address())
|
||||
pubKey, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addr := sdk.AccAddress(pubKey.Address())
|
||||
if !isTxSigner(addr, txBuilder.GetTx().GetSigners()) {
|
||||
return fmt.Errorf("%s: %s", sdkerrors.ErrorInvalidSigner, name)
|
||||
}
|
||||
|
|
|
@ -494,26 +494,35 @@ func (s *IntegrationTestSuite) TestSimMultiSigTx() {
|
|||
account2, _, err := kr.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
multi := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{account1.GetPubKey(), account2.GetPubKey()})
|
||||
pub1, err := account1.GetPubKey()
|
||||
s.Require().NoError(err)
|
||||
|
||||
pub2, err := account2.GetPubKey()
|
||||
s.Require().NoError(err)
|
||||
|
||||
multi := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{pub1, pub2})
|
||||
_, err = kr.SaveMultisig("multi", multi)
|
||||
s.Require().NoError(err)
|
||||
|
||||
_, err = s.network.WaitForHeight(1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
multisigInfo, err := val1.ClientCtx.Keyring.Key("multi")
|
||||
multisigRecord, err := val1.ClientCtx.Keyring.Key("multi")
|
||||
s.Require().NoError(err)
|
||||
|
||||
height, err := s.network.LatestHeight()
|
||||
_, err = s.network.WaitForHeight(height + 1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
addr, err := multisigRecord.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Send coins from validator to multisig.
|
||||
coins := sdk.NewInt64Coin(s.cfg.BondDenom, 15)
|
||||
_, err = bankcli.MsgSendExec(
|
||||
val1.ClientCtx,
|
||||
val1.Address,
|
||||
multisigInfo.GetAddress(),
|
||||
addr,
|
||||
sdk.NewCoins(coins),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
||||
|
@ -528,7 +537,7 @@ func (s *IntegrationTestSuite) TestSimMultiSigTx() {
|
|||
// Generate multisig transaction.
|
||||
multiGeneratedTx, err := bankcli.MsgSendExec(
|
||||
val1.ClientCtx,
|
||||
multisigInfo.GetAddress(),
|
||||
addr,
|
||||
val1.Address,
|
||||
sdk.NewCoins(
|
||||
sdk.NewInt64Coin(s.cfg.BondDenom, 5),
|
||||
|
@ -545,19 +554,23 @@ func (s *IntegrationTestSuite) TestSimMultiSigTx() {
|
|||
multiGeneratedTxFile := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String())
|
||||
|
||||
// Sign with account1
|
||||
addr1, err := account1.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1)
|
||||
account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
||||
account1Signature, err := authtest.TxSignExec(val1.ClientCtx, addr1, multiGeneratedTxFile.Name(), "--multisig", addr.String())
|
||||
s.Require().NoError(err)
|
||||
sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String())
|
||||
|
||||
// Sign with account2
|
||||
account2Signature, err := authtest.TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String())
|
||||
addr2, err := account2.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
account2Signature, err := authtest.TxSignExec(val1.ClientCtx, addr2, multiGeneratedTxFile.Name(), "--multisig", addr.String())
|
||||
s.Require().NoError(err)
|
||||
sign2File := testutil.WriteToNewTempFile(s.T(), account2Signature.String())
|
||||
|
||||
// multisign tx
|
||||
val1.ClientCtx.Offline = false
|
||||
multiSigWith2Signatures, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
|
||||
multiSigWith2Signatures, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigRecord.Name, multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name())
|
||||
s.Require().NoError(err)
|
||||
|
||||
// convert from protoJSON to protoBinary for sim
|
||||
|
|
|
@ -45,9 +45,9 @@ func (s *IntegrationTestSuite) SetupSuite() {
|
|||
val := s.network.Validators[0]
|
||||
s.grantee = make([]sdk.AccAddress, 2)
|
||||
|
||||
// Send some funds to the new account.
|
||||
// Create new account in the keyring.
|
||||
s.grantee[0] = s.createAccount("grantee1")
|
||||
// Send some funds to the new account.
|
||||
s.msgSendExec(s.grantee[0])
|
||||
_, err = s.network.WaitForHeight(1)
|
||||
s.Require().NoError(err)
|
||||
|
@ -84,9 +84,13 @@ func (s *IntegrationTestSuite) SetupSuite() {
|
|||
func (s *IntegrationTestSuite) createAccount(uid string) sdk.AccAddress {
|
||||
val := s.network.Validators[0]
|
||||
// Create new account in the keyring.
|
||||
info, _, err := val.ClientCtx.Keyring.NewMnemonic(uid, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
k, _, err := val.ClientCtx.Keyring.NewMnemonic(uid, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
s.Require().NoError(err)
|
||||
return sdk.AccAddress(info.GetPubKey().Address())
|
||||
|
||||
addr, err := k.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) msgSendExec(grantee sdk.AccAddress) {
|
||||
|
|
|
@ -661,9 +661,11 @@ func (s *IntegrationTestSuite) TestTxWithFeeGrant() {
|
|||
granter := val.Address
|
||||
|
||||
// creating an account manually (This account won't be exist in state)
|
||||
info, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
k, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
s.Require().NoError(err)
|
||||
grantee := sdk.AccAddress(info.GetPubKey().Address())
|
||||
pub, err := k.GetPubKey()
|
||||
s.Require().NoError(err)
|
||||
grantee := sdk.AccAddress(pub.Address())
|
||||
|
||||
commonFlags := []string{
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
||||
|
@ -708,9 +710,11 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() {
|
|||
val := s.network.Validators[0]
|
||||
|
||||
granter := val.Address
|
||||
info, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee1", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
k, _, err := val.ClientCtx.Keyring.NewMnemonic("grantee1", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
s.Require().NoError(err)
|
||||
grantee := sdk.AccAddress(info.GetPubKey().Address())
|
||||
pub, err := k.GetPubKey()
|
||||
s.Require().NoError(err)
|
||||
grantee := sdk.AccAddress(pub.Address())
|
||||
|
||||
clientCtx := val.ClientCtx
|
||||
|
||||
|
|
|
@ -121,8 +121,11 @@ $ %s gentx my-key-name 1000000stake --home=/path/to/home/dir --keyring-backend=o
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse coins")
|
||||
}
|
||||
|
||||
err = genutil.ValidateAccountInGenesis(genesisState, genBalIterator, key.GetAddress(), coins, cdc)
|
||||
addr, err := key.GetAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = genutil.ValidateAccountInGenesis(genesisState, genBalIterator, addr, coins, cdc)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to validate account in genesis")
|
||||
}
|
||||
|
@ -131,8 +134,11 @@ $ %s gentx my-key-name 1000000stake --home=/path/to/home/dir --keyring-backend=o
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "error creating tx builder")
|
||||
}
|
||||
|
||||
clientCtx = clientCtx.WithInput(inBuf).WithFromAddress(key.GetAddress())
|
||||
pub, err := key.GetAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clientCtx = clientCtx.WithInput(inBuf).WithFromAddress(pub)
|
||||
|
||||
// The following line comes from a discrepancy between the `gentx`
|
||||
// and `create-validator` commands:
|
||||
|
|
|
@ -2,13 +2,14 @@ package genutil
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
tmed25519 "github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
tmed25519 "github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/config"
|
||||
)
|
||||
|
|
|
@ -4,13 +4,14 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
tmcli "github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/network"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/client/cli"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
"github.com/stretchr/testify/suite"
|
||||
tmcli "github.com/tendermint/tendermint/libs/cli"
|
||||
)
|
||||
|
||||
type DepositTestSuite struct {
|
||||
|
|
|
@ -359,9 +359,10 @@ func (s *IntegrationTestSuite) TestGRPCQueryDelegatorDelegations() {
|
|||
baseURL := val.APIAddress
|
||||
|
||||
// Create new account in the keyring for address without delegations.
|
||||
info, _, err := val.ClientCtx.Keyring.NewMnemonic("test", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
k, _, err := val.ClientCtx.Keyring.NewMnemonic("test", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
s.Require().NoError(err)
|
||||
newAddr, err := k.GetAddress()
|
||||
s.Require().NoError(err)
|
||||
newAddr := sdk.AccAddress(info.GetPubKey().Address())
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
|
|
@ -93,10 +93,13 @@ func (s *IntegrationTestSuite) TestNewCreateValidatorCmd() {
|
|||
require.NoError(err)
|
||||
require.NotNil(consPubKeyBz)
|
||||
|
||||
info, _, err := val.ClientCtx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
k, _, err := val.ClientCtx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
require.NoError(err)
|
||||
|
||||
newAddr := sdk.AccAddress(info.GetPubKey().Address())
|
||||
pub, err := k.GetPubKey()
|
||||
require.NoError(err)
|
||||
|
||||
newAddr := sdk.AccAddress(pub.Address())
|
||||
_, err = banktestutil.MsgSendExec(
|
||||
val.ClientCtx,
|
||||
val.Address,
|
||||
|
@ -1058,10 +1061,13 @@ func (s *IntegrationTestSuite) TestNewEditValidatorCmd() {
|
|||
func (s *IntegrationTestSuite) TestNewDelegateCmd() {
|
||||
val := s.network.Validators[0]
|
||||
|
||||
info, _, err := val.ClientCtx.Keyring.NewMnemonic("NewAccount", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
k, _, err := val.ClientCtx.Keyring.NewMnemonic("NewAccount", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
newAddr := sdk.AccAddress(info.GetPubKey().Address())
|
||||
pub, err := k.GetPubKey()
|
||||
s.Require().NoError(err)
|
||||
|
||||
newAddr := sdk.AccAddress(pub.Address())
|
||||
|
||||
_, err = banktestutil.MsgSendExec(
|
||||
val.ClientCtx,
|
||||
|
@ -1298,9 +1304,11 @@ func (s *IntegrationTestSuite) TestBlockResults() {
|
|||
val := s.network.Validators[0]
|
||||
|
||||
// Create new account in the keyring.
|
||||
info, _, err := val.ClientCtx.Keyring.NewMnemonic("NewDelegator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
k, _, err := val.ClientCtx.Keyring.NewMnemonic("NewDelegator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
|
||||
require.NoError(err)
|
||||
newAddr := sdk.AccAddress(info.GetPubKey().Address())
|
||||
pub, err := k.GetPubKey()
|
||||
require.NoError(err)
|
||||
newAddr := sdk.AccAddress(pub.Address())
|
||||
|
||||
// Send some funds to the new account.
|
||||
_, err = banktestutil.MsgSendExec(
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
metrics "github.com/armon/go-metrics"
|
||||
"github.com/armon/go-metrics"
|
||||
tmstrings "github.com/tendermint/tendermint/libs/strings"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
|
|
|
@ -5,8 +5,9 @@ package testutil
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil/network"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil/network"
|
||||
)
|
||||
|
||||
func TestIntegrationTestSuite(t *testing.T) {
|
||||
|
|
|
@ -3,14 +3,15 @@ package testutil
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/network"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/upgrade/client/cli"
|
||||
"github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
"github.com/stretchr/testify/suite"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
)
|
||||
|
||||
func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite {
|
||||
|
|
Loading…
Reference in New Issue